summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp5
-rw-r--r--OWNERS1
-rw-r--r--PermissionController/Android.bp92
-rw-r--r--PermissionController/AndroidManifest-lib.xml18
-rw-r--r--PermissionController/AndroidManifest.xml26
-rw-r--r--PermissionController/TEST_MAPPING65
-rw-r--r--PermissionController/jarjar-rules.txt2
-rw-r--r--PermissionController/lint-baseline.xml708
-rw-r--r--PermissionController/proguard.flags10
-rw-r--r--PermissionController/res/drawable/ic_edit.xml24
-rw-r--r--PermissionController/res/drawable/ic_more_horizontal.xml26
-rw-r--r--PermissionController/res/layout-v33/action_button_list_large_screen.xml (renamed from PermissionController/res/layout-w764dp-v33/action_button_list.xml)2
-rw-r--r--PermissionController/res/layout-v33/action_button_list_small_screen.xml (renamed from PermissionController/res/layout-v33/spaced_preference_category_no_label.xml)4
-rw-r--r--PermissionController/res/layout-v33/preference_entries_top_padding.xml (renamed from PermissionController/res/layout-v33/action_button_list.xml)6
-rw-r--r--PermissionController/res/layout-v33/preference_issue_card.xml10
-rw-r--r--PermissionController/res/layout/app_permission.xml106
-rw-r--r--PermissionController/res/layout/grant_permissions.xml4
-rw-r--r--PermissionController/res/layout/grant_permissions_material3.xml2
-rw-r--r--PermissionController/res/navigation-watch/nav_graph.xml126
-rw-r--r--PermissionController/res/values-af-v33/strings.xml3
-rw-r--r--PermissionController/res/values-af/strings.xml73
-rw-r--r--PermissionController/res/values-am-v33/strings.xml3
-rw-r--r--PermissionController/res/values-am/strings.xml115
-rw-r--r--PermissionController/res/values-ar-v33/strings.xml5
-rw-r--r--PermissionController/res/values-ar-v34/strings.xml2
-rw-r--r--PermissionController/res/values-ar/strings.xml79
-rw-r--r--PermissionController/res/values-as/strings.xml55
-rw-r--r--PermissionController/res/values-az-v33/strings.xml3
-rw-r--r--PermissionController/res/values-az/strings.xml57
-rw-r--r--PermissionController/res/values-b+sr+Latn-v33/strings.xml3
-rw-r--r--PermissionController/res/values-b+sr+Latn/strings.xml89
-rw-r--r--PermissionController/res/values-be-v33/strings.xml3
-rw-r--r--PermissionController/res/values-be/strings.xml71
-rw-r--r--PermissionController/res/values-bg-v33/strings.xml3
-rw-r--r--PermissionController/res/values-bg/strings.xml63
-rw-r--r--PermissionController/res/values-bn-v33/strings.xml3
-rw-r--r--PermissionController/res/values-bn/strings.xml67
-rw-r--r--PermissionController/res/values-bs-television/strings.xml2
-rw-r--r--PermissionController/res/values-bs-v33/strings.xml2
-rw-r--r--PermissionController/res/values-bs/strings.xml61
-rw-r--r--PermissionController/res/values-ca-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ca-v34/strings.xml4
-rw-r--r--PermissionController/res/values-ca/strings.xml77
-rw-r--r--PermissionController/res/values-cs-v33/strings.xml3
-rw-r--r--PermissionController/res/values-cs-v34/strings.xml4
-rw-r--r--PermissionController/res/values-cs/strings.xml65
-rw-r--r--PermissionController/res/values-da-v33/strings.xml3
-rw-r--r--PermissionController/res/values-da/strings.xml77
-rw-r--r--PermissionController/res/values-de-v33/strings.xml3
-rw-r--r--PermissionController/res/values-de-v34/strings.xml5
-rw-r--r--PermissionController/res/values-de/strings.xml67
-rw-r--r--PermissionController/res/values-el-v33/strings.xml5
-rw-r--r--PermissionController/res/values-el/strings.xml121
-rw-r--r--PermissionController/res/values-en-rAU/strings.xml53
-rw-r--r--PermissionController/res/values-en-rCA/strings.xml46
-rw-r--r--PermissionController/res/values-en-rGB/strings.xml53
-rw-r--r--PermissionController/res/values-en-rIN/strings.xml53
-rw-r--r--PermissionController/res/values-en-rXC/strings.xml44
-rw-r--r--PermissionController/res/values-es-rUS-v33/strings.xml3
-rw-r--r--PermissionController/res/values-es-rUS/strings.xml69
-rw-r--r--PermissionController/res/values-es-v33/strings.xml3
-rw-r--r--PermissionController/res/values-es/strings.xml73
-rw-r--r--PermissionController/res/values-et-v34/strings.xml2
-rw-r--r--PermissionController/res/values-et/strings.xml59
-rw-r--r--PermissionController/res/values-eu-v33/strings.xml3
-rw-r--r--PermissionController/res/values-eu/strings.xml91
-rw-r--r--PermissionController/res/values-fa-v33/strings.xml3
-rw-r--r--PermissionController/res/values-fa/strings.xml101
-rw-r--r--PermissionController/res/values-fi-v33/strings.xml3
-rw-r--r--PermissionController/res/values-fi-v34/strings.xml2
-rw-r--r--PermissionController/res/values-fi/strings.xml65
-rw-r--r--PermissionController/res/values-fr-rCA-v33/strings.xml5
-rw-r--r--PermissionController/res/values-fr-rCA-v34/strings.xml2
-rw-r--r--PermissionController/res/values-fr-rCA/strings.xml67
-rw-r--r--PermissionController/res/values-fr-v33/strings.xml3
-rw-r--r--PermissionController/res/values-fr-v34/strings.xml2
-rw-r--r--PermissionController/res/values-fr/strings.xml91
-rw-r--r--PermissionController/res/values-gl-v33/strings.xml3
-rw-r--r--PermissionController/res/values-gl/strings.xml63
-rw-r--r--PermissionController/res/values-gu-v33/strings.xml3
-rw-r--r--PermissionController/res/values-gu/strings.xml69
-rw-r--r--PermissionController/res/values-hi/strings.xml75
-rw-r--r--PermissionController/res/values-hr-v33/strings.xml5
-rw-r--r--PermissionController/res/values-hr-v34/strings.xml2
-rw-r--r--PermissionController/res/values-hr/strings.xml97
-rw-r--r--PermissionController/res/values-hu-v33/strings.xml3
-rw-r--r--PermissionController/res/values-hu/strings.xml61
-rw-r--r--PermissionController/res/values-hy-v33/strings.xml3
-rw-r--r--PermissionController/res/values-hy/strings.xml61
-rw-r--r--PermissionController/res/values-in-v33/strings.xml5
-rw-r--r--PermissionController/res/values-in-v34/strings.xml2
-rw-r--r--PermissionController/res/values-in/strings.xml81
-rw-r--r--PermissionController/res/values-is-v33/strings.xml3
-rw-r--r--PermissionController/res/values-is/strings.xml61
-rw-r--r--PermissionController/res/values-it/strings.xml63
-rw-r--r--PermissionController/res/values-iw-v33/strings.xml3
-rw-r--r--PermissionController/res/values-iw/strings.xml63
-rw-r--r--PermissionController/res/values-ja-v34/strings.xml6
-rw-r--r--PermissionController/res/values-ja/strings.xml81
-rw-r--r--PermissionController/res/values-ka-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ka/strings.xml59
-rw-r--r--PermissionController/res/values-kk-v33/strings.xml7
-rw-r--r--PermissionController/res/values-kk-v34/strings.xml2
-rw-r--r--PermissionController/res/values-kk/strings.xml81
-rw-r--r--PermissionController/res/values-km/strings.xml53
-rw-r--r--PermissionController/res/values-kn-v33/strings.xml3
-rw-r--r--PermissionController/res/values-kn/strings.xml105
-rw-r--r--PermissionController/res/values-ko-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ko-v34/strings.xml2
-rw-r--r--PermissionController/res/values-ko/strings.xml67
-rw-r--r--PermissionController/res/values-ky-television/strings.xml2
-rw-r--r--PermissionController/res/values-ky-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ky-v34/strings.xml4
-rw-r--r--PermissionController/res/values-ky-watch/strings.xml2
-rw-r--r--PermissionController/res/values-ky/strings.xml81
-rw-r--r--PermissionController/res/values-lo-v33/strings.xml3
-rw-r--r--PermissionController/res/values-lo/strings.xml55
-rw-r--r--PermissionController/res/values-lt-v33/strings.xml3
-rw-r--r--PermissionController/res/values-lt/strings.xml57
-rw-r--r--PermissionController/res/values-lv-v33/strings.xml3
-rw-r--r--PermissionController/res/values-lv/strings.xml55
-rw-r--r--PermissionController/res/values-mk-v33/strings.xml5
-rw-r--r--PermissionController/res/values-mk-v34/strings.xml4
-rw-r--r--PermissionController/res/values-mk/strings.xml73
-rw-r--r--PermissionController/res/values-ml/strings.xml49
-rw-r--r--PermissionController/res/values-mn-v33/strings.xml3
-rw-r--r--PermissionController/res/values-mn/strings.xml61
-rw-r--r--PermissionController/res/values-mr-v33/strings.xml3
-rw-r--r--PermissionController/res/values-mr-v34/strings.xml2
-rw-r--r--PermissionController/res/values-mr/strings.xml65
-rw-r--r--PermissionController/res/values-ms-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ms/strings.xml55
-rw-r--r--PermissionController/res/values-my-v33/strings.xml3
-rw-r--r--PermissionController/res/values-my/strings.xml69
-rw-r--r--PermissionController/res/values-nb-v33/strings.xml3
-rw-r--r--PermissionController/res/values-nb/strings.xml61
-rw-r--r--PermissionController/res/values-ne-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ne/strings.xml67
-rw-r--r--PermissionController/res/values-night-v33/themes.xml12
-rw-r--r--PermissionController/res/values-night-v34/themes.xml5
-rw-r--r--PermissionController/res/values-nl-v33/strings.xml3
-rw-r--r--PermissionController/res/values-nl-v34/strings.xml2
-rw-r--r--PermissionController/res/values-nl/strings.xml69
-rw-r--r--PermissionController/res/values-or-v33/strings.xml3
-rw-r--r--PermissionController/res/values-or-v34/strings.xml2
-rw-r--r--PermissionController/res/values-or-watch/strings.xml2
-rw-r--r--PermissionController/res/values-or/strings.xml103
-rw-r--r--PermissionController/res/values-pa-v33/strings.xml9
-rw-r--r--PermissionController/res/values-pa/strings.xml69
-rw-r--r--PermissionController/res/values-pl-v33/strings.xml3
-rw-r--r--PermissionController/res/values-pl-v34/strings.xml4
-rw-r--r--PermissionController/res/values-pl/strings.xml73
-rw-r--r--PermissionController/res/values-pt-rBR-v33/strings.xml2
-rw-r--r--PermissionController/res/values-pt-rBR/strings.xml69
-rw-r--r--PermissionController/res/values-pt-rPT-v33/strings.xml3
-rw-r--r--PermissionController/res/values-pt-rPT/strings.xml99
-rw-r--r--PermissionController/res/values-pt-v33/strings.xml2
-rw-r--r--PermissionController/res/values-pt/strings.xml69
-rw-r--r--PermissionController/res/values-ro-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ro/strings.xml61
-rw-r--r--PermissionController/res/values-ru-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ru-v34/strings.xml2
-rw-r--r--PermissionController/res/values-ru/strings.xml75
-rw-r--r--PermissionController/res/values-si-v33/strings.xml3
-rw-r--r--PermissionController/res/values-si/strings.xml57
-rw-r--r--PermissionController/res/values-sk/strings.xml53
-rw-r--r--PermissionController/res/values-sl-v33/strings.xml4
-rw-r--r--PermissionController/res/values-sl-v34/strings.xml4
-rw-r--r--PermissionController/res/values-sl/strings.xml59
-rw-r--r--PermissionController/res/values-sq-v33/strings.xml3
-rw-r--r--PermissionController/res/values-sq/strings.xml73
-rw-r--r--PermissionController/res/values-sr-v33/strings.xml3
-rw-r--r--PermissionController/res/values-sr/strings.xml89
-rw-r--r--PermissionController/res/values-sv-v33/strings.xml3
-rw-r--r--PermissionController/res/values-sv-v34/strings.xml2
-rw-r--r--PermissionController/res/values-sv/strings.xml59
-rw-r--r--PermissionController/res/values-sw-v33/strings.xml5
-rw-r--r--PermissionController/res/values-sw-v34/strings.xml4
-rw-r--r--PermissionController/res/values-sw/strings.xml79
-rw-r--r--PermissionController/res/values-ta-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ta/strings.xml57
-rw-r--r--PermissionController/res/values-te/strings.xml65
-rw-r--r--PermissionController/res/values-th-v33/strings.xml3
-rw-r--r--PermissionController/res/values-th-v34/strings.xml2
-rw-r--r--PermissionController/res/values-th/strings.xml63
-rw-r--r--PermissionController/res/values-tl-v33/strings.xml3
-rw-r--r--PermissionController/res/values-tl/strings.xml61
-rw-r--r--PermissionController/res/values-tr-v33/strings.xml3
-rw-r--r--PermissionController/res/values-tr/strings.xml63
-rw-r--r--PermissionController/res/values-uk-v33/strings.xml3
-rw-r--r--PermissionController/res/values-uk-v34/strings.xml6
-rw-r--r--PermissionController/res/values-uk/strings.xml65
-rw-r--r--PermissionController/res/values-ur-v33/strings.xml3
-rw-r--r--PermissionController/res/values-ur/strings.xml71
-rw-r--r--PermissionController/res/values-uz-v33/strings.xml3
-rw-r--r--PermissionController/res/values-uz/strings.xml69
-rw-r--r--PermissionController/res/values-v31/styles.xml10
-rw-r--r--PermissionController/res/values-v33/attrs.xml3
-rw-r--r--PermissionController/res/values-v33/dimens.xml9
-rw-r--r--PermissionController/res/values-v33/layout.xml9
-rw-r--r--PermissionController/res/values-v33/styles.xml30
-rw-r--r--PermissionController/res/values-v33/themes.xml24
-rw-r--r--PermissionController/res/values-v34/strings.xml2
-rw-r--r--PermissionController/res/values-v35/bools.xml21
-rw-r--r--PermissionController/res/values-vi-v33/strings.xml3
-rw-r--r--PermissionController/res/values-vi-v34/strings.xml4
-rw-r--r--PermissionController/res/values-vi/strings.xml85
-rw-r--r--PermissionController/res/values-w764dp-v33/layout.xml6
-rw-r--r--PermissionController/res/values-w764dp-v33/styles.xml14
-rw-r--r--PermissionController/res/values-watch/themes.xml6
-rw-r--r--PermissionController/res/values-zh-rCN-v33/strings.xml3
-rw-r--r--PermissionController/res/values-zh-rCN-v34/strings.xml2
-rw-r--r--PermissionController/res/values-zh-rCN/strings.xml97
-rw-r--r--PermissionController/res/values-zh-rHK-car/strings.xml2
-rw-r--r--PermissionController/res/values-zh-rHK-television/strings.xml2
-rw-r--r--PermissionController/res/values-zh-rHK-v33/strings.xml6
-rw-r--r--PermissionController/res/values-zh-rHK-v34/strings.xml2
-rw-r--r--PermissionController/res/values-zh-rHK/strings.xml225
-rw-r--r--PermissionController/res/values-zh-rTW-v34/strings.xml4
-rw-r--r--PermissionController/res/values-zh-rTW/strings.xml57
-rw-r--r--PermissionController/res/values-zu-v33/strings.xml3
-rw-r--r--PermissionController/res/values-zu/strings.xml63
-rw-r--r--PermissionController/res/values/bools.xml1
-rw-r--r--PermissionController/res/values/colors.xml3
-rw-r--r--PermissionController/res/values/overlayable.xml36
-rw-r--r--PermissionController/res/values/strings.xml120
-rw-r--r--PermissionController/res/values/styles.xml14
-rw-r--r--PermissionController/res/values/themes.xml2
-rw-r--r--PermissionController/res/xml/roles.xml69
-rw-r--r--PermissionController/res/xml/safety_center_dashboard.xml7
-rw-r--r--PermissionController/role-controller/Android.bp1
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java125
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java42
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java16
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java16
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java16
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java16
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java23
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java8
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java17
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java104
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/RetailDemoRoleBehavior.java65
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java35
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java10
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java59
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/WalletRoleBehavior.java129
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java25
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java50
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Permission.java21
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java288
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java18
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java19
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java14
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java55
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java14
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java13
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Role.java194
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java61
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java57
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/VisibilityMixin.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/VisibilityMixin.java)28
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java (renamed from PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java)137
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java107
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java39
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java27
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/ResourceUtils.java57
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java52
-rw-r--r--PermissionController/role-controller/lint-baseline.xml10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/Constants.java11
-rw-r--r--PermissionController/src/com/android/permissioncontroller/DumpableLog.kt36
-rw-r--r--PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/auto/AutoSettingsFrameFragment.java17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt208
-rw-r--r--PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt752
-rw-r--r--PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/hibernation/v31/HibernationController.kt23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/hibernation/v31/InstallerPackagesLiveData.kt12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/incident/ConfirmationActivity.java40
-rw-r--r--PermissionController/src/com/android/permissioncontroller/incident/PendingList.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/incident/wear/ConfirmationActivityWearViewHandler.java85
-rw-r--r--PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationActivityViewModel.kt56
-rw-r--r--PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt84
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING70
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java84
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/AllPackageInfosLiveData.kt8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/AppOpLiveData.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt224
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveData.kt61
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/AutoRevokedPackagesLiveData.kt26
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/BroadcastReceiverLiveData.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/CarrierPrivilegedStatusLiveData.kt13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/DataRepository.kt165
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/DisabledPrintServicesLiveData.kt23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/EnabledAccessibilityServicesLiveData.kt11
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDeviceAdminsLiveData.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDreamServicesLiveData.kt23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/EnabledInputMethodsLiveData.kt18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/EnabledNotificationListenersLiveData.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/FullStoragePermissionAppsLiveData.kt88
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/HasIntentAction.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt47
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt103
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/LauncherPackagesLiveData.kt34
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/LightAppPermGroupLiveData.kt93
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt166
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt37
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/LoadAndFreezeLifeData.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/MicMutedLiveData.kt50
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/OpUsageLiveData.kt114
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt49
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt54
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt52
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt56
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt40
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt56
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermStateLiveData.kt75
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermissionChange.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermissionEvent.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermissionListenerMultiplexer.kt15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PreinstalledUserPackageInfosLiveData.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/RoleHoldersLiveData.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/RoleListenerMultiplexer.kt18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/SelectedAutofillServiceLiveData.kt20
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/SelectedVoiceInteractionServiceLiveData.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/SelectedWallpaperServiceLiveData.kt22
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt134
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/SinglePermGroupPackagesUiInfoLiveData.kt81
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/SmartAsyncMediatorLiveData.kt16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt61
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/StandardPermGroupNamesLiveData.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/UnusedPackagesLiveData.kt39
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/UsageStatsLiveData.kt15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt108
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt21
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v33/RecentPermissionDecisionsLiveData.kt8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v34/SafetyLabelInfoLiveData.kt8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java28
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/Permission.java12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt188
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt43
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermGroupInfo.kt17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt46
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroup.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroupPackagesUiInfo.kt18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/UidSensitivityState.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightPackageOps.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/LightInstallSourceInfo.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/SafetyLabelInfo.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt209
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/BasePermissionEventStorage.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/CheckLifecycleRegistry.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/ExemptRestrictedPermission.kt13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java106
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java28
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt106
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventCleanupJobService.kt47
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorage.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorageImpls.kt11
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionStorageTimeChangeReceiver.kt42
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PersistedStoragePackageUninstalledReceiver.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt654
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING55
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionDecisionStorageImpl.kt62
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/Category.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java400
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java59
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/RemovablePref.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/TEST_MAPPING15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt172
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoDividerPreference.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java11
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsFragment.kt168
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsViewAllFragment.kt42
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt27
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsPreference.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt25
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java47
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/FooterPreference.kt8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.kt352
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt21
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsWrapperFragment.kt17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java21
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java53
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionControlPreference.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsCollapsingToolbarBaseFragment.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SettingsWithLargeHeader.java16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SmartIconLoadPackagePermissionPreference.kt17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/UnusedAppPreference.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/Utils.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/DashboardUtils.kt78
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionHistoryPreference.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFragment.kt29
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt26
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt89
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/AllAppPermissionsViewModel.kt53
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt419
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt986
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt1818
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt26
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManagePermissionsViewModel.kt76
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt22
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt218
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt91
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/UnusedAppsViewModel.kt193
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BackgroundGrantBehavior.kt210
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BasicGrantBehavior.kt58
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/GrantBehavior.kt82
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/HealthGrantBehavior.kt56
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/LocationGrantBehavior.kt126
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/NotificationGrantBehavior.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/StorageGrantBehavior.kt138
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageControlPreferenceUtils.kt61
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt129
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModel.kt74
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/ReviewOngoingUsageViewModel.kt763
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/ReviewPermissionDecisionsViewModel.kt149
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt102
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/AllAppPermissionsFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/GrantPermissionsViewHandlerImpl.java32
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionsFrameFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsFragment.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsPreference.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v33/widget/SafetyProtectionSectionView.kt18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java407
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/GrantPermissionsWearViewHandler.java388
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/ReviewPermissionsWearFragment.java124
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionFragment.kt348
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsFragment.kt172
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt391
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt121
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt221
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt149
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageCustomPermissionScreen.kt73
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageCustomPermissionsFragment.kt63
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionScreen.kt157
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionsFragment.kt78
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt174
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt235
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt147
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt97
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt161
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageFragment.kt65
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageScreen.kt135
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUnusedAppsFragment.kt308
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUnusedAppsScreen.kt112
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUtils.kt80
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AdjustChipHeightToFontScale.kt30
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt238
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AnnotatedText.kt90
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Button.kt133
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Chip.kt261
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/DrawablePainter.kt170
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Icon.kt127
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ListFooter.kt77
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ListHeader.kt145
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt304
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ToggleChip.kt233
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ToggleChipToggleControl.kt23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/AppPermissionConfirmDialogViewModel.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/AppPermissionGroupsRevokeDialogViewModel.kt50
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearAppPermissionUsagesViewModel.kt33
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearGrantPermissionsViewModel.kt62
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearUnusedAppsViewModel.kt60
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt55
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTonalPalette.kt191
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/AndroidUtils.kt55
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/ContextCompat.java70
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/DebugUtils.kt23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt984
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/MultiDeviceUtils.kt50
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt53
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/SystemTimeSource.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/TimeSource.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/UserSensitiveFlagsUtils.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java338
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt43
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt473
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/AutoRevokePrivacySource.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerCheck.kt200
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt42
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceStorageRepository.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/WorkPolicyInfo.kt36
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.kt13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/Role.md4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING21
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/ChangeDefaultCardEmulationActivity.java76
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListActivity.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java33
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRadioPreference.java5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java21
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java33
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/WalletRoleUiBehavior.java187
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessActivity.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppFragment.kt121
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt123
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListFragment.kt53
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt74
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListScreen.kt76
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt111
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleFragment.kt395
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleHelper.kt137
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt184
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt56
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt59
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/model/DefaultAppConfirmDialogViewModel.kt48
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/model/WearRequestRoleViewModel.kt60
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java46
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java29
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterSearchIndexablesProvider.kt28
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreferenceCategory.kt16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EntriesTopPaddingPreference.kt13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java23
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt21
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java51
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java29
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt28
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt11
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java20
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt71
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.kt31
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterQsViewModel.kt40
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/LazyProperties.kt12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt60
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING29
-rw-r--r--PermissionController/tests/inprocess/Android.bp5
-rw-r--r--PermissionController/tests/inprocess/AndroidTest.xml6
-rw-r--r--PermissionController/tests/inprocess/AppThatUsesCameraPermission/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt3
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/GetPermissionGroupInfoTest.kt10
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java258
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveDataTest.kt7
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/DataUtils.kt11
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt3
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt47
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt34
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt74
-rw-r--r--PermissionController/tests/mocking/Android.bp18
l---------PermissionController/tests/mocking/main_res1
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationControllerTest.kt37
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt56
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/FakeEventStorage.kt4
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/RecentPermissionDecisionsLiveDataTest.kt16
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/BasePermissionEventStorageTest.kt63
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionChangeStorageImplTest.kt63
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionEventCleanupJobServiceTest.kt31
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionStorageTimeChangeReceiverTest.kt54
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PersistedStoragePackageUninstalledReceiverTest.kt38
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/RuntimePermissionsUpgradeControllerTest.kt491
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionDecisionStorageImplTest.kt33
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/handheld/v31/DashboardUtilsTest.kt138
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt164
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt534
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/StringUtilsTest.kt58
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AccessibilitySourceServiceTest.kt36
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AppDataSharingUpdatesPrivacySourceTest.kt39
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerCheckInternalTest.kt51
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPregrantsTest.kt8
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPrivacySourceTest.kt173
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/SafetyCenterReceiverTest.kt71
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/TextStorageRepositoryTest.kt52
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/WorkPolicyInfoTest.kt64
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/SafetyCenterUiDataTest.kt48
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/StatusUiDataTest.kt51
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryPersistenceTest.kt195
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryTest.kt84
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/SafetyLabelChangesJobServiceTest.kt10
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TestSafetyLabels.kt20
-rw-r--r--PermissionController/tests/outofprocess/Android.bp3
-rw-r--r--PermissionController/tests/outofprocess/src/com/android/permissioncontroller/tests/outofprocess/DumpTest.kt17
-rw-r--r--PermissionController/tests/permissionui/Android.bp3
-rw-r--r--PermissionController/tests/permissionui/AndroidTest.xml22
-rw-r--r--PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/Android.bp34
-rw-r--r--PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/AndroidManifest.xml26
-rw-r--r--PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt21
-rw-r--r--PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/Android.bp34
-rw-r--r--PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/AndroidManifest.xml26
-rw-r--r--PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/res/values/strings.xml21
-rw-r--r--PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/Android.bp34
-rw-r--r--PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/AndroidManifest.xml34
-rw-r--r--PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt21
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionGroupPreferenceUtils.kt22
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionHub2Test.kt69
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/UiUtils.kt10
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AllAppPermissionsFragmentTest.kt45
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AppPermissionFragmentTest.kt44
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/BasePermissionUiTest.kt14
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/CustomPermissionAppsFragmentTest.kt24
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/HealthConnectAllAppPermissionFragmentTest.kt148
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/HealthConnectAppPermissionFragmentTest.kt103
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/LocationPermissionAppsFragmentTest.kt16
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/PermissionAppsFragmentTest.kt131
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/StoragePermissionAppsFragmentTest.kt17
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/TestAppUtils.kt20
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/BaseHandheldPermissionUiTest.kt5
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt28
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt235
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ReviewOngoingUsageFragmentTest.kt17
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageFragmentTest.kt10
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsFragmentTest.kt41
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsOtherFragmentTest.kt38
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUiBaseTest.kt16
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUtils.kt27
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearPermissionUsageDetailsFragmentTest.kt100
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearPermissionUsageFragmentTest.kt167
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearUtils.kt40
-rw-r--r--SafetyCenter/Annotations/Android.bp1
-rw-r--r--SafetyCenter/Config/TEST_MAPPING2
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/os/Build.java4
-rw-r--r--SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java6
-rw-r--r--SafetyCenter/Resources/res/raw-v35/safety_center_config.xml147
-rw-r--r--SafetyCenter/Resources/res/values-af-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-af-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-af/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-am-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-am-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-am/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ar-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ar-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ar/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-as-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-as-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-az-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-az-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-b+sr+Latn-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-b+sr+Latn-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-be-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-be-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-be/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-bg-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-bg-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-bn-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-bn-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-bs-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-bs-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ca-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ca-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ca/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-cs-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-cs-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-da-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-da-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-da/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-de-v34/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-de-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-el-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-el-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-en-rAU-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-en-rCA-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-en-rGB-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-en-rIN-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-en-rXC-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-es-rUS-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-es-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-es-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-et-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-et-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-eu-v34/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-eu-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-fa-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-fa-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-fa/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-fi-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-fi-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-fr-rCA-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-fr-rCA/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-fr-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-fr-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-gl-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-gl-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-gu-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-gu-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-hi-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-hi-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-hr-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-hr-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-hr/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-hu-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-hu-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-hy-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-hy-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-in-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-in-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-in/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-is-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-is-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-it-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-it-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-it/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-iw-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-iw-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ja-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ja-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ka-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ka-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-kk-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-kk-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-kk/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-km-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-km-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-km/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-kn-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-kn-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ko-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ko-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ky-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-ky-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-lo-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-lo-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-lt-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-lt-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-lv-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-lv-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-mk-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-mk-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-mk/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ml-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ml-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-mn-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-mn-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-mr-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-mr-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ms-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-ms-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-my-v34/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-my-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-nb-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-nb-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ne-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ne-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ne/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-nl-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-nl-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-nl/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-or-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-or-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-or/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-pa-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-pa-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-pl-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-pl-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-pt-rBR-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-pt-rPT-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-pt-rPT/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-pt-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-pt-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ro-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ro-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ru-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-ru-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ru/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-si-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-si-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-sk-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-sk-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-sl-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-sl-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-sq-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-sq-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-sr-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-sr-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-sr/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-sv-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-sv-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-sw-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-sw-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-ta-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ta-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-te-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-te-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-te/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-th-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-th-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-tl-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-tl-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-tr-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-tr-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-uk-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-uk-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-uk/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ur-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-ur-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-uz-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-uz-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-uz/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-v34/config.xml2
-rw-r--r--SafetyCenter/Resources/res/values-v35/config.xml23
-rw-r--r--SafetyCenter/Resources/res/values-v35/strings.xml28
-rw-r--r--SafetyCenter/Resources/res/values-vi-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-vi-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-vi/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-zh-rCN-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml6
-rw-r--r--SafetyCenter/Resources/res/values-zh-rHK-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-zh-rTW-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values-zu-v34/strings.xml4
-rw-r--r--SafetyCenter/Resources/res/values-zu-v35/strings.xml25
-rw-r--r--SafetyCenter/Resources/res/values/config.xml2
-rw-r--r--SafetyCenter/Resources/shared_res/values-af/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-am/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-ar/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-as/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-az/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-be/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-bg/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-bn/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-bs/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-ca/strings.xml13
-rw-r--r--SafetyCenter/Resources/shared_res/values-cs/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-da/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-de/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-el/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-es/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-et/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-eu/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-fa/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-fi/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-fr/strings.xml15
-rw-r--r--SafetyCenter/Resources/shared_res/values-gl/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-gu/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-hi/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-hr/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-hu/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-hy/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-in/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-is/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-it/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-iw/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-ja/strings.xml15
-rw-r--r--SafetyCenter/Resources/shared_res/values-ka/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-kk/strings.xml13
-rw-r--r--SafetyCenter/Resources/shared_res/values-km/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-kn/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-ko/strings.xml13
-rw-r--r--SafetyCenter/Resources/shared_res/values-ky/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-lo/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-lt/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-lv/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-mk/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-ml/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-mn/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-mr/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-ms/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-my/strings.xml15
-rw-r--r--SafetyCenter/Resources/shared_res/values-nb/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-ne/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-nl/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-or/strings.xml13
-rw-r--r--SafetyCenter/Resources/shared_res/values-pa/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-pl/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-pt/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-ro/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-ru/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-si/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-sk/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-sl/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-sq/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-sr/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-sv/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-sw/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-ta/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-te/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-th/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-tl/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-tr/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-uk/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-ur/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-uz/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-vi/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml11
-rw-r--r--SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml19
-rw-r--r--SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml13
-rw-r--r--SafetyCenter/Resources/shared_res/values-zu/strings.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values/strings.xml3
-rw-r--r--SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesApk.java353
-rw-r--r--SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java403
-rw-r--r--SafetyCenter/ResourcesLib/tests/AndroidTest.xml2
-rw-r--r--SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/raw/safety_center_config.txt1
-rw-r--r--SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesApkTest.kt440
-rw-r--r--SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt226
-rw-r--r--SafetyCenter/TEST_MAPPING6
-rw-r--r--TEST_MAPPING62
-rw-r--r--flags/Android.bp65
-rw-r--r--flags/flags.aconfig29
-rw-r--r--flags/java/com/android/permission/flags/PermissionsFlags.java20
-rw-r--r--framework-s/Android.bp10
-rw-r--r--framework-s/api/current.txt1
-rw-r--r--framework-s/api/module-lib-current.txt8
-rw-r--r--framework-s/api/module-lib-lint-baseline.txt39
-rw-r--r--framework-s/api/system-current.txt14
-rw-r--r--framework-s/api/system-lint-baseline.txt37
-rw-r--r--framework-s/jarjar-rules.txt1
-rw-r--r--framework-s/java/android/app/ecm/EnhancedConfirmationFrameworkInitializer.java50
-rw-r--r--framework-s/java/android/app/ecm/EnhancedConfirmationManager.java411
-rw-r--r--framework-s/java/android/app/role/IRoleController.aidl2
-rw-r--r--framework-s/java/android/app/role/IRoleManager.aidl23
-rw-r--r--framework-s/java/android/app/role/RoleControllerManager.java39
-rw-r--r--framework-s/java/android/app/role/RoleControllerService.java28
-rw-r--r--framework-s/java/android/app/role/RoleManager.java167
-rw-r--r--framework-s/java/android/app/role/TEST_MAPPING19
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenter.md3
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterData.java12
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterIssue.java17
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterManager.java2
-rw-r--r--framework-s/java/android/safetycenter/SafetyEvent.java3
-rw-r--r--framework-s/java/android/safetycenter/SafetySourceData.java14
-rw-r--r--framework-s/java/android/safetycenter/SafetySourceIssue.java44
-rw-r--r--framework-s/java/android/safetycenter/SafetySourceStatus.java3
-rw-r--r--framework-s/java/android/safetycenter/config/SafetyCenterConfig.java3
-rw-r--r--framework-s/java/android/safetycenter/config/SafetySource.java24
-rw-r--r--framework-s/java/android/safetycenter/config/SafetySourcesGroup.java3
-rw-r--r--framework-s/lint-baseline.xml22
-rw-r--r--ktfmt_includes.txt1
-rw-r--r--permissions/Android.bp6
-rw-r--r--service/Android.bp16
-rw-r--r--service/api/system-server-current.txt2
-rw-r--r--service/jarjar-rules.txt1
-rw-r--r--service/java/com/android/role/LocalRoleController.java104
-rw-r--r--service/java/com/android/role/RemoteRoleController.java84
-rw-r--r--service/java/com/android/role/RoleController.java68
-rw-r--r--service/java/com/android/role/RoleService.java267
-rw-r--r--service/java/com/android/role/RoleUserState.java83
-rw-r--r--service/java/com/android/role/TEST_MAPPING27
-rw-r--r--service/java/com/android/role/persistence/RolesPersistenceImpl.java12
-rw-r--r--service/java/com/android/role/persistence/RolesState.java40
-rw-r--r--service/java/com/android/safetycenter/ApiLock.java5
-rw-r--r--service/java/com/android/safetycenter/DevicePolicyResources.java22
-rw-r--r--service/java/com/android/safetycenter/PendingIntentFactory.java58
-rw-r--r--service/java/com/android/safetycenter/RefreshReasons.java11
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java68
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterConfigReader.java57
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.java5
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataFactory.java117
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterFlags.java137
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterListeners.java18
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java92
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterService.java446
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java14
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterTimeouts.java5
-rw-r--r--service/java/com/android/safetycenter/SafetySourceIssueInfo.java6
-rw-r--r--service/java/com/android/safetycenter/SafetySourceIssues.java87
-rw-r--r--service/java/com/android/safetycenter/SafetySourceKey.java6
-rw-r--r--service/java/com/android/safetycenter/SafetySources.java5
-rw-r--r--service/java/com/android/safetycenter/SafetySourcesGroups.java5
-rw-r--r--service/java/com/android/safetycenter/UserProfileGroup.java17
-rw-r--r--service/java/com/android/safetycenter/data/AndroidLockScreenFix.java152
-rw-r--r--service/java/com/android/safetycenter/data/DefaultActionOverrideFix.java180
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterDataManager.java93
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java36
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java12
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java32
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java18
-rw-r--r--service/java/com/android/safetycenter/data/SafetyEventFix.java118
-rw-r--r--service/java/com/android/safetycenter/data/SafetySourceDataFix.java76
-rw-r--r--service/java/com/android/safetycenter/data/SafetySourceDataOverrides.java81
-rw-r--r--service/java/com/android/safetycenter/data/SafetySourceDataRepository.java68
-rw-r--r--service/java/com/android/safetycenter/data/SafetySourceDataValidator.java46
-rw-r--r--service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java9
-rw-r--r--service/java/com/android/safetycenter/data/package-info.java5
-rw-r--r--service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java18
-rw-r--r--service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java6
-rw-r--r--service/java/com/android/safetycenter/logging/package-info.java5
-rw-r--r--service/java/com/android/safetycenter/notifications/SafetyCenterNotificationChannels.java92
-rw-r--r--service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java46
-rw-r--r--service/java/com/android/safetycenter/notifications/SafetyCenterNotificationReceiver.java39
-rw-r--r--service/java/com/android/safetycenter/notifications/SafetyCenterNotificationSender.java39
-rw-r--r--service/java/com/android/safetycenter/notifications/package-info.java5
-rw-r--r--service/java/com/android/safetycenter/package-info.java5
-rw-r--r--service/lint-baseline.xml38
-rw-r--r--service/proguard.flags4
-rw-r--r--service/proto/role_service.proto3
-rw-r--r--tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt51
-rw-r--r--tests/cts/permission/Android.bp130
-rw-r--r--tests/cts/permission/AndroidManifest.xml100
-rw-r--r--tests/cts/permission/AndroidTest.xml137
-rw-r--r--tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp35
-rw-r--r--tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml41
-rw-r--r--tests/cts/permission/AppThatAccessesLocationOnCommand/Android.bp40
-rw-r--r--tests/cts/permission/AppThatAccessesLocationOnCommand/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/AccessLocationOnCommand.java68
-rw-r--r--tests/cts/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/IAccessLocationOnCommand.aidl22
-rw-r--r--tests/cts/permission/AppThatAlsoDefinesPermissionA/Android.bp32
-rw-r--r--tests/cts/permission/AppThatAlsoDefinesPermissionA/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatAlsoDefinesPermissionADifferentCert/Android.bp32
-rw-r--r--tests/cts/permission/AppThatAlsoDefinesPermissionADifferentCert/AndroidManifest.xml25
-rw-r--r--tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/Android.bp32
-rw-r--r--tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/Android.bp32
-rw-r--r--tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatDefinesPermissionA/Android.bp32
-rw-r--r--tests/cts/permission/AppThatDefinesPermissionA/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup/Android.bp31
-rw-r--r--tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup30/Android.bp31
-rw-r--r--tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup30/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatDefinesPermissionWithPlatformGroup/Android.bp31
-rw-r--r--tests/cts/permission/AppThatDefinesPermissionWithPlatformGroup/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp32
-rw-r--r--tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/AndroidManifest.xml38
-rw-r--r--tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/src/android/permission/cts/appthatrequestpermission/RequestPermissions.kt49
-rw-r--r--tests/cts/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp36
-rw-r--r--tests/cts/permission/AppThatDoesNotHaveBgLocationAccess/AndroidManifest.xml24
-rw-r--r--tests/cts/permission/AppThatHasNotificationListener/Android.bp39
-rw-r--r--tests/cts/permission/AppThatHasNotificationListener/AndroidManifest.xml33
-rw-r--r--tests/cts/permission/AppThatHasNotificationListener/src/android/permission/cts/appthathasnotificationlistener/CtsNotificationListenerService.java21
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermission30/Android.bp40
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermission30/AndroidManifest.xml35
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermission30/src/android/permission/cts/appthatrequestpermission/AccessBluetoothOnCommand.java161
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermission31/Android.bp33
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermission31/AndroidManifest.xml34
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocation31/Android.bp33
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocation31/AndroidManifest.xml40
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocationNoProvider/Android.bp32
-rw-r--r--tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocationNoProvider/AndroidManifest.xml36
-rw-r--r--tests/cts/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp31
-rw-r--r--tests/cts/permission/AppThatRequestContactsAndCallLogPermission16/AndroidManifest.xml29
-rw-r--r--tests/cts/permission/AppThatRequestContactsPermission15/Android.bp31
-rw-r--r--tests/cts/permission/AppThatRequestContactsPermission15/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatRequestContactsPermission16/Android.bp31
-rw-r--r--tests/cts/permission/AppThatRequestContactsPermission16/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatRequestCustomCameraPermission/Android.bp37
-rw-r--r--tests/cts/permission/AppThatRequestCustomCameraPermission/AndroidManifest.xml40
-rw-r--r--tests/cts/permission/AppThatRequestCustomCameraPermission/res/values/strings.xml20
-rw-r--r--tests/cts/permission/AppThatRequestCustomCameraPermission/src/android/permission/cts/appthatrequestcustomcamerapermission/RequestCameraPermission.java85
-rw-r--r--tests/cts/permission/AppThatRequestDevicePermissions/Android.bp32
-rw-r--r--tests/cts/permission/AppThatRequestDevicePermissions/AndroidManifest.xml41
-rw-r--r--tests/cts/permission/AppThatRequestDevicePermissions/src/android/permission/cts/appthatrequestpermission/RevokeSelfPermissionReceiver.kt37
-rw-r--r--tests/cts/permission/AppThatRequestLocationAndBackgroundPermission28/Android.bp32
-rw-r--r--tests/cts/permission/AppThatRequestLocationAndBackgroundPermission28/AndroidManifest.xml32
-rw-r--r--tests/cts/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp33
-rw-r--r--tests/cts/permission/AppThatRequestLocationAndBackgroundPermission29/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatRequestLocationPermission22/Android.bp31
-rw-r--r--tests/cts/permission/AppThatRequestLocationPermission22/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatRequestLocationPermission28/Android.bp31
-rw-r--r--tests/cts/permission/AppThatRequestLocationPermission28/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatRequestLocationPermission29/Android.bp32
-rw-r--r--tests/cts/permission/AppThatRequestLocationPermission29/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatRequestLocationPermission29v4/Android.bp32
-rw-r--r--tests/cts/permission/AppThatRequestLocationPermission29v4/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatRequestMultiplePermissionsWithMinMaxSdk/Android.bp31
-rw-r--r--tests/cts/permission/AppThatRequestMultiplePermissionsWithMinMaxSdk/AndroidManifest.xml30
-rw-r--r--tests/cts/permission/AppThatRequestOneTimePermission/Android.bp35
-rw-r--r--tests/cts/permission/AppThatRequestOneTimePermission/AndroidManifest.xml36
-rw-r--r--tests/cts/permission/AppThatRequestOneTimePermission/src/android/permission/cts/appthatrequestpermission/KeepAliveForegroundService.java72
-rw-r--r--tests/cts/permission/AppThatRequestOneTimePermission/src/android/permission/cts/appthatrequestpermission/RequestPermission.java29
-rw-r--r--tests/cts/permission/AppThatRequestPermissionAandB/Android.bp33
-rw-r--r--tests/cts/permission/AppThatRequestPermissionAandB/AndroidManifest.xml35
-rw-r--r--tests/cts/permission/AppThatRequestPermissionAandB/res/values/strings.xml19
-rw-r--r--tests/cts/permission/AppThatRequestPermissionAandB/src/android/permission/cts/appthatrequestpermission/RequestPermission.java30
-rw-r--r--tests/cts/permission/AppThatRequestPermissionAandC/Android.bp33
-rw-r--r--tests/cts/permission/AppThatRequestPermissionAandC/AndroidManifest.xml35
-rw-r--r--tests/cts/permission/AppThatRequestPermissionAandC/res/values/strings.xml19
-rw-r--r--tests/cts/permission/AppThatRequestPermissionAandC/src/android/permission/cts/appthatrequestpermission/RequestPermission.java30
-rw-r--r--tests/cts/permission/AppThatRequestStoragePermission28/Android.bp31
-rw-r--r--tests/cts/permission/AppThatRequestStoragePermission28/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatRequestStoragePermission29/Android.bp31
-rw-r--r--tests/cts/permission/AppThatRequestStoragePermission29/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/AppThatRequestSystemAlertWindow22/Android.bp32
-rw-r--r--tests/cts/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml24
-rw-r--r--tests/cts/permission/AppThatRequestSystemAlertWindow23/Android.bp32
-rw-r--r--tests/cts/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml24
-rw-r--r--tests/cts/permission/AppThatRunsRationaleTests/Android.bp35
-rw-r--r--tests/cts/permission/AppThatRunsRationaleTests/AndroidManifest.xml26
-rw-r--r--tests/cts/permission/AppThatRunsRationaleTests/src/android/permission/cts/appthatrunsrationaletests/TestActivity.java42
-rw-r--r--tests/cts/permission/AppToTestRevokeSelfPermission/Android.bp35
-rw-r--r--tests/cts/permission/AppToTestRevokeSelfPermission/AndroidManifest.xml31
-rw-r--r--tests/cts/permission/AppToTestRevokeSelfPermission/src/android/permission/cts/apptotestselfrevokepermission/RevokePermission.java49
-rw-r--r--tests/cts/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp33
-rw-r--r--tests/cts/permission/AppWithSharedUidThatRequestLocationPermission28/AndroidManifest.xml29
-rw-r--r--tests/cts/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp33
-rw-r--r--tests/cts/permission/AppWithSharedUidThatRequestLocationPermission29/AndroidManifest.xml30
-rw-r--r--tests/cts/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp30
-rw-r--r--tests/cts/permission/AppWithSharedUidThatRequestsNoPermissions/AndroidManifest.xml24
-rw-r--r--tests/cts/permission/AppWithSharedUidThatRequestsPermissions/Android.bp30
-rw-r--r--tests/cts/permission/AppWithSharedUidThatRequestsPermissions/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/OWNERS12
-rw-r--r--tests/cts/permission/README16
-rw-r--r--tests/cts/permission/StorageEscalationApp28/Android.bp30
-rw-r--r--tests/cts/permission/StorageEscalationApp28/AndroidManifest.xml30
-rw-r--r--tests/cts/permission/StorageEscalationApp29Full/Android.bp30
-rw-r--r--tests/cts/permission/StorageEscalationApp29Full/AndroidManifest.xml30
-rw-r--r--tests/cts/permission/StorageEscalationApp29Scoped/Android.bp30
-rw-r--r--tests/cts/permission/StorageEscalationApp29Scoped/AndroidManifest.xml30
-rw-r--r--tests/cts/permission/jni/Android.bp60
-rw-r--r--tests/cts/permission/jni/CtsPermissionsJniOnLoad.cpp34
-rw-r--r--tests/cts/permission/jni/PermissionManagerNativeJniTest.cpp50
-rw-r--r--tests/cts/permission/jni/android_permission_cts_FileUtils.cpp250
-rw-r--r--tests/cts/permission/nativeTests/Android.bp56
-rw-r--r--tests/cts/permission/nativeTests/AndroidTest.xml43
-rw-r--r--tests/cts/permission/nativeTests/src/PermissionManagerNativeTest.cpp63
-rw-r--r--tests/cts/permission/permissionTestUtilLib/Android.bp37
-rw-r--r--tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerHelperRule.kt56
-rw-r--r--tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerService.java72
-rw-r--r--tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerServiceUtils.kt127
-rw-r--r--tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/MtsIgnore.java40
-rw-r--r--tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java414
-rw-r--r--tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java205
-rw-r--r--tests/cts/permission/res/drawable/robot.pngbin0 -> 5634 bytes
-rw-r--r--tests/cts/permission/res/values/strings.xml22
-rw-r--r--tests/cts/permission/res/xml/test_accessibilityservice.xml21
-rw-r--r--tests/cts/permission/sdk28/Android.bp34
-rw-r--r--tests/cts/permission/sdk28/AndroidManifest.xml52
-rw-r--r--tests/cts/permission/sdk28/AndroidTest.xml32
-rw-r--r--tests/cts/permission/sdk28/OWNERS1
-rw-r--r--tests/cts/permission/sdk28/TEST_MAPPING7
-rw-r--r--tests/cts/permission/sdk28/res/values/strings.xml19
-rw-r--r--tests/cts/permission/sdk28/src/android/permission/cts/sdk28/RequestLocation.java70
-rw-r--r--tests/cts/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt358
-rw-r--r--tests/cts/permission/src/android/permission/cts/AccessibilityTestService.kt22
-rw-r--r--tests/cts/permission/src/android/permission/cts/ActivityPermissionRationaleTest.java135
-rw-r--r--tests/cts/permission/src/android/permission/cts/AppIdleStatePermissionTest.java92
-rw-r--r--tests/cts/permission/src/android/permission/cts/AppWidgetManagerPermissionTest.java62
-rw-r--r--tests/cts/permission/src/android/permission/cts/BackgroundPermissionButtonLabelTest.java55
-rw-r--r--tests/cts/permission/src/android/permission/cts/BackgroundPermissionsTest.java254
-rw-r--r--tests/cts/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java324
-rw-r--r--tests/cts/permission/src/android/permission/cts/Camera2PermissionTest.java191
-rw-r--r--tests/cts/permission/src/android/permission/cts/CameraPermissionTest.java95
-rw-r--r--tests/cts/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java120
-rw-r--r--tests/cts/permission/src/android/permission/cts/ContactsProviderTest.java158
-rw-r--r--tests/cts/permission/src/android/permission/cts/DebuggableTest.java50
-rw-r--r--tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt239
-rw-r--r--tests/cts/permission/src/android/permission/cts/DuplicatePermissionDefinitionsTest.kt195
-rw-r--r--tests/cts/permission/src/android/permission/cts/EthernetManagerPermissionTest.java113
-rw-r--r--tests/cts/permission/src/android/permission/cts/FileSystemPermissionTest.java1279
-rw-r--r--tests/cts/permission/src/android/permission/cts/FileUtils.java128
-rw-r--r--tests/cts/permission/src/android/permission/cts/IgnoreAllTestsRule.java52
-rw-r--r--tests/cts/permission/src/android/permission/cts/LocationAccessCheckTest.java806
-rw-r--r--tests/cts/permission/src/android/permission/cts/MainlineNetworkStackPermissionTest.java68
-rw-r--r--tests/cts/permission/src/android/permission/cts/MinMaxSdkVersionTest.kt97
-rw-r--r--tests/cts/permission/src/android/permission/cts/NearbyDevicesPermissionTest.java307
-rw-r--r--tests/cts/permission/src/android/permission/cts/NearbyDevicesRenouncePermissionTest.java315
-rw-r--r--tests/cts/permission/src/android/permission/cts/NfcPermissionTest.java221
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java99
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoAudioPermissionTest.java124
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoBroadcastPackageRemovedPermissionTest.java104
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoCaptureVideoPermissionTest.java106
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoKeyPermissionTest.java100
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoNetworkStatePermissionTest.java99
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoReadLogsPermissionTest.java104
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoRollbackPermissionTest.java48
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java182
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoWakeLockPermissionTest.java119
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java190
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java219
-rw-r--r--tests/cts/permission/src/android/permission/cts/NotificationListenerCheckTest.java226
-rw-r--r--tests/cts/permission/src/android/permission/cts/NotificationListenerCheckWithSafetyCenterUnsupportedTest.java108
-rw-r--r--tests/cts/permission/src/android/permission/cts/OneTimePermissionTest.java396
-rw-r--r--tests/cts/permission/src/android/permission/cts/PackageManagerRequiringPermissionsTest.java124
-rw-r--r--tests/cts/permission/src/android/permission/cts/PermissionControllerTest.java517
-rw-r--r--tests/cts/permission/src/android/permission/cts/PermissionFlagsTest.java254
-rw-r--r--tests/cts/permission/src/android/permission/cts/PermissionGroupChange.java207
-rw-r--r--tests/cts/permission/src/android/permission/cts/PermissionManagerNativeJniTest.java26
-rw-r--r--tests/cts/permission/src/android/permission/cts/PermissionManagerTest.java52
-rw-r--r--tests/cts/permission/src/android/permission/cts/PermissionStubActivity.java46
-rw-r--r--tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java270
-rw-r--r--tests/cts/permission/src/android/permission/cts/PlatformPermissionGroupMappingTest.kt62
-rw-r--r--tests/cts/permission/src/android/permission/cts/PowerManagerServicePermissionTest.java57
-rw-r--r--tests/cts/permission/src/android/permission/cts/ProviderPermissionTest.java294
-rw-r--r--tests/cts/permission/src/android/permission/cts/RebootPermissionTest.java49
-rw-r--r--tests/cts/permission/src/android/permission/cts/RemovePermissionTest.java247
-rw-r--r--tests/cts/permission/src/android/permission/cts/RevokePermissionTest.kt214
-rw-r--r--tests/cts/permission/src/android/permission/cts/RevokeSawPermissionTest.kt63
-rw-r--r--tests/cts/permission/src/android/permission/cts/RevokeSelfPermissionTest.java361
-rw-r--r--tests/cts/permission/src/android/permission/cts/RuntimePermissionPresentationInfoTest.java64
-rw-r--r--tests/cts/permission/src/android/permission/cts/SafetyCenterUtils.kt158
-rw-r--r--tests/cts/permission/src/android/permission/cts/SdkSandboxPermissionTest.java64
-rw-r--r--tests/cts/permission/src/android/permission/cts/SecureElementPermissionTest.java66
-rw-r--r--tests/cts/permission/src/android/permission/cts/ServicePermissionTest.java75
-rw-r--r--tests/cts/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java92
-rw-r--r--tests/cts/permission/src/android/permission/cts/SharedUidPermissionsTest.java150
-rw-r--r--tests/cts/permission/src/android/permission/cts/ShellCommandPermissionTest.java61
-rw-r--r--tests/cts/permission/src/android/permission/cts/ShellPermissionTest.java95
-rw-r--r--tests/cts/permission/src/android/permission/cts/SmsManagerPermissionTest.java124
-rw-r--r--tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java584
-rwxr-xr-xtests/cts/permission/src/android/permission/cts/SplitPermissionsSystemTest.java174
-rw-r--r--tests/cts/permission/src/android/permission/cts/StorageEscalationTest.kt158
-rw-r--r--tests/cts/permission/src/android/permission/cts/TvPermissionTest.java116
-rw-r--r--tests/cts/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt247
-rw-r--r--tests/cts/permission/src/android/permission/cts/appthataccesseslocation/IAccessLocationOnCommand.aidl22
-rw-r--r--tests/cts/permission/telephony/Android.bp39
-rw-r--r--tests/cts/permission/telephony/AndroidManifest.xml37
-rw-r--r--tests/cts/permission/telephony/AndroidTest.xml44
-rw-r--r--tests/cts/permission/telephony/OWNERS3
-rw-r--r--tests/cts/permission/telephony/src/android/permission/cts/telephony/TelephonyManagerPermissionTest.java470
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp32
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/res/values/strings.xml19
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp32
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/AndroidManifest.xml25
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp32
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/AndroidManifest.xml27
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp32
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp32
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/AndroidManifest.xml25
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/AndroidManifest.xml25
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp32
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/AndroidManifest.xml28
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/res/values/strings.xml19
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp32
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/AndroidManifest.xml25
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp32
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/AndroidManifest.xml25
-rw-r--r--tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/res/values/strings.xml19
-rw-r--r--tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/Android.bp32
-rw-r--r--tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml28
-rw-r--r--tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt22
-rw-r--r--tests/cts/permissionmultidevice/Android.bp50
-rw-r--r--tests/cts/permissionmultidevice/AndroidManifest.xml36
-rw-r--r--tests/cts/permissionmultidevice/AndroidTest.xml82
-rw-r--r--tests/cts/permissionmultidevice/OWNERS3
-rw-r--r--tests/cts/permissionmultidevice/TEST_MAPPNG7
-rw-r--r--tests/cts/permissionmultidevice/TestUtils/Android.bp41
-rw-r--r--tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/FakeVirtualDeviceRule.kt75
-rw-r--r--tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PackageManagementUtils.kt38
-rw-r--r--tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt32
-rw-r--r--tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/UiAutomatorUtils.kt56
-rw-r--r--tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt207
-rw-r--r--tests/cts/permissionmultiuser/Android.bp48
-rw-r--r--tests/cts/permissionmultiuser/AndroidManifest.xml34
-rw-r--r--tests/cts/permissionmultiuser/AndroidTest.xml71
-rw-r--r--tests/cts/permissionmultiuser/OWNERS3
-rw-r--r--tests/cts/permissionmultiuser/RequestLocationApp/Android.bp25
-rw-r--r--tests/cts/permissionmultiuser/RequestLocationApp/AndroidManifest.xml23
-rw-r--r--tests/cts/permissionmultiuser/TEST_MAPPING7
-rw-r--r--tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt493
-rw-r--r--tests/cts/permissionpolicy/Android.bp68
-rwxr-xr-xtests/cts/permissionpolicy/AndroidManifest.xml74
-rw-r--r--tests/cts/permissionpolicy/AndroidTest.xml84
-rw-r--r--tests/cts/permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml26
-rw-r--r--tests/cts/permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml28
-rw-r--r--tests/cts/permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml28
-rw-r--r--tests/cts/permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml26
-rw-r--r--tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk22/Android.bp30
-rw-r--r--tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk22/AndroidManifest.xml29
-rw-r--r--tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk29/Android.bp30
-rw-r--r--tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk29/AndroidManifest.xml28
-rw-r--r--tests/cts/permissionpolicy/CtsProcessOutgoingCalls/Android.bp33
-rw-r--r--tests/cts/permissionpolicy/CtsProcessOutgoingCalls/AndroidManifest.xml33
-rw-r--r--tests/cts/permissionpolicy/CtsProcessOutgoingCalls/src/android/permissionpolicy/cts/receivecallbroadcast/ProcessOutgoingCallReceiver.kt36
-rw-r--r--tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk22/Android.bp30
-rw-r--r--tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk22/AndroidManifest.xml40
-rw-r--r--tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk29/Android.bp30
-rw-r--r--tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk29/AndroidManifest.xml38
-rw-r--r--tests/cts/permissionpolicy/CtsSMSNotRestrictedWithSharedUid/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml26
-rw-r--r--tests/cts/permissionpolicy/CtsSMSRestrictedWithSharedUid/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml26
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30/AndroidManifest.xml31
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk22/Android.bp24
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk22/AndroidManifest.xml30
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk28/Android.bp24
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk28/AndroidManifest.xml30
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk29/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk29/AndroidManifest.xml30
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk30/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk30/AndroidManifest.xml32
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk22/Android.bp24
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk22/AndroidManifest.xml31
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk28/Android.bp24
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk28/AndroidManifest.xml31
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserOptOutSdk29/Android.bp26
-rw-r--r--tests/cts/permissionpolicy/CtsStoragePermissionsUserOptOutSdk29/AndroidManifest.xml31
-rw-r--r--tests/cts/permissionpolicy/OWNERS7
-rw-r--r--tests/cts/permissionpolicy/res/raw/OWNERS8
-rw-r--r--tests/cts/permissionpolicy/res/raw/android_manifest.xml8230
-rw-r--r--tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml613
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/CommandBroadcastReceiver.java49
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ContactsProviderTest.java95
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/IntelligenceRolesPolicyTest.java99
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoCaptureAudioOutputPermissionTest.java70
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoProcessOutgoingCallPermissionTest.java142
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoReceiveSmsPermissionTest.java277
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoWriteSecureSettingsPermissionTest.java47
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionMaxSdkVersionTest.java59
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionPolicyTest.java533
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PrivappPermissionsTest.java251
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ProtectedBroadcastsTest.java121
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedPermissionsTest.java745
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedStoragePermissionSharedUidTest.java269
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedStoragePermissionTest.java755
-rw-r--r--tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt192
-rw-r--r--tests/cts/permissionui/Android.bp81
-rw-r--r--tests/cts/permissionui/AndroidManifest.xml89
-rw-r--r--tests/cts/permissionui/AndroidTest.xml101
-rw-r--r--tests/cts/permissionui/AppThatAccessesCameraAndMic/Android.bp35
-rw-r--r--tests/cts/permissionui/AppThatAccessesCameraAndMic/AndroidManifest.xml35
-rw-r--r--tests/cts/permissionui/AppThatAccessesCameraAndMic/src/android/permissionui/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt259
-rw-r--r--tests/cts/permissionui/CreateNotificationChannelsApp31/Android.bp33
-rw-r--r--tests/cts/permissionui/CreateNotificationChannelsApp31/AndroidManifest.xml44
-rw-r--r--tests/cts/permissionui/CreateNotificationChannelsApp31/src/android/permissionui/cts/usepermission/CreateNotificationChannelsActivity.kt187
-rw-r--r--tests/cts/permissionui/DifferentPkgNameApp/Android.bp33
-rw-r--r--tests/cts/permissionui/DifferentPkgNameApp/AndroidManifest.xml33
-rw-r--r--tests/cts/permissionui/DifferentPkgNameApp/src/android/permissionui/cts/usepermissionother/EmptyActivity.kt21
-rw-r--r--tests/cts/permissionui/HelperAppOverlay/Android.bp32
-rw-r--r--tests/cts/permissionui/HelperAppOverlay/AndroidManifest.xml28
-rw-r--r--tests/cts/permissionui/HelperAppOverlay/src/android/permissionui/cts/helper/overlay/OverlayActivity.kt26
-rw-r--r--tests/cts/permissionui/ImplicitUserSelectStorageApp/Android.bp33
-rw-r--r--tests/cts/permissionui/ImplicitUserSelectStorageApp/AndroidManifest.xml30
-rw-r--r--tests/cts/permissionui/MediaPermissionApp33WithStorage/Android.bp32
-rw-r--r--tests/cts/permissionui/MediaPermissionApp33WithStorage/AndroidManifest.xml29
-rw-r--r--tests/cts/permissionui/OWNERS4
-rw-r--r--tests/cts/permissionui/PermissionPolicyApp25/Android.bp31
-rw-r--r--tests/cts/permissionui/PermissionPolicyApp25/AndroidManifest.xml28
-rw-r--r--tests/cts/permissionui/PermissionPolicyApp25/src/android/permissionui/cts/permissionpolicy/TestProtectionFlagsActivity.kt112
-rw-r--r--tests/cts/permissionui/StorageApp33/Android.bp33
-rw-r--r--tests/cts/permissionui/StorageApp33/AndroidManifest.xml30
-rw-r--r--tests/cts/permissionui/TEST_MAPPING32
-rw-r--r--tests/cts/permissionui/UsePermissionApp22/Android.bp32
-rw-r--r--tests/cts/permissionui/UsePermissionApp22/AndroidManifest.xml79
-rw-r--r--tests/cts/permissionui/UsePermissionApp22CalendarOnly/Android.bp33
-rw-r--r--tests/cts/permissionui/UsePermissionApp22CalendarOnly/AndroidManifest.xml36
-rw-r--r--tests/cts/permissionui/UsePermissionApp22CalendarOnly/src/android/permissionui/cts/usepermission/CheckPermissionService.kt39
-rw-r--r--tests/cts/permissionui/UsePermissionApp22CalendarOnly/src/android/permissionui/cts/usepermission/StartCheckPermissionServiceActivity.kt31
-rw-r--r--tests/cts/permissionui/UsePermissionApp22None/Android.bp32
-rw-r--r--tests/cts/permissionui/UsePermissionApp22None/AndroidManifest.xml30
-rw-r--r--tests/cts/permissionui/UsePermissionApp23/Android.bp32
-rw-r--r--tests/cts/permissionui/UsePermissionApp23/AndroidManifest.xml76
-rw-r--r--tests/cts/permissionui/UsePermissionApp25/Android.bp32
-rw-r--r--tests/cts/permissionui/UsePermissionApp25/AndroidManifest.xml76
-rw-r--r--tests/cts/permissionui/UsePermissionApp26/Android.bp32
-rw-r--r--tests/cts/permissionui/UsePermissionApp26/AndroidManifest.xml34
-rw-r--r--tests/cts/permissionui/UsePermissionApp28/Android.bp32
-rw-r--r--tests/cts/permissionui/UsePermissionApp28/AndroidManifest.xml32
-rw-r--r--tests/cts/permissionui/UsePermissionApp29/Android.bp32
-rw-r--r--tests/cts/permissionui/UsePermissionApp29/AndroidManifest.xml33
-rw-r--r--tests/cts/permissionui/UsePermissionApp30/Android.bp33
-rw-r--r--tests/cts/permissionui/UsePermissionApp30/AndroidManifest.xml43
-rw-r--r--tests/cts/permissionui/UsePermissionApp30WithBackground/Android.bp32
-rw-r--r--tests/cts/permissionui/UsePermissionApp30WithBackground/AndroidManifest.xml31
-rw-r--r--tests/cts/permissionui/UsePermissionApp30WithBackground/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt57
-rw-r--r--tests/cts/permissionui/UsePermissionApp30WithBluetooth/Android.bp34
-rw-r--r--tests/cts/permissionui/UsePermissionApp30WithBluetooth/AndroidManifest.xml38
-rw-r--r--tests/cts/permissionui/UsePermissionApp30WithBluetooth/src/android/permissionui/cts/usepermission/AccessBluetoothOnCommand.kt154
-rw-r--r--tests/cts/permissionui/UsePermissionApp31/Android.bp33
-rw-r--r--tests/cts/permissionui/UsePermissionApp31/AndroidManifest.xml31
-rw-r--r--tests/cts/permissionui/UsePermissionApp32/Android.bp34
-rw-r--r--tests/cts/permissionui/UsePermissionApp32/AndroidManifest.xml26
-rw-r--r--tests/cts/permissionui/UsePermissionAppLatest/Android.bp40
-rw-r--r--tests/cts/permissionui/UsePermissionAppLatest/AndroidManifest.xml53
-rw-r--r--tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/CheckCalendarAccessActivity.kt71
-rw-r--r--tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/FinishOnCreateActivity.kt29
-rw-r--r--tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt93
-rw-r--r--tests/cts/permissionui/UsePermissionAppLatestNone/Android.bp33
-rw-r--r--tests/cts/permissionui/UsePermissionAppLatestNone/AndroidManifest.xml28
-rw-r--r--tests/cts/permissionui/UsePermissionAppLocationProvider/Android.bp31
-rw-r--r--tests/cts/permissionui/UsePermissionAppLocationProvider/AndroidManifest.xml37
-rw-r--r--tests/cts/permissionui/UsePermissionAppLocationProvider/res/values/strings.xml (renamed from PermissionController/res/values-w764dp-v33/dimens.xml)6
-rw-r--r--tests/cts/permissionui/UsePermissionAppLocationProvider/src/android/permissionui/cts/accessmicrophoneapplocationprovider/AddLocationProviderActivity.kt46
-rw-r--r--tests/cts/permissionui/UsePermissionAppLocationProvider/src/android/permissionui/cts/accessmicrophoneapplocationprovider/UseMicrophoneActivity.kt68
-rw-r--r--tests/cts/permissionui/UsePermissionAppWithOverlay/Android.bp35
-rw-r--r--tests/cts/permissionui/UsePermissionAppWithOverlay/AndroidManifest.xml29
-rw-r--r--tests/cts/permissionui/UsePermissionAppWithOverlay/res/drawable/border.xml25
-rw-r--r--tests/cts/permissionui/UsePermissionAppWithOverlay/res/layout/overlay_activity.xml34
-rw-r--r--tests/cts/permissionui/UsePermissionAppWithOverlay/res/values/strings.xml19
-rw-r--r--tests/cts/permissionui/UsePermissionAppWithOverlay/res/values/styles.xml22
-rw-r--r--tests/cts/permissionui/UsePermissionAppWithOverlay/src/android/permissionui/cts/usepermission/OverlayActivity.kt60
-rw-r--r--tests/cts/permissionui/UsePermissionAppWithOverlay/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt106
-rw-r--r--tests/cts/permissionui/res/raw/lg_g4_iso_800_jpg.jpgbin0 -> 107684 bytes
-rw-r--r--tests/cts/permissionui/res/raw/test_video.mp4bin0 -> 135632 bytes
-rwxr-xr-x[-rw-r--r--]tests/cts/permissionui/res/values-en-rGB/strings.xml (renamed from PermissionController/res/values-w764dp-v34/dimens.xml)6
-rwxr-xr-xtests/cts/permissionui/res/values/strings.xml28
-rw-r--r--tests/cts/permissionui/res/xml/test_accessibilityservice.xml21
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/AppDataSharingUpdatesTest.kt591
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/AppMetadata.kt214
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt213
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt502
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt1327
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt698
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/LocationAccuracyTest.kt164
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/LocationProviderInterceptDialogTest.kt149
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionTest.kt183
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionUpgradeTest.kt60
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/NoPermissionTest.kt46
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/NotificationPermissionTest.kt416
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt131
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionGroupTest.kt90
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionNoOpGtsTest.kt (renamed from PermissionController/src/com/android/permissioncontroller/role/ui/behavior/BrowserRoleUiBehavior.java)26
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionPolicyTest25.kt64
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionRationalePermissionGrantDialogTest.kt284
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionRationaleTest.kt385
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt98
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTest.kt176
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt114
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt150
-rwxr-xr-xtests/cts/permissionui/src/android/permissionui/cts/PermissionTest22.kt66
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionTest23.kt403
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionTest29.kt205
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionTest30.kt93
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionTest30WithBluetooth.kt225
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionUpgradeTest.kt154
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionUsageInfoTest.kt56
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt522
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerUtils.kt128
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/ReviewAccessibilityServicesTest.kt241
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/SafetyLabelChangesJobServiceTest.kt507
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/SafetyProtectionTest.kt120
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/SensorBlockedBannerTest.kt178
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/StartForFutureActivity.kt61
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/TestInstallerActivity.kt21
-rw-r--r--tests/cts/role/Android.bp50
-rw-r--r--tests/cts/role/AndroidManifest.xml40
-rw-r--r--tests/cts/role/AndroidTest.xml51
-rw-r--r--tests/cts/role/CtsRoleTestApp/Android.bp26
-rw-r--r--tests/cts/role/CtsRoleTestApp/AndroidManifest.xml131
-rw-r--r--tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultDialerActivity.java52
-rw-r--r--tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultSmsActivity.java52
-rw-r--r--tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/IsRoleHeldActivity.java46
-rw-r--r--tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/RequestRoleActivity.java53
-rw-r--r--tests/cts/role/CtsRoleTestApp28/Android.bp27
-rw-r--r--tests/cts/role/CtsRoleTestApp28/AndroidManifest.xml79
-rw-r--r--tests/cts/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultDialerActivity.java40
-rw-r--r--tests/cts/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultSmsActivity.java41
-rw-r--r--tests/cts/role/CtsRoleTestApp33WithoutInCallService/Android.bp23
-rw-r--r--tests/cts/role/CtsRoleTestApp33WithoutInCallService/AndroidManifest.xml37
-rw-r--r--tests/cts/role/OWNERS3
-rw-r--r--tests/cts/role/TEST_MAPPING48
-rw-r--r--tests/cts/role/src/android/app/role/cts/RoleControllerManagerTest.kt167
-rw-r--r--tests/cts/role/src/android/app/role/cts/RoleManagerTest.java1239
-rw-r--r--tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt200
-rw-r--r--tests/cts/role/src/android/app/role/cts/WaitForResultActivity.java75
-rw-r--r--tests/cts/safetycenter/Android.bp1
-rw-r--r--tests/cts/safetycenter/AndroidTest.xml3
-rw-r--r--tests/cts/safetycenter/TEST_MAPPING2
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt62
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt80
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt177
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt39
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt4
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt16
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt204
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt4
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt4
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt10
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt8
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt44
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt33
-rw-r--r--tests/functional/safetycenter/multiusers/AndroidTest.xml3
-rw-r--r--tests/functional/safetycenter/multiusers/TEST_MAPPING27
-rw-r--r--tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt423
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml3
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING2
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt107
-rw-r--r--tests/functional/safetycenter/singleuser/AndroidManifest.xml9
-rw-r--r--tests/functional/safetycenter/singleuser/AndroidTest.xml3
-rw-r--r--tests/functional/safetycenter/singleuser/TEST_MAPPING2
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt1390
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt300
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterShellCommandsTest.kt (renamed from tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt)46
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetySourceDataFixesTest.kt298
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt92
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt108
-rw-r--r--tests/functional/safetycenter/subpages/Android.bp43
-rw-r--r--tests/functional/safetycenter/subpages/AndroidManifest.xml30
-rw-r--r--tests/functional/safetycenter/subpages/AndroidTest.xml64
-rw-r--r--tests/functional/safetycenter/subpages/TEST_MAPPING17
-rw-r--r--tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt (renamed from tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt)85
-rw-r--r--tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt (renamed from tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt)86
-rw-r--r--tests/hostside/safetycenter/Android.bp1
-rw-r--r--tests/hostside/safetycenter/AndroidTest.xml3
-rw-r--r--tests/hostside/safetycenter/helper-app/Android.bp1
-rw-r--r--tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt47
-rw-r--r--tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt35
-rw-r--r--tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt61
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt131
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt57
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt14
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt28
-rw-r--r--tests/utils/safetycenter/AndroidManifest.xml27
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt1
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/EnableSensorRule.kt72
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/NotificationCharacteristics.kt (renamed from tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/NotificationCharacteristics.kt)4
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt18
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt16
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt66
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt73
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt65
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt25
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestRule.kt57
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt14
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt38
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt154
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/StatusBarNotificationWithChannel.kt (renamed from tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/StatusBarNotificationWithChannel.kt)2
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SupportsSafetyCenter.kt29
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SupportsSafetyCenterRule.kt50
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt34
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/TestNotificationListener.kt (renamed from tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/TestNotificationListener.kt)116
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt85
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/WaitForBroadcasts.kt74
1580 files changed, 89075 insertions, 16445 deletions
diff --git a/Android.bp b/Android.bp
index 4a436da6c..389f330a6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -21,6 +21,9 @@ apex {
name: "com.android.permission",
defaults: ["com.android.permission-defaults"],
manifest: "apex_manifest.json",
+ compat_configs: [
+ "framework-permission-s-compat-config"
+ ],
}
apex_defaults {
@@ -30,7 +33,6 @@ apex_defaults {
systemserverclasspath_fragments: ["com.android.permission-systemserverclasspath-fragment"],
prebuilts: [
"current_sdkinfo",
- "privapp_allowlist_com.android.permissioncontroller.xml",
],
key: "com.android.permission.key",
certificate: ":com.android.permission.certificate",
@@ -105,6 +107,7 @@ bootclasspath_fragment {
// result in a build failure due to inconsistent flags.
package_prefixes: [
"android.app.role",
+ "android.app.ecm",
"android.permission.jarjar",
"android.safetycenter",
"android.safetylabel",
diff --git a/OWNERS b/OWNERS
index 3b4a8342c..403e9f430 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 137825
+
include platform/frameworks/base:/core/java/android/permission/OWNERS
include platform/packages/modules/common:/MODULES_OWNERS # see go/mainline-owners-policy
diff --git a/PermissionController/Android.bp b/PermissionController/Android.bp
index b4227f57f..54596049e 100644
--- a/PermissionController/Android.bp
+++ b/PermissionController/Android.bp
@@ -52,42 +52,35 @@ java_library {
srcs: [
":statslog-permissioncontroller-java-gen",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
-}
-
-// File to be included by permission controller app an mocking tests
-filegroup {
- name: "permissioncontroller-sources",
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ":permissioncontroller-protos",
- ],
}
-filegroup {
+java_library {
name: "permissioncontroller-protos",
+ sdk_version: "system_current",
+ min_sdk_version: "30",
srcs: [
"src/**/*.proto",
],
+ proto: {
+ type: "lite",
+ include_dirs: ["packages/modules/Permission/PermissionController/src/com/android/permissioncontroller"],
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
-android_app {
- name: "PermissionController",
- // Compiling against "module_current" would allow using non-APIs within the permission APEX
- // boundaries, which may be unsafe because PermissionController is also shipped as a standalone
- // artifact. See also b/209458854.
+android_library {
+ name: "PermissionController-lib",
sdk_version: "system_current",
min_sdk_version: "30",
- updatable: true,
- privileged: true,
- certificate: "platform",
- rename_resources_package: false,
- required: ["privapp_allowlist_com.android.permissioncontroller.xml"],
-
- srcs: [":permissioncontroller-sources"],
+ use_resource_processor: true,
+ manifest: "AndroidManifest-lib.xml",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
//javacflags: ["-Werror"],
kotlincflags: [
@@ -98,13 +91,11 @@ android_app {
libs: [
"android.car-stubs",
- // Soong fails to automatically add this dependency because all the
- // *.kt sources are inside a filegroup.
- "kotlin-annotations",
"safety-center-annotations",
],
static_libs: [
+ "permissioncontroller-protos",
"iconloader_sc_mainline_prod",
"com.google.android.material_material",
"androidx.transition_transition",
@@ -155,20 +146,55 @@ android_app {
"lottie",
"safety-label",
"role-controller",
+ "permissions-flags-lib",
+ "android.permission.flags-aconfig-java",
+ "androidx.compose.foundation_foundation",
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.runtime_runtime-livedata",
+ "androidx.compose.ui_ui",
+ "androidx.wear.compose_compose-material",
],
- proto: {
- type: "lite",
- include_dirs: ["packages/modules/Permission/PermissionController/src/com/android/permissioncontroller"],
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["Recycle"],
+ baseline_filename: "lint-baseline.xml",
+
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
+
+ // TODO(b/313706381): Remove jarjar once flagging lib is fixed
+ jarjar_rules: "jarjar-rules.txt",
+}
+
+android_app {
+ name: "PermissionController",
+ // Compiling against "module_current" would allow using non-APIs within the permission APEX
+ // boundaries, which may be unsafe because PermissionController is also shipped as a standalone
+ // artifact. See also b/209458854.
+ sdk_version: "system_current",
+ min_sdk_version: "30",
+ updatable: true,
+ privileged: true,
+ certificate: "platform",
+ use_resource_processor: true,
+ rename_resources_package: false,
+ privapp_allowlist: ":privapp_allowlist_com.android.permissioncontroller.xml",
+
+ static_libs: ["PermissionController-lib"],
+
lint: {
strict_updatability_linting: true,
error_checks: ["Recycle"],
- baseline_filename: "lint-baseline.xml",
+
},
optimize: {
+ proguard_compatibility: false, // TODO(b/215530220): remove when this is default behavior
proguard_flags_files: ["proguard.flags"],
},
diff --git a/PermissionController/AndroidManifest-lib.xml b/PermissionController/AndroidManifest-lib.xml
new file mode 100644
index 000000000..759256823
--- /dev/null
+++ b/PermissionController/AndroidManifest-lib.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest package="com.android.permissioncontroller">
+</manifest>
diff --git a/PermissionController/AndroidManifest.xml b/PermissionController/AndroidManifest.xml
index 874ba35d6..6dfee27d0 100644
--- a/PermissionController/AndroidManifest.xml
+++ b/PermissionController/AndroidManifest.xml
@@ -66,6 +66,7 @@
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
<uses-permission android:name="android.permission.READ_APP_SPECIFIC_LOCALES" />
<uses-permission android:name="android.permission.GET_APP_METADATA" />
+ <uses-permission android:name="android.permission.NFC_PREFERRED_PAYMENT_INFO" />
<application android:name="com.android.permissioncontroller.PermissionControllerApplication"
android:label="@string/app_name"
@@ -270,8 +271,7 @@
android:windowSoftInputMode="stateAlwaysHidden|adjustNothing"
android:visibleToInstantApps="true"
android:inheritShowWhenLocked="true"
- android:hardwareAccelerated="false"
- android:canDisplayOnRemoteDevices="false">
+ android:canDisplayOnRemoteDevices="@bool/is_at_least_v">
<intent-filter android:priority="1">
<action android:name="android.content.pm.action.REQUEST_PERMISSIONS" />
<category android:name="android.intent.category.DEFAULT" />
@@ -291,7 +291,7 @@
android:visibleToInstantApps="true"
android:inheritShowWhenLocked="true"
android:hardwareAccelerated="false"
- android:canDisplayOnRemoteDevices="false">
+ android:canDisplayOnRemoteDevices="@bool/is_at_least_v">
</activity>
<activity android:name="com.android.permissioncontroller.permission.ui.ManagePermissionsActivity"
@@ -399,6 +399,7 @@
<activity android:name="com.android.permissioncontroller.role.ui.RequestRoleActivity"
android:excludeFromRecents="true"
android:exported="true"
+ android:launchMode="singleTop"
android:theme="@style/RequestRole.FilterTouches">
<intent-filter android:priority="1">
<action android:name="android.app.role.action.REQUEST_ROLE" />
@@ -472,6 +473,18 @@
</intent-filter>
</activity>
+ <activity android:name="com.android.permissioncontroller.role.ui.ChangeDefaultCardEmulationActivity"
+ android:enabled="@bool/is_at_least_v"
+ android:excludeFromRecents="true"
+ android:noHistory="true"
+ android:exported="true"
+ android:theme="@android:style/Theme.NoDisplay">
+ <intent-filter android:priority="1001">
+ <action android:name="android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<provider android:name="com.android.permissioncontroller.permission.service.PermissionSearchIndexablesProvider"
android:authorities="com.android.permissioncontroller"
android:multiprocess="false"
@@ -521,7 +534,7 @@
</intent-filter>
</service>
- <service android:name="com.android.permissioncontroller.role.service.RoleControllerServiceImpl"
+ <service android:name="com.android.role.controller.service.RoleControllerServiceImpl"
android:exported="true">
<intent-filter android:priority="1">
<action android:name="android.app.role.RoleControllerService"/>
@@ -577,7 +590,7 @@
</receiver>
<activity android:name="com.android.permissioncontroller.incident.ConfirmationActivity"
- android:theme="@style/Theme.DeviceDefault.Dialog.NoActionBar.DayNight"
+ android:theme="@style/Theme.PermissionController.IncidentReportDialog"
android:exported="false"
android:excludeFromRecents="true"
android:finishOnCloseSystemDialogs="true"
@@ -593,6 +606,7 @@
android:name="com.android.permissioncontroller.safetycenter.ui.SafetyCenterActivity"
android:enabled="@bool/is_at_least_t"
android:exported="true"
+ android:enableOnBackInvokedCallback="true"
android:theme="@style/Theme.SafetyCenter">
<intent-filter android:priority="1">
<action android:name="android.intent.action.SAFETY_CENTER"/>
@@ -606,8 +620,6 @@
</intent-filter>
</activity>
- <!-- Unexported empty activity for in-process tests -->
- <activity android:name="android.app.Activity" />
</application>
</manifest>
diff --git a/PermissionController/TEST_MAPPING b/PermissionController/TEST_MAPPING
index 0ae3818fd..a7f2aec54 100644
--- a/PermissionController/TEST_MAPPING
+++ b/PermissionController/TEST_MAPPING
@@ -16,17 +16,17 @@
"name": "PermissionUiTestCases",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
],
"presubmit-large": [
{
- "name": "CtsPermission3TestCases",
+ "name": "CtsPermissionUiTestCases",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
@@ -43,7 +43,7 @@
"exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
},
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
],
"file_patterns": ["res/xml/roles\\.xml"]
@@ -52,7 +52,7 @@
"name": "PermissionUiTestCases[com.google.android.permission.apex]",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
},
// TODO(b/238773220): These tests currently fails on R base image
{
@@ -73,14 +73,65 @@
]
},
{
- "name": "CtsPermission3TestCases[com.google.android.permission.apex]",
+ "name": "CtsPermissionUiTestCases[com.google.android.permission.apex]",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
],
+ "postsubmit": [
+ {
+ "name": "CtsRoleTestCases",
+ "file_patterns": ["res/xml/roles\\.xml"]
+ },
+ {
+ "name": "PermissionUiTestCases"
+ },
+ {
+ "name": "CtsPermissionUiTestCases"
+ }
+ ],
+ "mainline-postsubmit": [
+ {
+ "name": "CtsRoleTestCases[com.google.android.permission.apex]",
+ "options": [
+ // TODO(b/238677748): These two tests currently fails on R base image
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#openDefaultAppListThenIsNotDefaultAppInList"
+ },
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
+ }
+ ],
+ "file_patterns": ["res/xml/roles\\.xml"]
+ },
+ {
+ "name": "PermissionUiTestCases[com.google.android.permission.apex]",
+ "options": [
+ // TODO(b/238773220): These tests currently fails on R base image
+ {
+ "exclude-filter": "com.android.permissioncontroller.permissionui.ui.handheld.ManageCustomPermissionsFragmentTest#groupSummaryGetsUpdatedWhenPermissionGetsGranted"
+ },
+ {
+ "exclude-filter": "com.android.permissioncontroller.permissionui.ui.handheld.ManageCustomPermissionsFragmentTest#groupSummaryGetsUpdatedWhenPermissionGetsRevoked"
+ },
+ {
+ "exclude-filter": "com.android.permissioncontroller.permissionui.ui.handheld.ManageStandardPermissionsFragmentTest#additionalPermissionSummaryGetUpdateWhenAppGetsInstalled"
+ },
+ {
+ "exclude-filter": "com.android.permissioncontroller.permissionui.ui.handheld.ManageStandardPermissionsFragmentTest#additionalPermissionSummaryGetUpdateWhenDefinerGetsUninstalled"
+ },
+ {
+ "exclude-filter": "com.android.permissioncontroller.permissionui.ui.handheld.ManageStandardPermissionsFragmentTest#additionalPermissionSummaryGetUpdateWhenUserGetsUninstalled"
+ }
+ ]
+ },
+ {
+ "name": "CtsPermissionUiTestCases[com.google.android.permission.apex]"
+ }
+ ],
"imports": [
{
"path": "vendor/xts/gts-tests/hostsidetests/permissioncontroller"
diff --git a/PermissionController/jarjar-rules.txt b/PermissionController/jarjar-rules.txt
new file mode 100644
index 000000000..4df97f4c0
--- /dev/null
+++ b/PermissionController/jarjar-rules.txt
@@ -0,0 +1,2 @@
+rule android.permission.flags.*Flags* com.android.permissioncontroller.jarjar.@0
+rule android.permission.flags.Flags com.android.permissioncontroller.jarjar.@0
diff --git a/PermissionController/lint-baseline.xml b/PermissionController/lint-baseline.xml
index 05a307234..5d77d8c81 100644
--- a/PermissionController/lint-baseline.xml
+++ b/PermissionController/lint-baseline.xml
@@ -1,147 +1,224 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.app.AppOpsManager.HistoricalOp#getDiscreteAccessAt`"
- errorLine1=" val attributedOpEntry: AttributedOpEntry = it.getDiscreteAccessAt(i)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Class requires API level 34 (current min is 31): `android.app.AppOpsManager.OnOpNotedListener`"
+ errorLine1=" AppOpsManager.OnOpNotedListener,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt"
- line="191"
- column="67"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt"
+ line="46"
+ column="5"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.app.AppOpsManager.HistoricalOp#getDiscreteAccessAt`"
- errorLine1=" val opEntry: AttributedOpEntry = it.getDiscreteAccessAt(i)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Class requires API level 34 (current min is 31): `android.app.AppOpsManager.OnOpNotedListener`"
+ errorLine1=" AppOpsManager.OnOpNotedListener,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt"
- line="156"
- column="57"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt"
+ line="43"
+ column="5"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.app.AppOpsManager.HistoricalOp#getDiscreteAccessCount`"
- errorLine1=" for (i in 0 until it.discreteAccessCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getIconId`"
+ errorLine1=" .setIcon(args.getIconId())"
+ errorLine2=" ~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt"
- line="155"
- column="38"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="504"
+ column="31"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.app.AppOpsManager.HistoricalOp#getDiscreteAccessCount`"
- errorLine1=" for (i in 0 until it.discreteAccessCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getMessageId`"
+ errorLine1=" .setMessage(args.getMessageId())"
+ errorLine2=" ~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt"
- line="190"
- column="38"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="505"
+ column="34"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.app.AppOpsManager.HistoricalOpsRequest.Builder#setHistoryFlags`"
- errorLine1=" .setHistoryFlags(HISTORY_FLAG_DISCRETE or HISTORY_FLAG_GET_ATTRIBUTION_CHAINS)"
- errorLine2=" ~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getNegativeButtonTextId`"
+ errorLine1=" .setNegativeButton(args.getNegativeButtonTextId(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt"
- line="101"
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="509"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `getPositiveButtonTextId`"
+ errorLine1=" .setPositiveButton(args.getPositiveButtonTextId(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="513"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `getSetOneTime`"
+ errorLine1=" mViewModel.requestChange(args.getSetOneTime(),"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="515"
+ column="59"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `getChangeRequest`"
+ errorLine1=" args.getChangeRequest(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="518"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `getButtonClicked`"
+ errorLine1=" args.getButtonClicked());"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="519"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `getTitleId`"
+ errorLine1=" if (args.getTitleId() != 0) {"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="521"
column="18"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.apphibernation.AppHibernationManager#isHibernatingForUser`"
- errorLine1=" if (hibernationManager.isHibernatingForUser(pkg.packageName)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getTitleId`"
+ errorLine1=" b.setTitle(args.getTitleId());"
+ errorLine2=" ~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt"
- line="56"
- column="44"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
+ line="522"
+ column="29"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.content.pm.Attribution#getLabel`"
- errorLine1=" attributions?.forEach { attributionTagToLabel[it.tag] = it.label }"
- errorLine2=" ~~~~~">
+ message="Call requires API level 33 (current min is 30): `getIconId`"
+ errorLine1=" .setIcon(args.getIconId())"
+ errorLine2=" ~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt"
- line="125"
- column="72"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="709"
+ column="31"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.content.pm.Attribution#getTag`"
- errorLine1=" attributions?.forEach { attributionTagToLabel[it.tag] = it.label }"
- errorLine2=" ~~~">
+ message="Call requires API level 33 (current min is 30): `getMessageId`"
+ errorLine1=" .setMessage(args.getMessageId())"
+ errorLine2=" ~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt"
- line="125"
- column="62"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="710"
+ column="34"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.permission.AdminPermissionControlParams#canAdminGrantSensorsPermissions`"
- errorLine1=" params.getGrantState(), params.canAdminGrantSensorsPermissions())));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getNegativeButtonTextId`"
+ errorLine1=" .setNegativeButton(args.getNegativeButtonTextId(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
- line="517"
- column="48"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="714"
+ column="41"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.permission.AdminPermissionControlParams#getGrantState`"
- errorLine1=" params.getGrantState(), params.canAdminGrantSensorsPermissions())));"
- errorLine2=" ~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getPositiveButtonTextId`"
+ errorLine1=" .setPositiveButton(args.getPositiveButtonTextId(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
- line="517"
- column="24"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="718"
+ column="41"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.permission.AdminPermissionControlParams#getGranteePackageName`"
- errorLine1=" callerPackageName, params.getGranteePackageName(), params.getPermission(),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getSetOneTime`"
+ errorLine1=" mViewModel.requestChange(args.getSetOneTime(),"
+ errorLine2=" ~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
- line="516"
- column="43"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="720"
+ column="59"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.permission.AdminPermissionControlParams#getPermission`"
- errorLine1=" callerPackageName, params.getGranteePackageName(), params.getPermission(),"
- errorLine2=" ~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getButtonClicked`"
+ errorLine1=" args.getChangeRequest(), args.getButtonClicked());"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
- line="516"
- column="75"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="722"
+ column="67"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.hardware.SensorPrivacyManager#addSensorPrivacyListener`"
- errorLine1=" mSensorPrivacyManager.addSensorPrivacyListener(mPrivacyChangedListener);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getChangeRequest`"
+ errorLine1=" args.getChangeRequest(), args.getButtonClicked());"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java"
- line="159"
- column="35"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="722"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `getTitleId`"
+ errorLine1=" if (args.getTitleId() != 0) {"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="724"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `getTitleId`"
+ errorLine1=" b.setTitle(args.getTitleId());"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
+ line="725"
+ column="29"/>
</issue>
<issue
@@ -150,8 +227,8 @@
errorLine1=" mSensorPrivacyManager.addSensorPrivacyListener(mPrivacyChangedListener);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java"
- line="114"
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java"
+ line="159"
column="35"/>
</issue>
@@ -168,123 +245,134 @@
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.hardware.SensorPrivacyManager#removeSensorPrivacyListener`"
- errorLine1=" mSensorPrivacyManager.removeSensorPrivacyListener(mPrivacyChangedListener);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getIconId`"
+ errorLine1=" .setIcon(args.getIconId())"
+ errorLine2=" ~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java"
- line="365"
- column="35"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="463"
+ column="31"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterData#getIssues`"
- errorLine1=" ) : this(safetyCenterData.status, hasIssues = safetyCenterData.issues.size &gt; 0)"
- errorLine2=" ~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getMessageId`"
+ errorLine1=" .setMessage(args.getMessageId())"
+ errorLine2=" ~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
- line="18"
- column="68"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="464"
+ column="34"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterData#getIssues`"
- errorLine1=" issues"
- errorLine2=" ~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getNegativeButtonTextId`"
+ errorLine1=" .setNegativeButton(args.getNegativeButtonTextId(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="309"
- column="5"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="468"
+ column="41"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterData#getIssues`"
- errorLine1="private fun SafetyCenterData.buildIssueIdSet(): Set&lt;IssueId&gt; = issues.map { it.id }.toSet()"
- errorLine2=" ~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getPositiveButtonTextId`"
+ errorLine1=" .setPositiveButton(args.getPositiveButtonTextId(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="323"
- column="64"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="472"
+ column="41"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterData#getStatus`"
- errorLine1=" ) : this(safetyCenterData.status, hasIssues = safetyCenterData.issues.size &gt; 0)"
- errorLine2=" ~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getSetOneTime`"
+ errorLine1=" mViewModel.requestChange(args.getSetOneTime(),"
+ errorLine2=" ~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
- line="18"
- column="31"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="474"
+ column="59"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterData#getStatus`"
- errorLine1=" status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS"
- errorLine2=" ~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getButtonClicked`"
+ errorLine1=" args.getChangeRequest(), args.getButtonClicked());"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="321"
- column="5"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="476"
+ column="67"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue#getActions`"
- errorLine1=" issue.actions"
- errorLine2=" ~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `getChangeRequest`"
+ errorLine1=" args.getChangeRequest(), args.getButtonClicked());"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="311"
- column="19"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="476"
+ column="42"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue#getId`"
- errorLine1=" .map { issue.id to it.id }"
- errorLine2=" ~~">
+ message="Call requires API level 33 (current min is 30): `getTitleId`"
+ errorLine1=" if (args.getTitleId() != 0) {"
+ errorLine2=" ~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="315"
- column="30"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="478"
+ column="18"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue#getId`"
- errorLine1="private fun SafetyCenterData.buildIssueIdSet(): Set&lt;IssueId&gt; = issues.map { it.id }.toSet()"
- errorLine2=" ~~">
+ message="Call requires API level 33 (current min is 30): `getTitleId`"
+ errorLine1=" b.setTitle(args.getTitleId());"
+ errorLine2=" ~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="323"
- column="80"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
+ line="479"
+ column="29"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue.Action#getId`"
- errorLine1=" .map { issue.id to it.id }"
- errorLine2=" ~~">
+ message="Call requires API level 34 (current min is 30): `android.health.connect.HealthConnectManager#isHealthPermission`"
+ errorLine1=" .filter { permission -&gt; isHealthPermission(activity, permission) }"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="315"
- column="39"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt"
+ line="1059"
+ column="45"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue.Action#getSuccessMessage`"
- errorLine1=" .filter { it.isInFlight &amp;&amp; !it.successMessage.isNullOrEmpty() }"
- errorLine2=" ~~~~~~~~~~~~~~">
+ message="Class requires API level 31 (current min is 30): `android.apphibernation.AppHibernationManager`"
+ errorLine1=" userContext.getSystemService(APP_HIBERNATION_SERVICE) as AppHibernationManager"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="314"
- column="48"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt"
+ line="48"
+ column="74"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.apphibernation.AppHibernationManager#isHibernatingForUser`"
+ errorLine1=" if (hibernationManager.isHibernatingForUser(pkg.packageName)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt"
+ line="51"
+ column="44"/>
</issue>
<issue
@@ -300,266 +388,310 @@
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue.Action#isInFlight`"
- errorLine1=" .filter { it.isInFlight &amp;&amp; !it.successMessage.isNullOrEmpty() }"
- errorLine2=" ~~~~~~~~~~">
+ message="Call requires API level 31 (current min is 30): `android.os.UserManager#isCloneProfile`"
+ errorLine1=" if (userManager.isCloneProfile) {"
+ errorLine2=" ~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="314"
- column="30"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt"
+ line="653"
+ column="29"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager#isSafetyCenterEnabled`"
- errorLine1=" if (!safetyCenterManager.isSafetyCenterEnabled()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.app.Activity#startActivityForResultAsUser`"
+ errorLine1=" activity.startActivityForResultAsUser(pickerIntent, requestCode, user)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
- line="96"
- column="34"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt"
+ line="662"
+ column="18"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager#isSafetyCenterEnabled`"
- errorLine1=" if (!safetyCenterManager.isSafetyCenterEnabled()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 34 (current min is 30): `android.health.connect.HealthConnectManager#getHealthPermissions`"
+ errorLine1=" val permissions = HealthConnectManager.getHealthPermissions(context)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
- line="149"
- column="34"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt"
+ line="1689"
+ column="48"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager#isSafetyCenterEnabled`"
- errorLine1=" if (!scManager.isSafetyCenterEnabled) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 31 (current min is 30): `android.content.pm.Attribution#getLabel`"
+ errorLine1=" attributions?.forEach { attributionTagToLabel[it.tag] = it.label }"
+ errorLine2=" ~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt"
- line="48"
- column="24"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt"
+ line="140"
+ column="72"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager#refreshSafetySources`"
- errorLine1=" safetyCenterManager.refreshSafetySources(getRefreshReason());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 31 (current min is 30): `android.content.pm.Attribution#getTag`"
+ errorLine1=" attributions?.forEach { attributionTagToLabel[it.tag] = it.label }"
+ errorLine2=" ~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
- line="155"
- column="29"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt"
+ line="140"
+ column="62"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterStatus#getRefreshStatus`"
- errorLine1=" when (status.refreshStatus) {"
- errorLine2=" ~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue#getActions`"
+ errorLine1=" issue.actions"
+ errorLine2=" ~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
- line="65"
- column="26"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="288"
+ column="19"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterStatus#getRefreshStatus`"
- errorLine1=" status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS"
- errorLine2=" ~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue.Action#getSuccessMessage`"
+ errorLine1=" .filter { it.isInFlight &amp;&amp; !it.successMessage.isNullOrEmpty() }"
+ errorLine2=" ~~~~~~~~~~~~~~">
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
- line="321"
- column="12"/>
+ line="291"
+ column="48"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `recordPermissionDecision`"
- errorLine1=" PermissionDecisionStorageImpl.recordPermissionDecision(app.applicationContext,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue.Action#isInFlight`"
+ errorLine1=" .filter { it.isInFlight &amp;&amp; !it.successMessage.isNullOrEmpty() }"
+ errorLine2=" ~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt"
- line="1147"
- column="39"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="291"
+ column="30"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 34 (current min is 30): `android.content.pm.PackageManager#getAppMetadata`"
- errorLine1=" app.packageManager.getAppMetadata(packageName)"
- errorLine2=" ~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue#getId`"
+ errorLine1=" .map { issue.id to it.id }"
+ errorLine2=" ~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt"
- line="116"
- column="32"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="292"
+ column="30"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 34 (current min is 30): `android.health.connect.HealthConnectManager#getHealthPermissions`"
- errorLine1=" val permissions = HealthConnectManager.getHealthPermissions(context)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue.Action#getId`"
+ errorLine1=" .map { issue.id to it.id }"
+ errorLine2=" ~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt"
- line="1465"
- column="48"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="292"
+ column="39"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 34 (current min is 30): `android.health.connect.HealthConnectManager#isHealthPermission`"
- errorLine1=" isHealthPermission(activity, permission)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterData#getStatus`"
+ errorLine1=" status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS"
+ errorLine2=" ~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt"
- line="1268"
- column="17"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="298"
+ column="5"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 34 (current min is 33): `getParentGroupId`"
- errorLine1=" String groupId = getParentGroupId(preferenceKey);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterStatus#getRefreshStatus`"
+ errorLine1=" status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS"
+ errorLine2=" ~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java"
- line="89"
- column="30"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="298"
+ column="12"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 34 (current min is 33): `openRelevantSubpage`"
- errorLine1=" frag = openRelevantSubpage(groupId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue#getId`"
+ errorLine1=" allResolvableIssues.map { it.id }.toSet()"
+ errorLine2=" ~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java"
- line="86"
- column="20"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="301"
+ column="34"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 34 (current min is 33): `openRelevantSubpage`"
- errorLine1=" frag = openRelevantSubpage(groupId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterData#getIssues`"
+ errorLine1=" issues.asSequence()"
+ errorLine2=" ~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java"
- line="90"
- column="20"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="308"
+ column="13"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.apphibernation.AppHibernationManager`"
- errorLine1=" userContext.getSystemService(APP_HIBERNATION_SERVICE) as AppHibernationManager"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ message="Field requires API level 33 (current min is 30): `Companion`"
+ errorLine1=" MoreIssuesCardPreference.TAG,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt"
- line="53"
- column="74"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt"
+ line="110"
+ column="21"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager`"
- errorLine1=" context.getSystemService(SafetyCenterManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Field requires API level 33 (current min is 30): `getTAG`"
+ errorLine1=" MoreIssuesCardPreference.TAG,"
+ errorLine2=" ~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
- line="84"
- column="42"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt"
+ line="110"
+ column="46"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager`"
- errorLine1=" SafetyCenterManager safetyCenterManager = this.getSystemService(SafetyCenterManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.hardware.SensorPrivacyManager#addSensorPrivacyListener`"
+ errorLine1=" mSensorPrivacyManager.addSensorPrivacyListener(mPrivacyChangedListener);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
- line="144"
- column="73"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java"
+ line="114"
+ column="35"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager`"
- errorLine1=" val scManager = getSystemService(SafetyCenterManager::class.java)!!"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.hardware.SensorPrivacyManager#removeSensorPrivacyListener`"
+ errorLine1=" mSensorPrivacyManager.removeSensorPrivacyListener(mPrivacyChangedListener);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt"
- line="41"
- column="42"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java"
+ line="365"
+ column="35"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 34 (current min is 30): `android.app.AppOpsManager.OnOpNotedListener`"
- errorLine1=" AppOpsManager.OnOpNotedListener,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 31 (current min is 30): `SensorStatusLiveData`"
+ errorLine1=" lazy(LazyThreadSafetyMode.NONE) { SensorStatusLiveData() }"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt"
- line="45"
- column="5"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt"
+ line="100"
+ column="43"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 34 (current min is 30): `android.app.AppOpsManager.OnOpNotedListener`"
- errorLine1=" AppOpsManager.OnOpNotedListener,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 31 (current min is 30): `android.permission.AdminPermissionControlParams#getGranteePackageName`"
+ errorLine1=" callerPackageName, params.getGranteePackageName(), params.getPermission(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt"
- line="38"
- column="5"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
+ line="521"
+ column="43"/>
</issue>
<issue
id="NewApi"
- message="Field requires API level 33 (current min is 30): `getTAG`"
- errorLine1=" MoreIssuesCardPreference.TAG,"
- errorLine2=" ~~~">
+ message="Call requires API level 31 (current min is 30): `android.permission.AdminPermissionControlParams#getPermission`"
+ errorLine1=" callerPackageName, params.getGranteePackageName(), params.getPermission(),"
+ errorLine2=" ~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt"
- line="107"
- column="46"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
+ line="521"
+ column="75"/>
</issue>
<issue
id="NewApi"
- message="Method reference requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterStatus::severityLevel`"
- errorLine1=" val severityLevel: Int by status::severityLevel"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 31 (current min is 30): `android.permission.AdminPermissionControlParams#canAdminGrantSensorsPermissions`"
+ errorLine1=" params.getGrantState(), params.canAdminGrantSensorsPermissions())));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
- line="30"
- column="31"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
+ line="522"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.permission.AdminPermissionControlParams#getGrantState`"
+ errorLine1=" params.getGrantState(), params.canAdminGrantSensorsPermissions())));"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
+ line="522"
+ column="24"/>
</issue>
<issue
id="NewApi"
- message="Method reference requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterStatus::summary`"
- errorLine1=" val originalSummary: CharSequence by status::summary"
- errorLine2=" ~~~~~~~~~~~~~~~">
+ message="Class requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager`"
+ errorLine1=" context.getSystemService(SafetyCenterManager.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
- line="29"
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
+ line="85"
column="42"/>
</issue>
<issue
id="NewApi"
- message="Method reference requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterStatus::title`"
- errorLine1=" val title: CharSequence by status::title"
- errorLine2=" ~~~~~~~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager#isSafetyCenterEnabled`"
+ errorLine1=" if (!safetyCenterManager.isSafetyCenterEnabled()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
- line="28"
- column="32"/>
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
+ line="97"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Class requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager`"
+ errorLine1=" SafetyCenterManager safetyCenterManager = this.getSystemService(SafetyCenterManager.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
+ line="141"
+ column="73"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager#isSafetyCenterEnabled`"
+ errorLine1=" if (!safetyCenterManager.isSafetyCenterEnabled()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
+ line="146"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager#refreshSafetySources`"
+ errorLine1=" safetyCenterManager.refreshSafetySources(getRefreshReason());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
+ line="152"
+ column="29"/>
</issue>
</issues> \ No newline at end of file
diff --git a/PermissionController/proguard.flags b/PermissionController/proguard.flags
index 13590aa39..292e3e4f4 100644
--- a/PermissionController/proguard.flags
+++ b/PermissionController/proguard.flags
@@ -31,3 +31,13 @@
*** set*(***);
*** has*();
}
+
+# Strip verbose logs.
+-assumenosideeffects class android.util.Log {
+ static *** v(...);
+ static *** isLoggable(...);
+}
+-assumenosideeffects class android.util.Slog {
+ static *** v(...);
+}
+-maximumremovedandroidloglevel 2
diff --git a/PermissionController/res/drawable/ic_edit.xml b/PermissionController/res/drawable/ic_edit.xml
new file mode 100644
index 000000000..6b806a894
--- /dev/null
+++ b/PermissionController/res/drawable/ic_edit.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2023 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+android:width="24dp"
+android:height="24dp"
+android:viewportWidth="24"
+android:viewportHeight="24"
+android:tint="?android:attr/colorControlNormal">
+<path android:fillColor="#FFFFFFFF"
+ android:pathData="M5,19H6.4L16.45,8.975L15.75,8.25L15.025,7.55L5,17.6ZM3,21V16.75L16.45,3.325Q17.025,2.75 17.863,2.75Q18.7,2.75 19.275,3.325L20.675,4.75Q21.25,5.325 21.25,6.15Q21.25,6.975 20.675,7.55L7.25,21ZM19.25,6.15 L17.85,4.75ZM16.45,8.975 L15.75,8.25 15.025,7.55 16.45,8.975Z"/>
+</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable/ic_more_horizontal.xml b/PermissionController/res/drawable/ic_more_horizontal.xml
new file mode 100644
index 000000000..c770e08ef
--- /dev/null
+++ b/PermissionController/res/drawable/ic_more_horizontal.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
+</vector>
diff --git a/PermissionController/res/layout-w764dp-v33/action_button_list.xml b/PermissionController/res/layout-v33/action_button_list_large_screen.xml
index 4db6df47c..141290fa2 100644
--- a/PermissionController/res/layout-w764dp-v33/action_button_list.xml
+++ b/PermissionController/res/layout-v33/action_button_list_large_screen.xml
@@ -16,6 +16,4 @@
<com.android.permissioncontroller.safetycenter.ui.EqualWidthContainer
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/action_button_list"
style="@style/SafetyCenterIssueActionButtonList" />
diff --git a/PermissionController/res/layout-v33/spaced_preference_category_no_label.xml b/PermissionController/res/layout-v33/action_button_list_small_screen.xml
index cecdc8bcd..048ac4595 100644
--- a/PermissionController/res/layout-v33/spaced_preference_category_no_label.xml
+++ b/PermissionController/res/layout-v33/action_button_list_small_screen.xml
@@ -14,5 +14,5 @@
~ limitations under the License.
-->
-<Space
- style="@style/SafetyCenterNoLabelPreferenceCategory"/> \ No newline at end of file
+<LinearLayout
+ style="@style/SafetyCenterIssueActionButtonList" />
diff --git a/PermissionController/res/layout-v33/action_button_list.xml b/PermissionController/res/layout-v33/preference_entries_top_padding.xml
index 3217f4c78..0e6e27148 100644
--- a/PermissionController/res/layout-v33/action_button_list.xml
+++ b/PermissionController/res/layout-v33/preference_entries_top_padding.xml
@@ -14,7 +14,7 @@
~ limitations under the License.
-->
-<LinearLayout
+<Space
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/action_button_list"
- style="@style/SafetyCenterIssueActionButtonList" />
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/sc_spacing_xsmall" /> \ No newline at end of file
diff --git a/PermissionController/res/layout-v33/preference_issue_card.xml b/PermissionController/res/layout-v33/preference_issue_card.xml
index 571efae3b..e6d749142 100644
--- a/PermissionController/res/layout-v33/preference_issue_card.xml
+++ b/PermissionController/res/layout-v33/preference_issue_card.xml
@@ -54,7 +54,7 @@
<include
android:id="@+id/issue_card_action_button_list"
- layout="@layout/action_button_list"/>
+ layout="?attr/scActionButtonListLayout"/>
<com.android.permissioncontroller.permission.ui.v33.widget.SafetyProtectionSectionView
android:id="@+id/issue_card_protected_by_android"
@@ -72,10 +72,10 @@
android:text="@string/safety_center_resolved_issue_fallback"
style="@style/SafetyCenterIssueCardResolvedTitle" />
- <!-- This group doesn't contain issue_card_dismiss_btn, issue_card_subtitle or
- issue_card_protected_by_android since the version of ConstraintLayout we're
- using doesn't allow us to override the group's visibility on individual group
- members. See b/242705351 for context. -->
+ <!-- This group doesn't contain issue_card_attribution_title, issue_card_dismiss_btn,
+ issue_card_subtitle or issue_card_protected_by_android since the version of
+ ConstraintLayout we're using doesn't allow us to override the group's visibility on
+ individual group members. See b/242705351 for context. -->
<androidx.constraintlayout.widget.Group
android:id="@+id/default_issue_content"
android:layout_width="wrap_content"
diff --git a/PermissionController/res/layout/app_permission.xml b/PermissionController/res/layout/app_permission.xml
index 6d68611fa..7e24207fe 100644
--- a/PermissionController/res/layout/app_permission.xml
+++ b/PermissionController/res/layout/app_permission.xml
@@ -83,53 +83,77 @@
android:id="@+id/permission_message"
style="@style/AppPermissionMessage" />
- <RadioGroup
- android:id="@+id/radiogroup"
- android:animateLayoutChanges="true"
+ <RadioButton
+ android:id="@+id/allow_radio_button"
+ android:text="@string/app_permission_button_allow"
+ style="@style/AppPermissionRadioButton" />
+
+ <RadioButton
+ android:id="@+id/allow_always_radio_button"
+ android:text="@string/app_permission_button_allow_always"
+ style="@style/AppPermissionRadioButton" />
+
+ <RadioButton
+ android:id="@+id/allow_foreground_only_radio_button"
+ android:text="@string/app_permission_button_allow_foreground"
+ style="@style/AppPermissionRadioButton" />
+
+ <RelativeLayout
+ android:id="@+id/radio_select_layout"
+ android:orientation="horizontal"
android:layout_width="match_parent"
+ android:layout_marginTop="16dp"
android:layout_height="wrap_content">
<RadioButton
- android:id="@+id/allow_radio_button"
- android:text="@string/app_permission_button_allow"
- style="@style/AppPermissionRadioButton" />
-
- <RadioButton
- android:id="@+id/allow_always_radio_button"
- android:text="@string/app_permission_button_allow_always"
- style="@style/AppPermissionRadioButton" />
-
- <RadioButton
- android:id="@+id/allow_foreground_only_radio_button"
- android:text="@string/app_permission_button_allow_foreground"
- style="@style/AppPermissionRadioButton" />
-
- <RadioButton
android:id="@+id/select_radio_button"
- android:text="@string/app_permission_button_ask"
- style="@style/AppPermissionRadioButton" />
-
- <RadioButton
- android:id="@+id/ask_one_time_radio_button"
- android:text="@string/app_permission_button_ask"
- style="@style/AppPermissionRadioButton" />
-
- <RadioButton
- android:id="@+id/ask_radio_button"
- android:text="@string/app_permission_button_ask"
- style="@style/AppPermissionRadioButton" />
-
- <RadioButton
- android:id="@+id/deny_radio_button"
- android:text="@string/app_permission_button_deny"
- style="@style/AppPermissionRadioButton" />
-
- <RadioButton
- android:id="@+id/deny_foreground_radio_button"
- android:text="@string/app_permission_button_deny"
- style="@style/AppPermissionRadioButton" />
+ android:text="@string/grant_dialog_button_allow_limited_access"
+ android:layout_alignParentStart="true"
+ style="@style/AppPermissionRadioButton"
+ android:layout_marginTop="0dp" />
+
+ <View
+ android:id="@+id/edit_photos_divider"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_toStartOf="@id/edit_selected_button"
+ android:layout_alignParentTop="true"
+ android:layout_alignBottom="@+id/select_radio_button"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:theme="@style/PreferenceDivider"/>
+
+ <ImageButton
+ android:id="@+id/edit_selected_button"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:contentDescription="@string/edit_photos_description"
+ android:background="@null"
+ android:src="@drawable/ic_edit"/>
+ </RelativeLayout>
+
+ <RadioButton
+ android:id="@+id/ask_one_time_radio_button"
+ android:text="@string/app_permission_button_ask"
+ style="@style/AppPermissionRadioButton" />
+
+ <RadioButton
+ android:id="@+id/ask_radio_button"
+ android:text="@string/app_permission_button_ask"
+ style="@style/AppPermissionRadioButton" />
+
+ <RadioButton
+ android:id="@+id/deny_radio_button"
+ android:text="@string/app_permission_button_deny"
+ style="@style/AppPermissionRadioButton" />
+
+ <RadioButton
+ android:id="@+id/deny_foreground_radio_button"
+ android:text="@string/app_permission_button_deny"
+ style="@style/AppPermissionRadioButton" />
- </RadioGroup>
<LinearLayout
android:layout_width="match_parent"
diff --git a/PermissionController/res/layout/grant_permissions.xml b/PermissionController/res/layout/grant_permissions.xml
index 9becddb7f..f01f00c60 100644
--- a/PermissionController/res/layout/grant_permissions.xml
+++ b/PermissionController/res/layout/grant_permissions.xml
@@ -143,7 +143,7 @@
<com.android.permissioncontroller.permission.ui.widget.SecureButton
android:id="@+id/permission_allow_selected_button"
- android:text="@string/grant_dialog_button_allow_selected_photos"
+ android:text="@string/grant_dialog_button_allow_limited_access"
style="@style/PermissionGrantButtonAllowSelected" />
<com.android.permissioncontroller.permission.ui.widget.SecureButton
@@ -184,7 +184,7 @@
<com.android.permissioncontroller.permission.ui.widget.SecureButton
android:id="@+id/permission_dont_allow_more_selected_button"
android:text="@string/grant_dialog_button_dont_select_more"
- style="@style/PermissionGrantButtonDeny" />
+ style="@style/PermissionGrantButtonDontAllowMore" />
</LinearLayout>
</LinearLayout>
diff --git a/PermissionController/res/layout/grant_permissions_material3.xml b/PermissionController/res/layout/grant_permissions_material3.xml
index d405976cf..6b1ccb2a4 100644
--- a/PermissionController/res/layout/grant_permissions_material3.xml
+++ b/PermissionController/res/layout/grant_permissions_material3.xml
@@ -144,7 +144,7 @@
<com.android.permissioncontroller.permission.ui.widget.SecureButton
android:id="@+id/permission_allow_selected_button"
- android:text="@string/grant_dialog_button_allow_selected_photos"
+ android:text="@string/grant_dialog_button_allow_limited_access"
style="@style/PermissionGrantButtonAllowSelectedMaterial3" />
<com.android.permissioncontroller.permission.ui.widget.SecureButton
diff --git a/PermissionController/res/navigation-watch/nav_graph.xml b/PermissionController/res/navigation-watch/nav_graph.xml
new file mode 100644
index 000000000..7af2c3e39
--- /dev/null
+++ b/PermissionController/res/navigation-watch/nav_graph.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/nav_graph"
+ app:startDestination="@id/manage_standard">
+
+ <!-- For explanation of the navigation component, and this graph, see
+ https://developer.android.com/guide/navigation -->
+
+ <fragment
+ android:id="@+id/manage_standard"
+ android:name="com.android.permissioncontroller.permission.ui.wear.WearManageStandardPermissionsFragment"
+ android:label="ManageStandard">
+
+ <action
+ android:id="@+id/standard_to_custom"
+ app:destination="@id/manage_custom"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popEnterAnim="@anim/activity_close_enter"
+ app:popExitAnim="@anim/activity_close_exit"/>
+
+ <action
+ android:id="@+id/manage_to_perm_apps"
+ app:destination="@id/permission_apps"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popEnterAnim="@anim/activity_open_enter"
+ app:popExitAnim="@anim/activity_close_exit"/>
+
+ <action
+ android:id="@+id/manage_to_auto_revoke"
+ app:destination="@id/auto_revoke"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popEnterAnim="@anim/activity_open_enter"
+ app:popExitAnim="@anim/activity_close_exit"/>
+
+ </fragment>
+
+ <fragment
+ android:id="@+id/manage_custom"
+ android:name="com.android.permissioncontroller.permission.ui.wear.WearManageCustomPermissionsFragment"
+ android:label="ManageCustom">
+
+ <action
+ android:id="@+id/manage_to_perm_apps"
+ app:destination="@id/permission_apps"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popExitAnim="@anim/activity_close_exit"
+ app:popEnterAnim="@anim/activity_open_enter"/>
+
+ </fragment>
+
+ <fragment
+ android:id="@+id/auto_revoke"
+ android:name="com.android.permissioncontroller.permission.ui.wear.WearUnusedAppsFragment"
+ android:label="AutoRevoke">
+
+ <action
+ android:id="@+id/auto_revoke_to_app_perms"
+ app:destination="@id/app_permission_groups"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popExitAnim="@anim/activity_close_exit"
+ app:popEnterAnim="@anim/activity_open_enter"/>
+
+ </fragment>
+
+ <fragment
+ android:id="@+id/app_permission_groups"
+ android:name="com.android.permissioncontroller.permission.ui.wear.WearAppPermissionGroupsFragment"
+ android:label="AppPermissionGroups">
+
+ <action
+ android:id="@+id/perm_groups_to_app"
+ app:destination="@id/app_permission"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popExitAnim="@anim/activity_close_exit"
+ app:popEnterAnim="@anim/activity_open_enter"/>
+
+ <action
+ android:id="@+id/perm_groups_to_all_perms"
+ app:destination="@id/all_app_permissions"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popExitAnim="@anim/activity_close_exit"
+ app:popEnterAnim="@anim/activity_open_enter"/>
+
+ <action
+ android:id="@+id/perm_groups_to_custom"
+ app:destination="@id/custom_app_permission_groups"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popExitAnim="@anim/activity_close_exit"
+ app:popEnterAnim="@anim/activity_open_enter"/>
+ </fragment>
+
+ <fragment
+ android:id="@+id/app_permission"
+ android:name="com.android.permissioncontroller.permission.ui.wear.WearAppPermissionFragment"
+ android:label="AppPermission" />
+
+ <fragment
+ android:id="@+id/permission_apps"
+ android:name="com.android.permissioncontroller.permission.ui.wear.WearPermissionAppsFragment"
+ android:label="PermissionApps">
+
+ <action
+ android:id="@+id/perm_apps_to_app"
+ app:destination="@id/app_permission"
+ app:enterAnim="@anim/activity_open_enter"
+ app:popExitAnim="@anim/activity_close_exit"
+ app:popEnterAnim="@anim/activity_open_enter"/>
+ </fragment>
+</navigation>
diff --git a/PermissionController/res/values-af-v33/strings.xml b/PermissionController/res/values-af-v33/strings.xml
index 2d81b6946..6d6a118cd 100644
--- a/PermissionController/res/values-af-v33/strings.xml
+++ b/PermissionController/res/values-af-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Meer waarskuwings"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Waarskuwings wat toegemaak is"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Vou uit om nog een waarskuwing te sien}other{Vou uit om nog # waarskuwings te sien}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Waarskuwing. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Handeling is voltooi"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Gaan instellings na wat jou toestel kan beskerm"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Kitsinstellings vir sekuriteit en privaatheid"</string>
diff --git a/PermissionController/res/values-af/strings.xml b/PermissionController/res/values-af/strings.xml
index ebd2dff4f..9c30aa738 100644
--- a/PermissionController/res/values-af/strings.xml
+++ b/PermissionController/res/values-af/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Meer inligting"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Laat alles toe"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Laat altyd alles toe"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Laat beperkte toegang toe"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Kies foto’ en video’s"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Kies meer"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Moenie meer kies nie"</string>
@@ -57,9 +58,10 @@
<string name="grant_dialog_button_allow_background" msgid="8236044729434367833">"Laat altyd toe"</string>
<string name="grant_dialog_button_allow_all_files" msgid="4955436994954829894">"Laat toe dat alle lêers bestuur word"</string>
<string name="grant_dialog_button_allow_media_only" msgid="4832877658422573832">"Laat toegang tot medialêers toe"</string>
- <string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Programme"</string>
+ <string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"Programtoestemmings"</string>
<string name="unused_apps" msgid="2058057455175955094">"Ongebruikte programme"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Redigeer geselekteerde foto’s vir hierdie app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Geen ongebruikte programme nie"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ongebruikte programme"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Onlangse toestemmingbesluite"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Laat altyd toe"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Laat net toe terwyl jy program gebruik"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Laat net toe terwyl jy app gebruik"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Moenie toelaat nie"</string>
<string name="loading" msgid="4789365003890741082">"Laai tans …"</string>
<string name="all_permissions" msgid="6911125611996872522">"Alle toestemmings"</string>
<string name="other_permissions" msgid="2901186127193849594">"Ander programvermoëns"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Toestemmingsversoek"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Installeer- en deïnstalleerhandelinge word nie in Wear gesteun nie."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Kies waartoe &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang mag kry"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; is opgedateer. Kies waartoe hierdie program toegang mag kry."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Kanselleer"</string>
@@ -187,7 +187,7 @@
<string name="app_permission_button_allow_all_files" msgid="1792232272599018825">"Laat toe dat alle lêers bestuur word"</string>
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Laat net toegang tot media toe"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Laat altyd toe"</string>
- <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Laat net toe terwyl jy program gebruik"</string>
+ <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Laat net toe terwyl jy app gebruik"</string>
<string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Laat altyd alles toe"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Vra elke keer"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Moenie toelaat nie"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Verwyder toestemmings as program nie gebruik word nie"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Verwyder toestemmings en maak spasie beskikbaar"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Onderbreek programaktiwiteit as ongebruik"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Bestuur app indien ongebruik"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Verwyder toestemmings, vee tydelike lêers uit, en stop kennisgewings"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Verwyder toestemmings, vee tydelike lêers uit, stop kennisgewings en argiveer die app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Om jou data te beskerm, sal toestemmings vir hierdie program verwyder word as die program \'n paar maande nie gebruik word nie."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Om jou data te beskerm, sal die volgende toestemmings verwyder word as dit vir \'n paar maande nie gebruik word nie: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Om jou data te beskerm, is toestemmings verwyder van programme wat jy \'n paar maande gelede laas gebruik het."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"<xliff:g id="DATE">%s</xliff:g> laas oopgemaak"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"As jy toelaat dat alle lêers bestuur word, kan hierdie program enige lêers in gedeelde bergingspasie op hierdie toestel en gekoppelde bergingtoestelle kry, wysig en uitvee. Die program kan toegang tot lêers kry sonder om jou te vra."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Laat hierdie program toe om lêers op die toestel en enige gekoppelde bergingtoestelle te kry, te wysig en uit te vee? Hierdie program kan toegang tot lêers kry sonder om jou te vra."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Programme met hierdie toestemming <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Apps met hierdie toestemming <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Programme met hierdie toestemming kan ingaan by fisieke aktiwiteit, soos stap, fietsry, ry, treëtelling, en meer"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Programme met hierdie toestemming kan toegang tot jou kalender kry"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Programme met hierdie toestemming kan foonoproeprekord lees en skryf"</string>
@@ -337,7 +339,7 @@
<string name="app_perms_content_provider_7d_all_files" msgid="7962416229708835558">"In afgelope 7 dae gebruik • Alle lêers"</string>
<string name="no_permissions_allowed" msgid="6081976856354669209">"Geen toestemmings toegelaat nie"</string>
<string name="no_permissions_denied" msgid="8159923922804043282">"Geen toestemmings geweier nie"</string>
- <string name="no_apps_allowed" msgid="7718822655254468631">"Geen programme toegelaat nie"</string>
+ <string name="no_apps_allowed" msgid="7718822655254468631">"Geen apps toegelaat nie"</string>
<string name="no_apps_allowed_full" msgid="8011716991498934104">"Geen programme het toestemming vir alle lêers nie"</string>
<string name="no_apps_allowed_scoped" msgid="4908850477787659501">"Geen programme het toestemming net vir media nie"</string>
<string name="no_apps_denied" msgid="7663435886986784743">"Geen programme geweier nie"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Notasapp"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps wat jou toelaat om notas op jou toestel te maak"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notas"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Huidige verstek"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Moenie weer vra nie"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Stel as verstek"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Wys assistent-aktiveringbespeuring"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Wys ikoon in statusbalk wanneer mikrofoon gebruik word om stemassistent te aktiveer"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou foto\'s en media op jou toestel?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot foto’s en media op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou kontakte?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou kontakte op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot hierdie toestel se ligging?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt; se ligging?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Die program sal net toegang tot die ligging hê terwyl jy die program gebruik"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot hierdie toestel se ligging?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> se ligging?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Hierdie program wil dalk die hele tyd toegang tot jou ligging hê, selfs wanneer jy nie die program gebruik nie. "<annotation id="link">"Laat toe in instellings."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Verander liggingtoegang vir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Verander liggingtoegang vir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Hierdie program wil die hele tyd toegang tot jou ligging hê, selfs wanneer jy nie die program gebruik nie. "<annotation id="link">"Laat toe in instellings."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om toestelle in die omtrek te soek, aan hulle te koppel en hul relatiewe posisie te bepaal?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestelle in die omtrek op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; soek, aan hulle koppel, en hul relatiewe posisie bepaal."</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om toestelle in die omtrek te soek, aan hulle te koppel en hul relatiewe posisie te bepaal? "<annotation id="link">"Laat toe in Instellings."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Verander <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> se liggingtoegang van benaderd na presies?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Verander <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> se liggingtoegang op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; van benaderd tot presies?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot hierdie toestel se benaderde ligging?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; se benaderde ligging?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Presies"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Benaderd"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou kalender?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou kalender op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om SMS\'e te stuur en te bekyk?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om SMS’e op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; te stuur en te bekyk?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Gee vir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot foto\'s, media en lêers op jou toestel?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot foto’s, media en lêers op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot &lt;b&gt;foto\'s, video\'s, musiek en oudio&lt;/b&gt; op hierdie toestel?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot &lt;b&gt;foto\'s, video\'s, musiek, oudio en ander lêers&lt;/b&gt; op hierdie toestel?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot musiek en oudio op hierdie toestel?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot musiek en oudio op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot foto\'s en video\'s op hierdie toestel?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot foto’s en video’s op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot meer foto\'s en video\'s op hierdie toestel?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot meer foto’s en video’s op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om oudio op te neem?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om oudio op te neem op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Die program sal net kan oudio opneem terwyl jy die program gebruik"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om oudio op te neem?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om oudio op te neem op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Hierdie program wil dalk die hele tyd oudio opneem, selfs wanneer jy nie die program gebruik nie. "<annotation id="link">"Laat toe in instellings."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Verander mikrofoontoegang vir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Verander mikrofoontoegang vir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Hierdie program wil die hele tyd oudio opneem, selfs wanneer jy nie die program gebruik nie. "<annotation id="link">"Laat toe in instellings."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou fisieke aktiwiteit?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou fisieke aktiwiteit op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om foto\'s te neem en video\'s op te neem?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om foto’s te neem en video’s op te neem op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Die program sal net kan foto\'s neem en video\'s opneem terwyl jy die program gebruik"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om foto\'s te neem en video\'s op te neem?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om foto’s te neem en video’s op te neem op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Hierdie program wil dalk die hele tyd foto\'s neem en video\'s opneem, selfs wanneer jy nie die program gebruik nie. "<annotation id="link">"Laat toe in instellings."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Verander kameratoegang vir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Verander kameratoegang vir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Hierdie program wil die hele tyd foto\'s neem en video\'s opneem, selfs wanneer jy nie die program gebruik nie. "<annotation id="link">"Laat toe in instellings."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou foonoproeprekords?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot jou foonoproeprekords op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om foonoproepe te maak en te bestuur?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om foonoproepe op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; te maak en te bestuur?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot sensordata oor jou lewenstekens?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot sensordata oor jou lewenstekens op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Dié program wil dalk deurentyd toegang tot sensordata oor jou lewenstekens hê, selfs wanneer jy nie die program gebruik nie. "<annotation id="link">"Gaan na instellings"</annotation>" om hierdie verandering te maak."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot die sensordata oor jou lewenstekens?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot die sensordata oor jou lewenstekens op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501"><annotation id="link">"Gaan na instellings"</annotation>" om altyd vir hierdie program toegang tot liggaamsensordata te gee, selfs wanneer jy nie die program gebruik nie."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; steeds toegang tot liggaamsensordata terwyl die program gebruik word?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Gee &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; steeds toegang tot liggaamsensordata op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; terwyl die app gebruik word?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om vir jou kennisgewings te stuur?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Laat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toe om vir jou kennisgewings op jou &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; te stuur?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Beheerde toestemmings"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> het liggingtoegang"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Jou organisasie gee <xliff:g id="APP_NAME">%1$s</xliff:g> toegang tot jou ligging"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Ander toestemmings"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Toestemming wat deur die stelsel gebruik word"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Toestemmings wat net deur die stelselprogramme gebruik word."</string>
@@ -574,23 +611,24 @@
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Hierdie program steun nie die jongste weergawe van Android nie. As hierdie program nie toegang tot musiek- en oudiolêers het nie, sal dit ook nie toegelaat word om toegang tot foto\'s en video\'s te kry nie."</string>
<string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Gaan program met agtergrondliggingtoegang na"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> het altyd toegang tot jou ligging, selfs wanneer die program toe is"</string>
- <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Gaan program met agtergrondliggingtoegang na"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Gaan app met agtergrondliggingtoegang na"</string>
<string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Hierdie app het altyd toegang tot jou ligging, selfs wanneer dit toe is.\n\nSekere veiligheid- en noodapps moet op die agtergrond toegang tot jou ligging hê om te kan werk soos hulle moet."</string>
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Toegang is verander"</string>
<string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Sien onlangse ligginggebruik"</string>
<string name="privacy_controls_title" msgid="7605929972256835199">"Privaatheidkontroles"</string>
<string name="camera_toggle_title" msgid="1251201397431837666">"Kameratoegang"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofoontoegang"</string>
- <string name="perm_toggle_description" msgid="7801326363741451379">"Vir programme en dienste"</string>
- <string name="mic_toggle_description" msgid="9163104307990677157">"Vir programme en dienste. As hierdie instelling af is, kan mikrofoondata steeds gedeel word wanneer jy ’n noodnommer bel."</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Vir apps en dienste"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Vir apps en dienste. As hierdie instelling af is, kan mikrofoondata steeds gedeel word wanneer jy ’n noodnommer bel."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Sien programme en dienste met toegang tot ligging"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Wys knipbordtoegang"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Wys ’n boodskap wanneer programme toegang het tot teks, prente of ander inhoud wat jy gekopieer het"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Wys ’n boodskap wanneer apps toegang het tot teks, prente of ander inhoud wat jy gekopieer het"</string>
<string name="show_password_title" msgid="2877269286984684659">"Wys wagwoorde"</string>
<string name="show_password_summary" msgid="1110166488865981610">"Wys karakters kortliks terwyl jy tik"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Hierdie app het verklaar dat dit dalk liggingdata met derde party sal deel"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Datadeling en -ligging"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Waar datadelinginligting vandaan kom"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Die ontwikkelaar het inligting aan hierdie toestel se vervaardiger verskaf oor hoe hierdie app data deel. Die ontwikkelaar kan hierdie inligting mettertyd opdateer."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Die ontwikkelaar het inligting aan "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" verskaf oor hoe hierdie app data deel. Die ontwikkelaar kan hierdie inligting mettertyd opdateer."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Hierdie app kan liggingdata deel vir:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datadeling verskil"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Dataveiligheid"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Liggingdata sal dalk gedeel word"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Hierdie app het verklaar dat dit jou liggingdata met derde partye kan deel"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Kan nie hierdie skakel oopmaak nie"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Datadelingopdaterings vir ligging"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Gaan apps na wat die manier waarop hulle jou liggingdata kan deel, verander het"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Hierdie apps het die manier waarop hulle jou liggingdata kan deel, verander. Hulle het dit dalk nie voorheen gedeel nie, of kan dit nou vir reklame- of bemarkingdoeleindes deel."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Datadelingopdaterings"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Sommige apps het die manier waarop hulle jou liggingdata kan deel, verander"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Instellings"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Ingegaan <xliff:g id="TIME_DATE">%1$s</xliff:g>."</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Gister ingegaan <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Ingegaan <xliff:g id="TIME_DATE_0">%1$s</xliff:g><xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-am-v33/strings.xml b/PermissionController/res/values-am-v33/strings.xml
index 2967c04e8..e2a599a3c 100644
--- a/PermissionController/res/values-am-v33/strings.xml
+++ b/PermissionController/res/values-am-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"ተጨማሪ ማንቂያዎች"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"የተሰናበቱ ማንቂያዎች"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{ይዘርጉ እና አንድ ተጨማሪ ማንቂያ ይመልከቱ}one{ይዘርጉ እና # ተጨማሪ ማንቂያ ይመልከቱ}other{ይዘርጉ እና # ተጨማሪ ማንቂያዎችን ይመልከቱ}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"ማንቂያ። <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"እርምጃ ተጠናቅቋል"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"የእርስዎ መሣሪያ ላይ ጥበቃ ማከል የሚችሉ ቅንብሮችን ይፈትሹ"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"የደህንነት እና የግላዊነት ፈጣን ቅንብሮች"</string>
diff --git a/PermissionController/res/values-am/strings.xml b/PermissionController/res/values-am/strings.xml
index cd025e5f8..beb83a4e2 100644
--- a/PermissionController/res/values-am/strings.xml
+++ b/PermissionController/res/values-am/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"ተጨማሪ መረጃ"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"ሁሉንም ፍቀድ"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"ሁልጊዜ ሁሉንም ፍቀድ"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"የተገደበ መዳረሻ ፍቀድ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ፎቶዎችን እና ቪድዮዎችን ምረጥ"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"ተጨማሪ ምረጥ"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ተጨማሪ አትምረጥ"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"መተግበሪያዎች"</string>
<string name="app_permissions" msgid="3369917736607944781">"የመተግበሪያ ፈቃዶች"</string>
<string name="unused_apps" msgid="2058057455175955094">"ጥቅም ላይ ያልዋሉ መተግበሪያዎች"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ለዚህ መተግበሪያ የተመረጡ ፎቶዎችን ያርትዑ"</string>
<string name="no_unused_apps" msgid="12809387670415295">"አገልግሎት ላይ ያልዋሉ መተግበሪያዎች የሉም"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ሥራ ላይ ያልዋሉ መተግበሪያዎች"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"የቅርብ ጊዜ የፈቃድ ውሳኔዎች"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"ሁሉም ፍቃዶች"</string>
<string name="other_permissions" msgid="2901186127193849594">"ሌሎች የመተግበሪያ ችሎታዎች"</string>
<string name="permission_request_title" msgid="8790310151025020126">"የፍቃድ ጥያቄ"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"በWear ላይ የመጫን/ማራገፍ እርምጃዎች አይደገፉም።"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ምን መድረስ እንደሚችል ይምረጡ"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ተዘምኗል። ይህ መተግበሪያ ምን መድረስ እንደሚችል ይምረጡ።"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"ይቅር"</string>
@@ -161,9 +161,9 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"ባለፈው 1 ሰዓት የፈቃድ አጠቃቀም"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"ባለፉት 15 ደቂቃዎች ውስጥ የፈቃድ አጠቃቀም"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"ባለፈው 1 ደቂቃ የፈቃድ አጠቃቀም"</string>
- <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{ባለፈው # ቀን ውስጥ ስራ ላይ አልዋለም}one{ባለፈው # ቀን ውስጥ ስራ ላይ አልዋለም}other{ባለፉት # ቀናት ውስጥ ስራ ላይ አልዋለም}}"</string>
- <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{ባለፈው # ሰዓት ውስጥ ስራ ላይ አልዋለም}one{ባለፈው # ሰዓት ውስጥ ስራ ላይ አልዋለም}other{ባለፉት # ሰዓታት ውስጥ ስራ ላይ አልዋለም}}"</string>
- <string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{በ1 መተግበሪያ ስራ ላይ ውሏል}one{በ# መተግበሪያዎች ስራ ላይ ውለዋል}other{በ# መተግበሪያዎች ስራ ላይ ውለዋል}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{ባለፈው # ቀን ውስጥ ሥራ ላይ አልዋለም}one{ባለፈው # ቀን ውስጥ ሥራ ላይ አልዋለም}other{ባለፉት # ቀናት ውስጥ ሥራ ላይ አልዋለም}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{ባለፈው # ሰዓት ውስጥ ሥራ ላይ አልዋለም}one{ባለፈው # ሰዓት ውስጥ ሥራ ላይ አልዋለም}other{ባለፉት # ሰዓታት ውስጥ ሥራ ላይ አልዋለም}}"</string>
+ <string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{በ1 መተግበሪያ ሥራ ላይ ውሏል}one{በ# መተግበሪያዎች ሥራ ላይ ውለዋል}other{በ# መተግበሪያዎች ሥራ ላይ ውለዋል}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"ሁሉንም በዳሽ ቦርድ ውስጥ ይመልከቱ"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"የተጣራው በ፦ <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_usage_remove_filter" msgid="2926157607436428207">"ማጣሪያን አስወግድ"</string>
@@ -200,11 +200,13 @@
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"ሁሉንም <xliff:g id="APP">%1$s</xliff:g> ፈቃዶች ይመልከቱ"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"ከዚህ መተግበሪያ ጋር ሁሉንም መተግበሪያዎች ይመልከቱ"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"የረዳት ማይክሮፎን አጠቃቀምን አሳይ"</string>
- <string name="unused_apps_category_title" msgid="2988455616845243901">"ስራ ላይ ያልዋሉ የመተግበሪያ ቅንብሮች"</string>
+ <string name="unused_apps_category_title" msgid="2988455616845243901">"ሥራ ላይ ያልዋሉ የመተግበሪያ ቅንብሮች"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"መተግበሪያ ጥቅም ላይ ካልዋለ ፈቃዶችን አስወግድ"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"ፈቃዶችን ያስወግዱ እና ቦታ ያስለቅቁ"</string>
- <string name="unused_apps_label_v2" msgid="7058776770056517980">"የመተግበሪያ እንቅስቃሴ ስራ ላይ ካልዋለ ባለበት አቁም"</string>
+ <string name="unused_apps_label_v2" msgid="7058776770056517980">"የመተግበሪያ እንቅስቃሴ ሥራ ላይ ካልዋለ ባለበት አቁም"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ጥቅም ላይ ካልዋለ መተግበሪያን ያስተዳድሩ"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ፈቃዶችን አስወግድ፣ ጊዜያዊ ፋይሎችን ሰርዝ እና ማሳወቂያዎችን አቁም"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ፈቃዶችን ያስወግዱ፣ ጊዜያዊ ፋይሎችን ይሰርዙ፣ ማሳወቂያዎችን ያቁሙ እና መተግበሪያውን በማህደር ያስቀምጡ"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"ለእርስዎ ውሂብ ጥበቃ ለማድረግ፣ ለዚህ መተግበሪያ የተሰጡ ፈቃዶች መተግበሪያው ለጥቂት ወራት ጥቅም ላይ ካልዋለ ይህ መተግበሪያ ይወገዳል።"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"የእርስዎን ውሂብ ለመጠበቅ፣ መተግበሪያው ለጥቂት ወራት ጥቅም ላይ ካልዋለ፣ የሚከተሉት ፈቃዶች ይወገዳሉ፦ <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"የእርስዎን ውሂብ ለመጠበቅ ሲባል ለጥቂት ወራት ካልተጠቀሙባቸው መተግበሪያዎች ላይ ፈቃዶች ተወግደዋል።"</string>
@@ -218,8 +220,8 @@
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"የ<xliff:g id="PERMISSION_NAME">%s</xliff:g> ፈቃድ ተወግዷል"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"የ<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> እና <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> ፈቃዶች ተወግደዋል"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> እና <xliff:g id="NUMBER">%2$s</xliff:g> ሌሎች ፈቃዶች ተወግደዋል"</string>
- <string name="unused_apps_page_title" msgid="6986983535677572559">"ስራ ላይ ያልዋሉ መተግበሪያዎች"</string>
- <string name="unused_apps_page_summary" msgid="1867593913217272155">"አንድ መተግበሪያ ለጥቂት ወራት ስራ ላይ ካልዋለ፦\n\n• ውሂብዎን ለመጠበቅ ፈቃዶች ይወገዳሉ\n• ባትሪን ለመቆጠብ ማሳወቂያዎች ይቆማሉ\n• ባዶ ቦታ ለማስለቀቅ ጊዜያዊ ፋይሎች ይወገዳሉ\n\nፈቃዶችን እና ማሳወቂያዎችን እንደገና ለመፍቀድ መተግበሪያውን ይክፈቱት።"</string>
+ <string name="unused_apps_page_title" msgid="6986983535677572559">"ሥራ ላይ ያልዋሉ መተግበሪያዎች"</string>
+ <string name="unused_apps_page_summary" msgid="1867593913217272155">"አንድ መተግበሪያ ለጥቂት ወራት ሥራ ላይ ካልዋለ፦\n\n• ውሂብዎን ለመጠበቅ ፈቃዶች ይወገዳሉ\n• ባትሪን ለመቆጠብ ማሳወቂያዎች ይቆማሉ\n• ባዶ ቦታ ለማስለቀቅ ጊዜያዊ ፋይሎች ይወገዳሉ\n\nፈቃዶችን እና ማሳወቂያዎችን እንደገና ለመፍቀድ መተግበሪያውን ይክፈቱት።"</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"መተግበሪያ ለአንድ ወር ጥቅም ላይ ካልዋለ፦\n\n• ውሂብዎን ለመጠበቅ ፈቃዶች ይወገዳሉ\n• ጊዜያዊ ፋይሎች ቦታ ለማስለቀቅ ይወገዳሉ\n\nፈቃዶችን ዳግም ለመፍቀድ መተግበሪያውን ይክፈቱ።"</string>
<string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{መጨረሻ የተከፈተው ከ# ወር በፊት}one{መጨረሻ የተከፈተው ከ# ወር በፊት}other{መጨረሻ የተከፈተው ከ# ወራት በፊት}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"መተግበሪያ ለመጨረሻ ጊዜ በ<xliff:g id="DATE">%s</xliff:g> ላይ ተከፍቷል"</string>
@@ -247,7 +249,7 @@
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"ተከልክሏል / በጭራሽ አልተደረሰበትም"</string>
<string name="allowed_header" msgid="7769277978004790414">"ይፈቀዳል"</string>
<string name="allowed_always_header" msgid="6455903312589013545">"ሁልጊዜ የተፈቀደ"</string>
- <string name="allowed_foreground_header" msgid="6845655788447833353">"ስራ ላይ ሲውል ብቻ የሚፈቀድ"</string>
+ <string name="allowed_foreground_header" msgid="6845655788447833353">"ሥራ ላይ ሲውል ብቻ የሚፈቀድ"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"ለሚዲያ ብቻ መዳረሻ ተፈቅዷል"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"ሁሉንም ፋይሎች ማስተዳደር ተፈቀዷል"</string>
<string name="ask_header" msgid="2633816846459944376">"ሁልጊዜ ጠይቅ"</string>
@@ -262,8 +264,8 @@
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> ጥቅም ላይ ያልዋሉ መተግበሪያዎች"</string>
<string name="auto_revoke_permission_reminder_notification_content" msgid="4492228990462107487">"ፈቃዶች የእርስዎን ግላዊነት ለመጠበቅ ተወግደዋል። ለመገምገም መታ ያድርጉ"</string>
<string name="auto_revoke_permission_notification_title" msgid="2629844160853454657">"ጥቅም ላይ ላልዋሉ መተግበሪያዎች ፈቃዶች ተወግደዋል"</string>
- <string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"አንዳንድ መተግበሪያዎች ለጥቂት ወሮች ስራ ላይ አልዋሉም። ለመገምገም መታ ያድርጉ።"</string>
- <string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ስራ ላይ ያልዋለ መተግበሪያ}one{# ስራ ላይ ያልዋሉ መተግበሪያዎች}other{# ስራ ላይ ያልዋሉ መተግበሪያዎች}}"</string>
+ <string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"አንዳንድ መተግበሪያዎች ለጥቂት ወሮች ሥራ ላይ አልዋሉም። ለመገምገም መታ ያድርጉ።"</string>
+ <string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ሥራ ላይ ያልዋለ መተግበሪያ}one{# ሥራ ላይ ያልዋሉ መተግበሪያዎች}other{# ሥራ ላይ ያልዋሉ መተግበሪያዎች}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"ፈቃዶች እና ጊዜያዊ ፋይሎች ተወግደዋል እንዲሁም ማሳወቂያዎች ቆመዋል። ለመገምገም መታ ያድርጉ።"</string>
<string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"ፈቃዶቻቸው የተወገዱባቸው መተግበሪያዎችን ይገምግሙ"</string>
<string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"ለሆነ ያህል ጊዜ ላልተጠቀሙባቸው መተግበሪያዎች ፈቃዶች እና ጊዜያዊ ፋይሎች ተወግደዋል እና ማሳወቂያዎች ቆመዋል።"</string>
@@ -274,7 +276,7 @@
<string name="post_drive_permission_decision_reminder_summary_1_app_multi_permission" msgid="4080701771111456927">"እየነዱ ሳለ <xliff:g id="COUNT">%1$d</xliff:g> ፈቃዶችን ለ<xliff:g id="APP">%2$s</xliff:g> ሰጥተዋል"</string>
<string name="post_drive_permission_decision_reminder_summary_multi_apps" msgid="5253882771252863902">"{count,plural, =1{እየነዱ ሳለ የ<xliff:g id="APP_0">%1$s</xliff:g> &amp; # ሌላ መተግበሪያ መዳረሻ ሰጥተዋል}one{እየነዱ ሳለ የ<xliff:g id="APP_1">%1$s</xliff:g> &amp; # ሌላ መተግበሪያ መዳረሻ ሰጥተዋል}other{እየነዱ ሳለ የ<xliff:g id="APP_1">%1$s</xliff:g> &amp; # ሌላ መተግበሪያ መዳረሻ ሰጥተዋል}}"</string>
<string name="go_to_settings" msgid="1053735612211228335">"ወደ ቅንብሮች ሂድ"</string>
- <string name="auto_revoke_setting_subtitle" msgid="8631720570723050460">"አንዳንድ መተግበሪያዎች ለጥቂት ወሮች ስራ ላይ አልዋሉም።"</string>
+ <string name="auto_revoke_setting_subtitle" msgid="8631720570723050460">"አንዳንድ መተግበሪያዎች ለጥቂት ወሮች ሥራ ላይ አልዋሉም።"</string>
<string name="permissions_removed_category_title" msgid="1064754271178447643">"ፈቃዶች የተወገዱባቸው"</string>
<string name="permission_removed_page_title" msgid="2627436155091001209">"ፈቃዶች የተወገዱባቸው"</string>
<string name="all_unused_apps_category_title" msgid="755663524704745414">"ሁሉም ጥቅም ላይ ያልዋሉ መተግበሪያዎች"</string>
@@ -289,8 +291,8 @@
<string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"ተጨማሪ አማራጮችን ይመልከቱ"</string>
<string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"መዳረሻ ተወግዷል"</string>
<string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"ሙሉ የመሣሪያ መዳረሻ ያለውን መተግበሪያ ይገምግሙ"</string>
- <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> የእርስዎን ማያ ገጽ ማየት እና በመሣሪያዎ ላይ እርምጃዎችን መውሰድ ይችላል። የተደራሽነት መተግበሪያዎች እንደታሰቡት እንዲሰሩ እንደዚህ አይነት መዳረሻ ያስፈልጋቸዋል።"</string>
- <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"ይህ መተግበሪያ ማያ ገጽዎን ማየት እና በመሣሪያዎ ላይ እርምጃዎችን ማከናወን ይችላል። የተደራሽነት መተግበሪያዎች እንደታሰቡት እንዲሰሩ እንደዚህ አይነት መዳረሻ ያስፈልጋቸዋል፣ ነገር ግን መተግበሪያውን ይፈትሹት እና እንደሚያምኑት ያረጋግጡ።"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> የእርስዎን ማያ ገፅ ማየት እና በመሣሪያዎ ላይ እርምጃዎችን መውሰድ ይችላል። የተደራሽነት መተግበሪያዎች እንደታሰቡት እንዲሰሩ እንደዚህ ዓይነት መዳረሻ ያስፈልጋቸዋል።"</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"ይህ መተግበሪያ ማያ ገጽዎን ማየት እና በመሣሪያዎ ላይ እርምጃዎችን ማከናወን ይችላል። የተደራሽነት መተግበሪያዎች እንደታሰቡት እንዲሰሩ እንደዚህ ዓይነት መዳረሻ ያስፈልጋቸዋል፣ ነገር ግን መተግበሪያውን ይፈትሹት እና እንደሚያምኑት ያረጋግጡ።"</string>
<string name="accessibility_remove_access_button_label" msgid="44145801526711640">"መዳረሻን አስወግድ"</string>
<string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"ሙሉ መዳረሻ ያላቸውን መተግበሪያዎች ይመልከቱ"</string>
<string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"መዳረሻ ተወግዷል"</string>
@@ -345,11 +347,11 @@
<string name="settings" msgid="5409109923158713323">"ቅንብሮች"</string>
<string name="accessibility_service_dialog_title_single" msgid="7956432823014102366">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ወደ የእርስዎ መሣሪያ ሙሉ መዳረሻ አለው"</string>
<string name="accessibility_service_dialog_title_multiple" msgid="5527879210683548175">"<xliff:g id="NUM_SERVICES">%s</xliff:g> ተደራሽነት መተግበሪያዎች ወደ የእርስዎ መሣሪያ ሙሉ መዳረሻ አላቸው"</string>
- <string name="accessibility_service_dialog_bottom_text_single" msgid="1128666197822205958">"<xliff:g id="SERVICE_NAME">%s</xliff:g> የእርስዎን ማያ ገጽ፣ እርምጃዎች እና ግቤቶች መመልከት፣ እርምጃዎችን መውሰድ እና ማሳያን መቆጣጠር ይችላል።"</string>
- <string name="accessibility_service_dialog_bottom_text_multiple" msgid="7009848932395519852">"እነዚህ መተግበሪያዎች የእርስዎን ማያ ገጽ፣ እርምጃዎች እና ግቤቶች መመልከት፣ እርምጃዎችን መውሰድ እና ማሳያን መቆጣጠር ይችላሉ።"</string>
+ <string name="accessibility_service_dialog_bottom_text_single" msgid="1128666197822205958">"<xliff:g id="SERVICE_NAME">%s</xliff:g> የእርስዎን ማያ ገፅ፣ እርምጃዎች እና ግቤቶች መመልከት፣ እርምጃዎችን መውሰድ እና ማሳያን መቆጣጠር ይችላል።"</string>
+ <string name="accessibility_service_dialog_bottom_text_multiple" msgid="7009848932395519852">"እነዚህ መተግበሪያዎች የእርስዎን ማያ ገፅ፣ እርምጃዎች እና ግቤቶች መመልከት፣ እርምጃዎችን መውሰድ እና ማሳያን መቆጣጠር ይችላሉ።"</string>
<string name="role_assistant_label" msgid="4727586018198208128">"ነባሪ የዲጂታል ረዳት መተግበሪያ"</string>
<string name="role_assistant_short_label" msgid="3369003713187703399">"የዲጂታል ረዳት መተግበሪያ"</string>
- <string name="role_assistant_description" msgid="6622458130459922952">"ረዳት መተግበሪያዎች በሚያዩት ማያ ገጽ ላይ ባለ መረጃ ላይ ተመስርቶ ሊያግዘዎት ይችላል። አንዳንድ መተግበሪያዎች የተዋሃደ እርዳታ ለእርስዎ ለመስጠት ሁለቱንም ማስጀመሪያ እና የድምፅ ግቤት አገልግሎቶችን ይደግፋሉ።"</string>
+ <string name="role_assistant_description" msgid="6622458130459922952">"ረዳት መተግበሪያዎች በሚያዩት ማያ ገፅ ላይ ባለ መረጃ ላይ ተመስርቶ ሊያግዘዎት ይችላል። አንዳንድ መተግበሪያዎች የተዋሃደ እርዳታ ለእርስዎ ለመስጠት ሁለቱንም ማስጀመሪያ እና የድምፅ ግቤት አገልግሎቶችን ይደግፋሉ።"</string>
<string name="role_browser_label" msgid="2877796144554070207">"ነባሪ አሳሽ መተግበሪያ"</string>
<string name="role_browser_short_label" msgid="6745009127123292296">"የአሳሽ መተግበሪያ"</string>
<string name="role_browser_description" msgid="3465253637499842671">"ወደ በየነ መረብ ለእርስዎ መዳረሻ የሚሰጥዎትን እና እርስዎ መታ የሚያደርጓቸውን አገናኞች የሚያሳዩ መተግበሪያዎች"</string>
@@ -401,12 +403,22 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"የማስታወሻዎች መተግበሪያ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"በመሣሪያዎ ላይ ማስታወሻ እንዲይዙ የሚያስችሉዎት መተግበሪያዎች"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ማስታወሻዎች"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"አሁን ያለ ነባሪ"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"ዳግም አትጠይቅ"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"እንደ ነባሪ አዘጋጅ"</string>
- <string name="phone_call_uses_microphone" msgid="233569591461187177">"ማይክሮፎን በ&lt;b&gt;ስልክ ጥሪ&lt;/b&gt; ላይ ስራ ላይ ውሏል"</string>
- <string name="phone_call_uses_microphone_and_camera" msgid="6291898755681748189">"ካሜራ እና ማይክሮፎን በ&lt;b&gt;ቪዲዮ ጥሪ&lt;/b&gt; ላይ ስራ ላይ ውለዋል"</string>
- <string name="phone_call_uses_camera" msgid="2048417022147857418">"ካሜራ በ&lt;b&gt;ቪዲዮ ጥሪ&lt;/b&gt; ላይ ስራ ላይ ውሏል"</string>
+ <string name="phone_call_uses_microphone" msgid="233569591461187177">"ማይክሮፎን በ&lt;b&gt;ስልክ ጥሪ&lt;/b&gt; ላይ ሥራ ላይ ውሏል"</string>
+ <string name="phone_call_uses_microphone_and_camera" msgid="6291898755681748189">"ካሜራ እና ማይክሮፎን በ&lt;b&gt;ቪዲዮ ጥሪ&lt;/b&gt; ላይ ሥራ ላይ ውለዋል"</string>
+ <string name="phone_call_uses_camera" msgid="2048417022147857418">"ካሜራ በ&lt;b&gt;ቪዲዮ ጥሪ&lt;/b&gt; ላይ ሥራ ላይ ውሏል"</string>
<string name="system_uses_microphone" msgid="576672130318877143">"ማይክሮፎን የሥርዓት አገልግሎትን በመጠቀም ተደርሶበታል"</string>
<string name="system_uses_microphone_and_camera" msgid="5124478304275138804">"ካሜራ እና ማይክሮፎን የሥርዓት አገልግሎትን በመጠቀም ተደርሶበታል"</string>
<string name="system_uses_camera" msgid="1911223105234441470">"ካሜራ የሥርዓት አገልግሎትን በመጠቀም ተደርሶበታል"</string>
@@ -436,8 +448,8 @@
<string name="no_special_app_access" msgid="6950277571805106247">"ምንም ልዩ መተግበሪያ መዳረሻ"</string>
<string name="special_app_access_no_apps" msgid="4102911722787886970">"መተግበሪያዎች የሉም"</string>
<string name="home_missing_work_profile_support" msgid="1756855847669387977">"የሥራ መገለጫን አይደግፍም"</string>
- <string name="encryption_unaware_confirmation_message" msgid="8274491794636402484">"ማስታወሻ፦ የእርስዎን መሣሪያ ዳግም ካስጀምሩ እና ማያ ገጽ መቆለፊያው እንዲቀናበር ካደረጉ፣ ይህ መተግበሪያ የእርስዎን መሣሪያ ዳግም እስከሚከፍቱ ድረስ መጀመር አይችልም።"</string>
- <string name="assistant_confirmation_message" msgid="7476540402884416212">"ረዳቱ በእርስዎ ስርዓት ላይ በአገልግሎት ላይ ስለሚውሉ መተግበሪያዎች መረጃን ማንበብ ይችላል፣ ይህም በእርስዎ ማያ ገጽ ላይ የሚታይ ወይም በመተግበሪያዎች ውስጥ የሚደረስበት መረጃን ይጨምራል።"</string>
+ <string name="encryption_unaware_confirmation_message" msgid="8274491794636402484">"ማስታወሻ፦ የእርስዎን መሣሪያ ዳግም ካስጀምሩ እና ማያ ገፅ መቆለፊያው እንዲቀናበር ካደረጉ፣ ይህ መተግበሪያ የእርስዎን መሣሪያ ዳግም እስከሚከፍቱ ድረስ መጀመር አይችልም።"</string>
+ <string name="assistant_confirmation_message" msgid="7476540402884416212">"ረዳቱ በእርስዎ ስርዓት ላይ በአገልግሎት ላይ ስለሚውሉ መተግበሪያዎች መረጃን ማንበብ ይችላል፣ ይህም በእርስዎ ማያ ገፅ ላይ የሚታይ ወይም በመተግበሪያዎች ውስጥ የሚደረስበት መረጃን ይጨምራል።"</string>
<string name="incident_report_channel_name" msgid="3144954065936288440">"ሳንካ ማረሚያ ውሂብን አጋራ"</string>
<string name="incident_report_notification_title" msgid="4635984625656519773">"ዝርዝር የሳንካ ማረሚያ መረጃ ይጋራ?"</string>
<string name="incident_report_notification_text" msgid="3376480583513587923">"<xliff:g id="APP_NAME">%1$s</xliff:g> የሳንካ ማረሚያ መረጃን መስቀል ይፈልጋል።"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"የረዳት ቀስቃሽ ማግኛን አሳይ"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"የድምፅ ረዳትን ለማግበር ማይክራፎን ጥቅም ላይ ሲውል በሁናቴ አሞሌ ውስጥ አዶን አሳይ"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በመሣሪያዎ ላይ ያሉ ፎቶዎችን፣ እና ማህደረ መረጃን እንዲደርስ ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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> አካባቢ እንዲደርስ ይፈቀድለት?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ይህ መተግበሪያ አካባቢዎን ሁልጊዜ መድረስ ሊፈልግ ይችላል፣ እርስዎ በማይጠቀሙበት ጊዜም እንኳ። "<annotation id="link">"በቅንብሮች ውስጥ ይፍቀዱ"</annotation>"።"</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"ለ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የመገኛ አካባቢ መዳረሻ ይለወጥ?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"ይህ መተግበሪያ አካባቢዎን ሁልጊዜ መድረስ ይፈልጋል፣ እርስዎ በማይጠቀሙበት ጊዜም እንኳ። "<annotation id="link">"በቅንብሮች ውስጥ ይፍቀዱ"</annotation>"።"</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በአቅራቢያ ያሉ የመሣሪያዎች አንጻራዊ አቀማመጥን እንዲፈልግ፣ እንዲገናኝ እና እንዲወስን ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ በአቅራቢያ ያሉ መሣሪያዎችን አንጻራዊ አካባቢ ለመፈለግ፣ ለመገናኘት እና ለመወሰን ይፈቀድለት?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በአቅራቢያ ያሉ የመሣሪያዎች አንጻራዊ አቀማመጥን እንዲፈልግ፣ እንዲገናኝ እና እንዲወስን ይፈቀድለት? "<annotation id="link">"በቅንብሮች ውስጥ ይፍቀዱ።"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"የ<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> አካባቢ መዳረሻ ከግምታዊ ወደ ትክክለኛ ይቀየር?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"የ<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> የአካባቢ መዳረሻ በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የእርስዎን የ&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;’s ግምታዊ አካባቢ እንዲደርስ ይፈቀድለት?"</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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%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; የኤስኤምኤስ መልዕክቶችን እንዲልክ እና እንዲመለከት ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ፎቶዎችን፣ ሚዲያን እና ፋይሎችን እንዲደርስ ይፈቀድለት?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በመሣሪያዎ ላይ ያሉ &lt;b&gt;ፎቶዎችን፣ ቪዲዮዎችን፣ ሙዚቃን እና ኦዲዮን&lt;/b&gt; እንዲደርስ ይፈቀድለት?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በመሣሪያዎ ላይ ያሉ &lt;b&gt;ፎቶዎችን፣ ቪዲዮዎችን፣ ሙዚቃን፣ ኦዲዮን፣ ቪዲዮዎችን እና ሌሎች ፋይሎችን&lt;/b&gt; ዘንድ እንዲደርስ ይፈቀድለት?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በዚህ መሣሪያ ላይ ያለ ሙዚቃን እና ሌሎች የኦዲዮ ፋይሎችን እንዲደርስ ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ሙዚቃን እና ኦዲዮን እንዲደርስ ይፈቀድለት?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በዚህ መሣሪያ ላይ ያሉ ፎቶዎችን እና ቪዲዮዎችን እንዲደርስ ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ፎቶዎችን እና ቪድዮዎችን እንዲደርስ ይፈቀድለት?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በዚህ መሣሪያ ላይ ያሉ ፎቶዎችን እና ቪድዮዎችን እንዲደርስ ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ተጨማሪ ፎቶዎችን እና ቪድዮዎችን እንዲደርስ ይፈቀድለት?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ኦዲዮን እንዲቀዳ ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ኦዲዮ እንዲቀዳ ይፈቀድለት?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"መተግበሪያው ኦዲዮን መቅዳት የሚችለው መተግበሪያውን እርስዎ ሲጠቀሙበት ብቻ ነው"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ኦዲዮን እንዲቀዳ ይፈቀድለት?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ኦዲዮ እንዲቀዳ ይፈቀድለት?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ይህ መተግበሪያ መተግበሪያውን በማይጠቀሙበት ጊዜም እንኳ ሁልጊዜ ኦዲዮ መቅዳት ሊፈልግ ይችላል። "<annotation id="link">"በቅንብሮች ውስጥ ይፍቀዱ።"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"ለ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የማይክራፎን መዳረሻ ይለወጥ?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"ይህ መተግበሪያ መተግበሪያውን በማይጠቀሙበት ጊዜም እንኳ ሁልጊዜ ኦዲዮ መቅዳት ይፈልጋል። "<annotation id="link">"በቅንብሮች ውስጥ ይፍቀዱ።"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የእርስዎን አካላዊ እንቅስቃሴ እንዲደርስበት ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ አካላዊ እንቅስቃሴዎን እንዲደርስ ይፈቀድለት?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ስዕሎችን እንዲያነሳ እና ቪዲዮን እንዲቀርጽ ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;? ላይ ሥዕሎችን እንዲያነሳ እና ቪድዮ እንዲቀርጽ ይፈቀድለት?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"መተግበሪያው ስዕሎችን ማንሳት እና ቪዲዮውን መቅዳት የሚችለው መተግበሪያውን እርስዎ ሲጠቀሙበት ብቻ ነው"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ስዕሎችን እንዲያነሳ እና ቪዲዮን እንዲቀርጽ ይፈቀድለት?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;? ላይ ሥዕሎችን እንዲያነሳ እና ቪድዮ እንዲቀርጽ ይፈቀድለት?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ይህ መተግበሪያ መተግበሪያውን በማይጠቀሙበት ጊዜም እንኳ ሁልጊዜ ሥዕሎችን ማንሳት እና ቪዲዮ መቅዳት ሊፈልግ ይችላል። "<annotation id="link">"በቅንብሮች ውስጥ ይፍቀዱ።"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"ለ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የካሜራ መዳረሻ ይለወጥ?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"ይህ መተግበሪያ መተግበሪያውን በማይጠቀሙበት ጊዜም እንኳ ሁልጊዜ ሥዕሎችን ማንሳት እና ቪዲዮ መቅዳት ይፈልጋል። "<annotation id="link">"በቅንብሮች ውስጥ ይፍቀዱ።"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"የእርስዎን ስልክ የጥሪ ምዝግብ ማስታወሻዎች &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; እንዲደርስበት ይፈቀድ?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ የስልክ የጥሪ ምዝገባ ማስታወሻዎችዎን እንዲደርስ ይፈቀድለት?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የስልክ ጥሪዎችን እንዲያደርግ እና እንዲያቀናብር ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ የስልክ ጥሪዎችን ማድረግ እና ማስተዳደር ይፈቀድለት?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የሰውነትዎ መሠረታዊ ምልክቶች የዳሳሽ ውሂብ እንዲደርስ ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ስለ መሠረታዊ ምልክቶችዎ የዳሳሽ ውሂብን እንዲደርስ ይፈቀድለት?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"መተግበሪያውን በማይጠቀሙበት ጊዜም እንኳ ይህ መተግበሪያ የእርስዎን የመሠረታዊ ምልክቶች የዳሳሽ ውሂብን ሁልጊዜ መድረስ ይፈልጋል። ይህን ለውጥ ለማድረግ "<annotation id="link">"ወደ ቅንብሮች ይሂዱ።"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የሰውነትዎ መሠረታዊ ምልክቶች የዳሳሽ ውሂብ እንዲደርስ ይፈቀድለት?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ስለ መሠረታዊ ምልክቶችዎ የዳሳሽ ውሂቡን እንዲደርስ ይፈቀድለት?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"መተግበሪያውን በማይጠቀሙበት ጊዜ እንኳን ይህ መተግበሪያ የሰውነት ዳሳሽ ውሂብን ሁልጊዜ እንዲደርስ ለመፍቀድ "<annotation id="link">"ወደ ቅንብሮች ይሂዱ።"</annotation></string>
- <string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"መተግበሪያ ስራ ላይ በሚውልበት ጊዜ የሰውነት ዳሳሽ ውሂብን እንዲደርስ ለ&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; መፍቀድ ይቀጥሉ?"</string>
+ <string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"መተግበሪያ ሥራ ላይ በሚውልበት ጊዜ የሰውነት ዳሳሽ ውሂብን እንዲደርስ ለ&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; መፍቀድ ይቀጥሉ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"መተግበሪያ ጥቅም ላይ እየዋለ ሳለ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ የሰውነት ዳሳሽ ውሂብን እንዲደርስ መፍቀድ ይቀጥል?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ለእርስዎ ማሳወቂያዎች እንዲልክ ይፈቀድለት?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; በእርስዎ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ላይ ማሳወቂያዎችን እንዲልክልዎ ይፈቀድለት?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"ቁጥጥር የሚደረግባችድው ፈቃዶች"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> የአካባቢ መዳረሻ አለው"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"ድርጅትዎ <xliff:g id="APP_NAME">%1$s</xliff:g> አካባቢዎን እንዲደርስ ይፈቅዳል"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"ሌሎች ፍቃዶች"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"በስርዓት ጥቅም ላይ የሚውል ፈቃድ"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"በስርዓት መተግበሪያዎችች ብቻ ጥቅም ላይ የሚውሉ ፈቃዶች።"</string>
@@ -546,14 +583,14 @@
<string name="remove_microphone_qs" msgid="1276551965129953198">"ለዚህ መተግበሪያ ፈቃድን አስወግድ"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"አገልግሎት ያስተዳድሩ"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"ፈቃዶችን ያስተዳድሩ"</string>
- <string name="active_call_usage_qs" msgid="8559974395932523391">"በስልክ ጥሪ ስራ ላይ እየዋለ ነው"</string>
- <string name="recent_call_usage_qs" msgid="743044899599410935">"በቅርብ ጊዜ በስልክ ጥሪ ውስጥ ስራ ላይ ውሏል"</string>
- <string name="active_app_usage_qs" msgid="4063912870936464727">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> ስራ ላይ እየዋለ ነው"</string>
- <string name="recent_app_usage_qs" msgid="6650259601306212327">"በቅርብ ጊዜ በ<xliff:g id="APP_NAME">%1$s</xliff:g> ስራ ላይ ውሏል"</string>
- <string name="active_app_usage_1_qs" msgid="4325136375823357052">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ስራ ላይ እየዋለ ነው"</string>
- <string name="recent_app_usage_1_qs" msgid="261450184773310741">"በቅርብ ጊዜ በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ስራ ላይ ውሏል"</string>
- <string name="active_app_usage_2_qs" msgid="6107866785243565283">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ስራ ላይ እየዋለ ነው"</string>
- <string name="recent_app_usage_2_qs" msgid="3591205954235694403">"በቅርብ ጊዜ በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ስራ ላይ ውሏል"</string>
+ <string name="active_call_usage_qs" msgid="8559974395932523391">"በስልክ ጥሪ ሥራ ላይ እየዋለ ነው"</string>
+ <string name="recent_call_usage_qs" msgid="743044899599410935">"በቅርብ ጊዜ በስልክ ጥሪ ውስጥ ሥራ ላይ ውሏል"</string>
+ <string name="active_app_usage_qs" msgid="4063912870936464727">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> ሥራ ላይ እየዋለ ነው"</string>
+ <string name="recent_app_usage_qs" msgid="6650259601306212327">"በቅርብ ጊዜ በ<xliff:g id="APP_NAME">%1$s</xliff:g> ሥራ ላይ ውሏል"</string>
+ <string name="active_app_usage_1_qs" msgid="4325136375823357052">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ሥራ ላይ እየዋለ ነው"</string>
+ <string name="recent_app_usage_1_qs" msgid="261450184773310741">"በቅርብ ጊዜ በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ሥራ ላይ ውሏል"</string>
+ <string name="active_app_usage_2_qs" msgid="6107866785243565283">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ሥራ ላይ እየዋለ ነው"</string>
+ <string name="recent_app_usage_2_qs" msgid="3591205954235694403">"በቅርብ ጊዜ በ<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) ሥራ ላይ ውሏል"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"አረጋግጥ"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"ተመለስ"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"የሌሎች ፋይሎች መዳረሻም ይፈቀዳል"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"ይህ መተግበሪያ የአካባቢ ውሂብን ከሦስተኛ ወገኖች ጋር ሊያጋራ እንደሚችል ገልጿል"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ውሂብ ማጋራት እና አካባቢ"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"የውሂብ ማጋራት መረጃ ከየት እንደሚመጣ"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ገንቢው ይህ መተግበሪያ እንዴት ውሂብን እንደሚያጋራ ለዚህ የመሣሪያ አምራች መረጃን አቅርቧል። ገንቢው ይህን መረጃ በጊዜ ሂደት ሊያዘምን ይችላል።"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ገንቢው ይህ መተግበሪያ እንዴት ውሂብ እንደሚያጋራ መረጃ ለ"<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" አቅርቧል። ገንቢው ይህን መረጃ በጊዜ ሂደት ሊያዘምን ይችላል።"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ይህ መተግበሪያ የአካባቢ ውሂብን ለሚከተሉት ሊያጋራ ይችላል፦"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"የውሂብ ማጋራት ይለያያል"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"የውሂብ ደህንነት"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"የአካባቢ ውሂብ ሊጋራ ይችላል"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"ይህ መተግበሪያ የአካባቢ ውሂብዎን ከሦስተኛ ወገኖች ጋር ሊያጋራ እንደሚችል ገልጿል"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ይህን አገናኝ መክፈት አልተቻለም"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"የአካባቢ የውሂብ ማጋራት ዝማኔዎች"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"የእርስዎን የአካባቢ ውሂብ ሊያጋሩ የሚችሉበትን መንገድ የለወጡ መተግበሪያዎችን ይገምግሙ"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"እነዚህ መተግበሪያዎች የእርስዎን የአካባቢ ውሂብ ሊያጋሩ የሚችሉበትን መንገድ ለውጠዋል። ከዚህ በፊት አጋርተውት ላይሆን ይችላል፣ ወይም አሁን ለማስታወቂያ ወይም የገበያ ሥራ ዓላማዎች ሊያጋሩት ይችላሉ።"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"የውሂብ ማጋራት ዝማኔዎች"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"አንዳንድ መተግበሪያዎች የእርስዎን የአካባቢ ውሂብ ሊያጋሩ የሚችሉበትን መንገድ ለውጠዋል"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ቅንብሮች"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"በ<xliff:g id="TIME_DATE">%1$s</xliff:g> ላይ ተደርስበታል"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"ትላንት በ<xliff:g id="TIME_DATE">%1$s</xliff:g> ላይ ተደርስበታል"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"በ<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g> ላይ ተደርስበታል"</string>
</resources>
diff --git a/PermissionController/res/values-ar-v33/strings.xml b/PermissionController/res/values-ar-v33/strings.xml
index bede64168..6b881f064 100644
--- a/PermissionController/res/values-ar-v33/strings.xml
+++ b/PermissionController/res/values-ar-v33/strings.xml
@@ -20,7 +20,7 @@
<string name="role_sms_request_description" msgid="1506966389698625395">"سيُسمح لهذا التطبيق بإرسال إشعارات إليك، وسيُمنح إذن الوصول إلى الكاميرا وجهات الاتصال والملفات والميكروفون والهاتف والرسائل القصيرة."</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"يمكن للتطبيقات التي لديها هذا الإذن الوصول إلى جميع الملفات على هذا الجهاز."</string>
<string name="work_policy_title" msgid="832967780713677409">"معلومات سياسة العمل"</string>
- <string name="work_policy_summary" msgid="3886113358084963931">"يتولى مشرف تكنولوجيا المعلومات إدارة الإعدادات."</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"يتولى مشرف تكنولوجيا المعلومات إدارة الإعدادات"</string>
<string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"توسيع القائمة وعرضها"</string>
<string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"تصغير القائمة وإخفاء الإعدادات"</string>
<string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"قائمة <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"المزيد من التنبيهات"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"التنبيهات التي تم إغلاقها"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{التوسيع لعرض تنبيه واحد إضافي}zero{التوسيع لعرض # تنبيه إضافي}two{التوسيع لعرض تنبيهين إضافيَين}few{التوسيع لعرض # تنبيهات إضافية}many{التوسيع لعرض # تنبيهًا إضافيًا}other{التوسيع لعرض # تنبيه إضافي}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"تنبيه: <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"اكتمل الإجراء"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"التحقّق من الإعدادات التي يمكن أن تعزّز حماية جهازك"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"الإعدادات السريعة للأمان والخصوصية"</string>
diff --git a/PermissionController/res/values-ar-v34/strings.xml b/PermissionController/res/values-ar-v34/strings.xml
index 667db98f7..5a0d25e63 100644
--- a/PermissionController/res/values-ar-v34/strings.xml
+++ b/PermissionController/res/values-ar-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"الأمان والخصوصية"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"عناصر التحكّم"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"يمكنك إدارة وصول التطبيقات إلى البيانات الصحية."</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"إدارة إمكانية وصول التطبيقات إلى البيانات الصحية"</string>
<string name="location_settings" msgid="8863940440881290182">"الوصول إلى الموقع الجغرافي"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"للتطبيقات والخدمات: إذا كان هذا الخيار غير مفعّل، ستستمر إمكانية مشاركة بيانات الميكروفون عند الاتصال برقم طوارئ."</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"للتطبيقات والخدمات"</string>
diff --git a/PermissionController/res/values-ar/strings.xml b/PermissionController/res/values-ar/strings.xml
index f1ecdc3c4..72da19625 100644
--- a/PermissionController/res/values-ar/strings.xml
+++ b/PermissionController/res/values-ar/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"معلومات أكثر"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"السماح بالكل"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"السماح بالكل دومًا"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"السماح بالوصول المحدود إلى الصور والفيديوهات"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"اختيار صور وفيديوهات"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"اختيار المزيد"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"عدم اختيار المزيد"</string>
@@ -43,7 +44,7 @@
<string name="permission_warning_template" msgid="2247087781222679458">"‏هل تريد السماح للتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بإجراء <xliff:g id="ACTION">%2$s</xliff:g>؟"</string>
<string name="permission_add_background_warning_template" msgid="1812914855915092273">"‏هل تريد السماح دائمًا للتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بهذا الإجراء <xliff:g id="ACTION">%2$s</xliff:g>؟"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"أثناء استخدام التطبيق فقط"</string>
- <string name="allow_permission_always" msgid="5194342531206054051">"دومًا"</string>
+ <string name="allow_permission_always" msgid="5194342531206054051">"دائمًا"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"عدم السماح وعدم طرح السؤال مرةً أخرى"</string>
<string name="permission_revoked_count" msgid="4785082705441547086">"<xliff:g id="COUNT">%1$d</xliff:g> إذن موقوف"</string>
<string name="permission_revoked_all" msgid="3397649017727222283">"كل الأذونات موقوفة."</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"تطبيقات"</string>
<string name="app_permissions" msgid="3369917736607944781">"أذونات التطبيقات"</string>
<string name="unused_apps" msgid="2058057455175955094">"التطبيقات غير المستخدمة"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"تغيير الصور المتاحة لهذا التطبيق"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ما مِن تطبيقات غير مستخدمة."</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"التطبيقات غير المستخدمة: 0"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"قرارات حديثة متعلقة بالأذونات"</string>
@@ -71,7 +73,7 @@
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{اليوم}=1{قبل يوم واحد}two{قبل يومَين}few{قبل # أيام}many{قبل # يومًا}other{قبل # يوم}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"إيقاف التطبيق"</string>
<string name="app_disable_dlg_text" msgid="3126943217146120240">"‏قد يؤدي إيقاف هذا التطبيق إلى عدم عمل نظام Android وتطبيقات أخرى على النحو المنشود. تجدر الإشارة إلى أنه لا يمكنك حذف هذا التطبيق لأنه من التطبيقات المثبّتة تلقائيًا على جهازك. ويعني إيقاف التطبيق أنه سيتم إيقافه وإخفاؤه على جهازك."</string>
- <string name="app_permission_manager" msgid="3903811137630909550">"مدير الأذونات"</string>
+ <string name="app_permission_manager" msgid="3903811137630909550">"إدارة الأذونات"</string>
<string name="never_ask_again" msgid="4728762438198560329">"عدم السؤال مجدّدًا"</string>
<string name="no_permissions" msgid="3881676756371148563">"ليس هناك أيّ أذونات."</string>
<string name="additional_permissions" msgid="5801285469338873430">"أذونات إضافية"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"كل الأذونات"</string>
<string name="other_permissions" msgid="2901186127193849594">"إمكانات التطبيق الأخرى"</string>
<string name="permission_request_title" msgid="8790310151025020126">"طلب الإذن"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"‏لا تتوافق إجراءات التثبيت/إلغاء التثبيت مع نظام Android Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"‏اختيار ما تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إليه"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"‏تمّ تحديث &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;. وعليك اختيار ما تريد السماح لهذا التطبيق بالوصول إليه."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"إلغاء"</string>
@@ -129,7 +129,7 @@
<string name="permission_group_usage_title" msgid="2595013198075285173">"استخدام <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"عرض الأذونات الأخرى"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>، <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
- <string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g> و<xliff:g id="PERMGROUP_1">%2$s</xliff:g> و<xliff:g id="NUM">%3$s</xliff:g> تطبيق آخر"</string>
+ <string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"‫\"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>\" و\"<xliff:g id="PERMGROUP_1">%2$s</xliff:g>\" و<xliff:g id="NUM">%3$s</xliff:g> تطبيق آخر"</string>
<string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"المخطط الزمني لاستخدام <xliff:g id="PERMGROUP">%1$s</xliff:g> في آخر 24 ساعة"</string>
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"المخطط الزمني لاستخدام <xliff:g id="PERMGROUP">%1$s</xliff:g> في آخر 7 أيام"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"وقت استخدام هذا التطبيق لإذن <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"إزالة الأذونات في حال عدم استخدام التطبيق"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"إزالة الأذونات وإخلاء مساحة"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"إيقاف نشاط التطبيق مؤقتًا عند عدم استخدامه"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"إدارة التطبيق في حال عدم استخدامه"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"إزالة الأذونات وحذف الملفات المؤقتة وإيقاف الإشعارات"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"إزالة الأذونات وحذف الملفات المؤقتة وإيقاف الإشعارات وأرشفة التطبيق"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"لحماية بياناتك، ستتم إزالة أذونات هذا التطبيق إذا لم يتم استخدامه لبضعة أشهر."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"لحماية بياناتك، إذا لم يتم استخدام التطبيق لبضعة أشهر، ستتم إزالة الأذونات التالية: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"لحماية بياناتك، تمت إزالة الأذونات من هذه التطبيقات التي لم تستخدمها منذ بضعة أشهر."</string>
@@ -221,7 +223,7 @@
<string name="unused_apps_page_title" msgid="6986983535677572559">"التطبيقات غير المستخدمة"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"في حال عدم استخدام التطبيق لبضعة أشهر:\n\n• تتم إزالة الأذونات لحماية بياناتك.\n• يتم إيقاف الإشعارات لتوفير شحن البطارية.\n• تتم إزالة الملفات المؤقتة لتوفير مساحة.\n\nلمنح الأذونات والسماح للتطبيقات مرة أخرى، افتح التطبيق."</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"في حال عدم استخدام تطبيق لمدة شهر:\n\n• تتم إزالة الأذونات لحماية بياناتك.\n• تتم إزالة الملفات المؤقتة لإخلاء بعض المساحة.\n\nللسماح بالأذونات مرة أخرى، افتَح التطبيق."</string>
- <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{التطبيقات التي تم فتحها آخر مرة قبل أكثر من شهر واحد}zero{التطبيقات التي تم فتحها آخر مرة قبل أكثر من # شهر}two{التطبيقات التي تم فتحها آخر مرة قبل أكثر من شهرَين}few{التطبيقات التي تم فتحها آخر مرة قبل أكثر من # شهور}many{التطبيقات التي تم فتحها آخر مرة قبل أكثر من # شهرًا}other{التطبيقات التي تم فتحها آخر مرة قبل أكثر من # شهر}}"</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{التطبيقات التي تم فتحها آخر مرة قبل أكثر من شهر واحد}zero{التطبيقات التي تم فتحها آخر مرة قبل أكثر من # شهر}two{التطبيقات التي تم فتحها آخر مرة قبل أكثر من شهرَين}few{التطبيقات التي تم فتحها آخر مرة قبل أكثر من # أشهر}many{التطبيقات التي تم فتحها آخر مرة قبل أكثر من # شهرًا}other{التطبيقات التي تم فتحها آخر مرة قبل أكثر من # شهر}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"آخر مرة تم فتح التطبيق فيها: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"آخر مرة تم فتحه: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"في حال السماح لهذا التطبيق بإدارة كل الملفات، سيتمكن من الوصول إلى أي ملفات وتعديلها وحذفها من مساحة التخزين العادية على هذا الجهاز أو أجهزة التخزين المتصلة. يمكن أن يصل التطبيق إلى الملفات بدون طلب موافقتك."</string>
@@ -245,13 +247,13 @@
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"مرفوض حاليًا / تاريخ آخر وصول: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"لم يستخدم الإذن مطلقًا"</string>
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"تم الرفض / لم يسبق الحصول على الإذن"</string>
- <string name="allowed_header" msgid="7769277978004790414">"الأذونات المسموح بها"</string>
- <string name="allowed_always_header" msgid="6455903312589013545">"التطبيقات المسموح لها بالوصول طوال الوقت"</string>
+ <string name="allowed_header" msgid="7769277978004790414">"التطبيقات المسموح لها"</string>
+ <string name="allowed_always_header" msgid="6455903312589013545">"تطبيقات مسموح لها بالوصول طوال الوقت"</string>
<string name="allowed_foreground_header" msgid="6845655788447833353">"تطبيقات يمكنها الوصول عند استخدامها فقط"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"التطبيقات المسموح لها بالوصول إلى الوسائط فقط"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"التطبيقات المسموح لها بإدارة كل الملفات"</string>
<string name="ask_header" msgid="2633816846459944376">"الطلب في كل مرة"</string>
- <string name="denied_header" msgid="903209608358177654">"الأذونات غير المسموح بها"</string>
+ <string name="denied_header" msgid="903209608358177654">"التطبيقات غير المسموح لها"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"الاطّلاع على تطبيقات أكثر يمكنها الوصول إلى كل الملفات"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{يوم واحد}zero{# يوم}two{يومان}few{# أيام}many{# يومًا}other{# يوم}}"</string>
<string name="hours" msgid="7302866489666950038">"{count,plural, =1{ساعة واحدة}zero{# ساعة}two{ساعتان}few{# ساعات}many{# ساعةً}other{# ساعة}}"</string>
@@ -340,7 +342,7 @@
<string name="no_apps_allowed" msgid="7718822655254468631">"لم يتم السماح لأي تطبيقات."</string>
<string name="no_apps_allowed_full" msgid="8011716991498934104">"ما من تطبيقات تم منحها إذن الوصول إلى جميع الملفات."</string>
<string name="no_apps_allowed_scoped" msgid="4908850477787659501">"ما من تطبيقات تم منحها إذن الوصول إلى الوسائط فقط."</string>
- <string name="no_apps_denied" msgid="7663435886986784743">"لم يتم رفض أي تطبيقات."</string>
+ <string name="no_apps_denied" msgid="7663435886986784743">"لم يتم رفض أي تطبيقات"</string>
<string name="car_permission_selected" msgid="180837028920791596">"مُختار"</string>
<string name="settings" msgid="5409109923158713323">"الإعدادات"</string>
<string name="accessibility_service_dialog_title_single" msgid="7956432823014102366">"تحظى خدمة <xliff:g id="SERVICE_NAME">%s</xliff:g> بوصول كامل إلى جهازك."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"تطبيق تدوين الملاحظات"</string>
<string name="role_notes_description" msgid="8496852798616883551">"التطبيقات التي تتيح لك تدوين ملاحظات على جهازك"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ملاحظات"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"التطبيق التلقائي الحالي"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"لا تسألني مرة أخرى."</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ضبط كتطبيق تلقائي"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"عرض الرمز الخاص برصد تشغيل تطبيق مساعد"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"عرض الرمز في شريط الحالة عند استخدام الميكروفون لتفعيل المساعد الصوتي."</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالدخول إلى الصور والوسائط على جهازك؟"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الصور والوسائط على جهاز &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى جهات اتصالك على جهاز &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"‏هل تريد السماح لتطبيق &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"‏هل تريد السماح لتطبيق &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>؟"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"قد يطلب هذا التطبيق الوصول الدائم إلى موقعك الجغرافي، حتى عند عدم استخدامك للتطبيق. يمكنك "<annotation id="link">"السماح بذلك في الإعدادات."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"‏هل تريد تغيير إمكانية الوصول إلى الموقع الجغرافي بالنسبة إلى &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;؟"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"‏هل تريد تغيير إذن وصول تطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى الموقع الجغرافي على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"يطلب هذا التطبيق الوصول الدائم إلى موقعك الجغرافي، حتى عند عدم استخدامك للتطبيق. يمكنك "<annotation id="link">"السماح بذلك في الإعدادات."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالعثور على الأجهزة المجاورة والربط بها وتحديد موضعها النسبي؟"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"‏هل تسمح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالعثور على الأجهزة المجاورة والربط بها وتحديد موضعها النسبي على &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالعثور على الأجهزة المجاورة والربط بها وتحديد موضعها النسبي؟ "<annotation id="link">"يمكنك السماح بذلك في \"الإعدادات\"."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"هل تريد تغيير إذن وصول <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> من الموقع الجغرافي التقريبي إلى الموقع الجغرافي الدقيق؟"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"‏هل تريد تغيير إذن وصول تطبيق \"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>\" إلى الموقع الجغرافي ليكون دقيقًا بدلاً من كونه تقريبيًّا على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الموقع الجغرافي التقريبي لجهاز &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى تقويمك على جهاز &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بإرسال الرسائل القصيرة SMS وعرضها على جهاز &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الصور والوسائط والملفات على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"‏هل تسمح بوصول &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى &lt;b&gt;الصور والفيديوهات والموسيقى والملفات الصوتية&lt;/b&gt; على هذا الجهاز؟"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"‏هل تسمح بوصول &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى &lt;b&gt;الصور والفيديوهات والموسيقى والملفات الصوتية وملفات أخرى&lt;/b&gt; على هذا الجهاز؟"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"‏هل تريد السماح بوصول &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى المقاطع الموسيقية والملفات الصوتية على هذا الجهاز؟"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الموسيقى والملفات الصوتية على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"‏هل تريد السماح بوصول &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى الصور والفيديوهات على هذا الجهاز؟"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الصور والفيديوهات على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"‏هل تريد السماح بوصول تطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى المزيد من الصور والفيديوهات على هذا الجهاز؟"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى مزيد من الصور والفيديوهات على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بتسجيل الصوت؟"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بتسجيل الصوت على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"لن يتمكن هذا التطبيق من تسجيل الصوت إلا عندما يكون قيد الاستخدام"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بتسجيل الصوت؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بتسجيل الصوت على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"قد يحتاج هذا التطبيق إلى تسجيل الصوت طوال الوقت، حتى عند عدم استخدامك للتطبيق. يمكنك "<annotation id="link">"السماح بذلك في الإعدادات"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"‏هل تريد تغيير إذن الوصول إلى الميكروفون بالنسبة إلى &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;؟"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"‏هل تريد تغيير إذن وصول تطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى الميكروفون على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"يحتاج هذا التطبيق إلى تسجيل الصوت طوال الوقت، حتى عند عدم استخدامك للتطبيق. يمكنك "<annotation id="link">"السماح بذلك في الإعدادات"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"‏هل تريد السماح للتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى بيانات نشاطك البدني؟"</string>
- <string name="permgrouprequest_camera" msgid="5123097035410002594">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالتقاط صور وتسجيل فيديو؟"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى بيانات نشاطك البدني على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
+ <string name="permgrouprequest_camera" msgid="5123097035410002594">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالتقاط صور وتسجيل فيديوهات؟"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالتقاط الصور وتسجيل الفيديوهات على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"لن يتمكن هذا التطبيق من التقاط صور وتسجيل فيديوهات إلا عندما يكون قيد الاستخدام"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالتقاط صور وتسجيل فيديوهات؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالتقاط الصور وتسجيل الفيديوهات على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"قد يحتاج هذا التطبيق إلى التقاط صور وتسجيل فيديوهات طوال الوقت، حتى عند عدم استخدامك للتطبيق. يمكنك "<annotation id="link">"السماح بذلك في الإعدادات"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"‏هل تريد تغيير إذن الوصول إلى الكاميرا بالنسبة إلى &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;؟"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"‏هل تريد تغيير إذن وصول تطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى الكاميرا على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"يحتاج هذا التطبيق إلى التقاط صور وتسجيل فيديوهات طوال الوقت، حتى عند عدم استخدامك للتطبيق. يمكنك "<annotation id="link">"السماح بذلك في الإعدادات"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى سجلّ مكالماتك الهاتفية؟"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى سجلّ مكالمات الهاتف على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بإجراء المكالمات الهاتفية وإدارتها؟"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بإجراء المكالمات الهاتفية وإدارتها على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى بيانات استشعار مؤشراتك الحيوية؟"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"‏هل تريد السماح بوصول &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى بيانات جهاز الاستشعار المتعلّقة بالمؤشرات الحيوية على &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"يطلب هذا التطبيق الوصول الدائم إلى بيانات جهاز الاستشعار المتعلّقة بالمؤشرات الحيوية، حتى في حال عدم استخدامك للتطبيق. لإجراء هذا التغيير، "<annotation id="link">"انتقِل إلى الإعدادات."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى بيانات استشعار مؤشراتك الحيوية؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"‏هل تريد السماح بوصول &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; إلى بيانات جهاز الاستشعار المتعلّقة بالمؤشرات الحيوية على &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"للسماح لهذا التطبيق بالوصول إلى بيانات أجهزة استشعار الجسم دائمًا وحتى عند عدم استخدامك للتطبيق، "<annotation id="link">"انتقِل إلى الإعدادات"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"‏هل تريد مواصلة السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; عند استخدامه بالوصول إلى بيانات أجهزة استشعار الجسم؟"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"‏هل تريد مواصلة السماح بوصول تطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; المستخدَم إلى بيانات جهاز استشعار الجسم على &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بإرسال إشعارات إليك؟"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بإرسال إشعارات إليك على جهاز &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"الأذونات خاضعة لتحكّم المشرف"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"تطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" مسموح له بالوصول إلى الموقع الجغرافي"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"تسمح مؤسستك لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" بالوصول إلى موقعك الجغرافي."</string>
<string name="other_permissions_label" msgid="8986184335503271992">"الأذونات الأخرى"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"الأذونات المستخدمة من قِبل النظام"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"الأذونات المستخدمة من قِبل تطبيقات النظام فقط"</string>
@@ -549,7 +586,7 @@
<string name="active_call_usage_qs" msgid="8559974395932523391">"يتم الاستخدام في المكالمة الهاتفية"</string>
<string name="recent_call_usage_qs" msgid="743044899599410935">"تم الاستخدام مؤخرًا في مكالمة هاتفية"</string>
<string name="active_app_usage_qs" msgid="4063912870936464727">"يتم الاستخدام من قِبل <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="recent_app_usage_qs" msgid="6650259601306212327">"تم الاستخدام مؤخرًا من قِبل <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="recent_app_usage_qs" msgid="6650259601306212327">"تم الاستخدام مؤخرًا من قِبل \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="active_app_usage_1_qs" msgid="4325136375823357052">"يتم الاستخدام من قِبل <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"تم الاستخدام مؤخرًا من قِبل <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="active_app_usage_2_qs" msgid="6107866785243565283">"يتم الاستخدام من قِبل <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
@@ -585,12 +622,13 @@
<string name="mic_toggle_description" msgid="9163104307990677157">"بالنسبة للتطبيقات والخدمات. إذا كان هذا الخيار غير مفعّل، قد يظل بالإمكان مشاركة بيانات الميكروفون عند الاتصال برقم طوارئ."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"عرض التطبيقات والخدمات التي يمكنها الوصول إلى الموقع الجغرافي"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"عرض إشعار عند الوصول إلى الحافظة"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"عرض رسالة عندما يصل التطبيق إلى نص أو صور أو محتوى آخر تم نسخه."</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"عرض رسالة عندما يصل التطبيق إلى نص أو صور أو محتوى آخر تم نسخه"</string>
<string name="show_password_title" msgid="2877269286984684659">"عرض كلمات المرور"</string>
<string name="show_password_summary" msgid="1110166488865981610">"عرض الأحرف لفترة وجيزة أثناء الكتابة"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"وضَّح هذا التطبيق أنه يمكنه مشاركة بيانات الموقع الجغرافي مع جهات خارجية."</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"مشاركة البيانات والموقع الجغرافي"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"من أين تأتي معلومات مشاركة البيانات؟"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"قدَّم المطوّر معلومات إلى الشركة المصنّعة لهذا الجهاز عن الطريقة التي يشارك بها هذا التطبيق البيانات. يمكن أنّ يعدّل المطوّر هذه المعلومات بمرور الوقت."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"‏قدَّم المطوّر معلومات إلى "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" عن كيفية مشاركة هذا التطبيق للبيانات. يمكن أنّ يعدّل المطوّر هذه المعلومات بمرور الوقت."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"قد يشارك التطبيق بيانات الموقع الجغرافي من أجل:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"اختلاف مشاركة البيانات"</string>
@@ -608,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"أمان البيانات"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"قد تتم مشاركة بيانات الموقع الجغرافي"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"وضَّح هذا التطبيق أنّه قد يشارك بيانات موقعك الجغرافي مع جهات خارجية."</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"يتعذَّر فتح هذا الرابط"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"تعديلات مشاركة بيانات الموقع الجغرافي"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"راجِع التطبيقات التي غيّرت الطريقة التي قد تشارك بها بيانات موقعك الجغرافي."</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"مراجعة التطبيقات التي غيّرت الطريقة التي قد تشارك بها بيانات موقعك الجغرافي"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"غيّرت هذه التطبيقات الطريقة التي قد تشارك بها بيانات موقعك الجغرافي. ربما لم تشارك هذه التطبيقات بياناتك من قبل، أو قد تشاركها الآن لأغراض إعلانية أو تسويقية."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"قدَّم مطوّرو هذه التطبيقات معلومات حول الممارسات المتعلقة بمشاركة البيانات مع متجر التطبيقات. ويمكن أن يعدّلوا تلك المعلومات بمرور الوقت.\n\nقد تختلف الممارسات المتعلقة بمشاركة البيانات بناءً على إصدار تطبيقك وآلية استخدامك له ومنطقتك وعمرك."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"التعرّف على مشاركة البيانات"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"تعديلات مشاركة البيانات"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"غيّرت بعض التطبيقات الطريقة التي قد تشارك بها بيانات موقعك الجغرافي."</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"الإعدادات"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"‏آخر استخدام للإذن: ‎<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"‏آخر استخدام للإذن أمس: ‎<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"‏آخر استخدام للإذن في ‎<xliff:g id="TIME_DATE_0">%1$s</xliff:g>: ‏<xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-as/strings.xml b/PermissionController/res/values-as/strings.xml
index 40d8ed7c0..8d84af552 100644
--- a/PermissionController/res/values-as/strings.xml
+++ b/PermissionController/res/values-as/strings.xml
@@ -32,8 +32,9 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"“এপ্‌টো ব্যৱহাৰ হৈ থকা অৱস্থাত” ৰাখক"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"“কেৱল এইবাৰৰ বাবে অনুমতি দিয়ক” বিকল্পটো ৰাখক"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"অধিক তথ্য"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"আটাইবোৰকে অনুমতি দিয়ক"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"আটাইবোৰৰে অনুমতি দিয়ক"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"আটাইবোৰকে সদায় অনুমতি দিয়ক"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"সীমিত এক্সেছৰ অনুমতি দিয়ক"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ফট’ আৰু ভিডিঅ’ বাছনি কৰক"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"অধিক বাছনি কৰক"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"আৰু অধিক বাছনি নকৰিব"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"এপ্"</string>
<string name="app_permissions" msgid="3369917736607944781">"এপৰ অনুমতি"</string>
<string name="unused_apps" msgid="2058057455175955094">"অব্যৱহৃত এপ্‌সমূহ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"এই এপ্‌টোৰ বাবে বাছনি কৰা ফট’ সম্পাদনা কৰক"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ব্যৱহাৰ নকৰা কোনো এপ্‌ নাই"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"০ টা অব্যৱহৃত এপ্‌"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"শেহতীয়া অনুমতিৰ সিদ্ধান্তসমূহ"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"সকলো অনুমতি"</string>
<string name="other_permissions" msgid="2901186127193849594">"অন্য এপৰ কার্যক্ষমতা"</string>
<string name="permission_request_title" msgid="8790310151025020126">"অনুমতি বিচাৰি কৰা অনুৰোধ"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"ইনষ্টল/আনইনষ্টল কাৰ্য Wearত কৰিব নোৱাৰি।"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক ক’ত এক্সেছ দিব লাগে বাছনি কৰক"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; আপডে’ট কৰা হৈছে। এই এপক ক’ত এক্সেছ দিব লাগে বাছনি কৰক।"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"বাতিল কৰক"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"যদি এপ্‌টো ব্যৱহাৰ কৰা নাই অনুমতিসমূহ আঁতৰাওক"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"অনুমতি আঁতৰাওক আৰু ঠাই খালী কৰক"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"অব্যৱহৃত হৈ থাকিলে এপৰ কাৰ্যকলাপ পজ কৰক"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"যদি ব্যৱহাৰ হোৱা নাই এপ্‌টো পৰিচালনা কৰক"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"অনুমতি আঁতৰাওক, অস্থায়ী ফাইল মচক আৰু জাননী বন্ধ কৰক"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"অনুমতি আঁতৰাওক, অস্থায়ী ফাইল মচক, জাননী বন্ধ কৰক আৰু এপ্‌টো আৰ্কাইভ কৰক"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"আপোনাৰ ডেটা সুৰক্ষিত কৰিবলৈ এই এপ্‌টো কেইমাহমান ব্যৱহাৰ নকৰিলে এইটোৰ বাবে থকা অনুমতিসমূহ আঁতৰোৱা হ\'ব।"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"আপোনাৰ ডেটা সুৰক্ষিত কৰিবলৈ এই এপ্‌টো কেইমাহমান ব্যৱহাৰ নকৰিলে তলত উল্লেখ কৰা অনুমতিসমূহ আঁতৰোৱা হ\'ব: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"আপোনাৰ ডেটা সুৰক্ষিত কৰিবলৈ আপুনি কেইমাহমান ব্যৱহাৰ নকৰা এপ্‌সমূহৰ পৰা অনুমতিসমূহ আঁতৰোৱা হ\'ব।"</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"অন্তিমবাৰ <xliff:g id="DATE">%s</xliff:g>ত খোলা হৈছিল"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"আপুনি যদি আটাইবোৰ ফাইল পৰিচালনাৰ অনুমতি দিয়ে, এই এপ্‌টোৱে এই ডিভাইচটোৰ যৌথ ষ্ট\'ৰেজত থকা যিকোনো ফাইল অথবা সংযুক্ত ষ্ট\'ৰেজ ডিভাইচসমূহ এক্সেছ কৰিব, সংশোধন কৰিব আৰু মচিব পাৰে। এপ্‌টোৱে আপোনাক নোসোধাকৈয়ে ফাইলসমূহ এক্সেছ কৰিব পাৰে।"</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"এই এপ্‌টোক ডিভাইচটোত থকা অথবা যিকোনো সংযুক্ত ষ্ট\'ৰেজ ডিভাইচসমূহৰ ফাইলসমূহ এক্সেছ কৰিবলৈ, সংশোধন কৰিবলৈ আৰু মচিবলৈ অনুমতি দিবনে? এই এপ্‌টোৱে আপোনাক নোসোধাকৈয়ে ফাইলসমূহ এক্সেছ কৰিব পাৰে।"</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"অনুমতি থকা এপ্‌সমূহে <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"অনুমতি থকা এপ্‌সমূহে কৰিব পাৰে: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"এই অনুমতিটো লাভ কৰা এপে আপোনাৰ শাৰীৰিক কাৰ্যকলাপ, যেনে খোজকঢ়া, বাইক চলোৱা, গাড়ী চলোৱা, পদক্ষেপৰ পৰিমাণ আৰু বহুতো তথ্য এক্সেছ কৰিব পাৰে"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"এই অনুমতি থকা এপ্‌সমূহে আপোনাৰ কেলেণ্ডাৰ এক্সেছ কৰিব পাৰে"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"এই অনুমতি থকা এপ্‌সমূহে ফ’ন কল লগ পঢ়িব আৰু লিখিব পাৰে"</string>
@@ -374,7 +376,7 @@
<string name="role_emergency_request_description" msgid="131645948770262850">"কোনো অনুমতিৰ প্ৰয়োজন নাই"</string>
<string name="role_emergency_search_keywords" msgid="1920007722599213358">"বৰফ"</string>
<string name="role_home_label" msgid="3871847846649769412">"ডিফ’ল্ট হ’ম এপ্"</string>
- <string name="role_home_short_label" msgid="8544733747952272337">"হ’ম এপ্"</string>
+ <string name="role_home_short_label" msgid="8544733747952272337">"Home এপ্"</string>
<string name="role_home_description" msgid="7997371519626556675">"যিবোৰ এপক সাধাৰণতে লঞ্চাৰ বুলি কোৱা হয় সেই এপ্‌বোৰে আপোনাৰ Android ডিভাইচত গৃহ স্ক্ৰীনৰ ঠাই লয় আৰু আপোনাক নিজৰ ডিভাইচৰ সমল আৰু সুবিধাবোৰৰ এক্সেছ দিয়ে"</string>
<string name="role_home_request_title" msgid="738136983453341081">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ ডিফ’ল্ট হ’ম এপ্ হিচাপে ছেট কৰিবনে?"</string>
<string name="role_home_request_description" msgid="2658833966716057673">"কোনো অনুমতিৰ প্ৰয়োজন নাই"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"টোকা লোৱা এপ্‌"</string>
<string name="role_notes_description" msgid="8496852798616883551">"আপোনাক আপোনাৰ ডিভাইচত টোকা ল’বলৈ দিয়া এপ্‌সমূহ"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"টোকা"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"বৰ্তমানৰ ডিফ’ল্ট"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"পুনৰায় নুসুধিব"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ডিফ’ল্ট ৰূপে ছেট কৰক"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"সহায়কৰ ট্ৰিগাৰ চিনাক্তকৰণ দেখুৱাওক"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"ভইচ এছিষ্টেণ্ট সক্ৰিয় কৰিবলৈ মাইক্ৰফ’ন ব্যৱহাৰ কৰিলে স্থিতি দণ্ডত দেখুৱাওক"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ ডিভাইচত থকা ফট’ আৰু মিডিয়া চাবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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>ৰ অৱস্থান এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"এই এপ্‌টোৱে সকলো সময়তে আপোনাৰ অৱস্থান এক্সেছ কৰিবলৈ বিচাৰিব পাৰে, আনকি আপুনি এপ্‌টো ব্যৱহাৰ কৰি নথকা সময়তো। "<annotation id="link">"ছেটিঙত অনুমতি দিয়ক।"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ৰ বাবে অৱস্থানৰ এক্সেছ সলনি কৰিবনে?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"এই এপ্‌টোৱে সকলো সময়তে আপোনাৰ অৱস্থান এক্সেছ কৰিবলৈ বিচাৰে, আনকি আপুনি এপ্‌টো ব্যৱহাৰ কৰি নথকা সময়তো। "<annotation id="link">"ছেটিঙত অনুমতি দিয়ক।"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক বিচাৰিবলৈ, সংযোগ কৰিবলৈ আৰু নিকটৱৰ্তী ডিভাইচৰ আপেক্ষিক স্থান নিৰ্ধাৰণ কৰিবলৈ দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত নিকটৱৰ্তী ডিভাইচসমূহ বিচাৰিবলৈ, সংযোগ কৰিবলৈ আৰু সেইসমূহৰ প্ৰাসংগিক অৱস্থান নিৰ্ধাৰণ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক বিচাৰিবলৈ, সংযোগ কৰিবলৈ আৰু নিকটৱৰ্তী ডিভাইচৰ আপেক্ষিক স্থান নিৰ্ধাৰণ কৰিবলৈ দিবনে? "<annotation id="link">"ছেটিঙত অনুমতি প্ৰদান কৰক।"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>ৰ অৱস্থানৰ এক্সেছ আনুমানিকৰ পৰা সঠিকলৈ সলনি কৰিবনে?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>ৰ অৱস্থানৰ এক্সেছ আনুমানিকৰ পৰা সঠিকলৈ সলনি কৰিবনে?"</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%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;ক এছএমএছ বাৰ্তা পঠিয়াবলৈ আৰু চাবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত থকা ফট’ মিডিয়া আৰু ফাইল এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক এই ডিভাইচটোত থকা &lt;b&gt;ফট’, ভিডিঅ’, সংগীত আৰু অডিঅ’&lt;/b&gt; এক্সেছ কৰিবলৈ দিবনে?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক এই ডিভাইচটোত থকা &lt;b&gt;ফট’, ভিডিঅ’, সংগীত, অডিঅ’ আৰু অন্য ফাইল&lt;/b&gt; এক্সেছ কৰিবলৈ দিবনে?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক এই ডিভাইচটোত থকা সংগীত আৰু অডিঅ’ এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত থকা সংগীত আৰু অডিঅ’ এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক এই ডিভাইচটোত থকা ফট’ আৰু ভিডিঅ’ এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত থকা ফট’ আৰু ভিডিঅ’ এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক এই ডিভাইচটোত থকা অধিক ফট’ আৰু ভিডিঅ’ এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত থকা অধিক ফট’ আৰু ভিডিঅ’ এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক অডিঅ\' ৰেকৰ্ড কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত অডিঅ’ ৰেকৰ্ড কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"আপুনি এই এপ্‌টো ব্যৱহাৰ কৰি থকাৰ সময়তহে কেৱল ই অডিঅ’ ৰেকৰ্ড কৰিব পাৰিব"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক অডিঅ’ ৰেকৰ্ড কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত অডিঅ’ ৰেকৰ্ড কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"এই এপ্‌টোৱে সকলো সময়তে অডিঅ’ ৰেকৰ্ড কৰিবলৈ বিচাৰিব পাৰে, আনকি আপুনি এপ্‌টো ব্যৱহাৰ কৰি নথকাৰ সময়তো। "<annotation id="link">"ছেটিঙত অনুমতি দিয়ক।"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ৰ বাবে মাই’ক্ৰ’নৰ এক্সেছ সলনি কৰিবনে?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"এই এপ্‌টোৱে সকলো সময়তে অডিঅ’ ৰেকৰ্ড কৰিবলৈ বিচাৰিছে, আনকি আপুনি এপ্‌টো ব্যৱহাৰ কৰি নথকাৰ সময়তো। "<annotation id="link">"ছেটিঙত অনুমতি দিয়ক।"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"আপোনাৰ শাৰীৰিক কাৰ্যকলাপ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক এক্সেছ কৰাৰ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত আপোনাৰ শাৰীৰিক কাৰ্যকলাপ এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক ছবি তুলিবলৈ আৰু ভিডিঅ\' ৰেকৰ্ড কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত ফট’ তুলিবলৈ আৰু ভিডিঅ’ ৰেকৰ্ড কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"আপুনি এই এপ্‌টো ব্যৱহাৰ কৰি থকাৰ সময়তহে কেৱল ই ফট’ তুলিবলৈ আৰু ভিডিঅ’ ৰেকৰ্ড কৰিব পাৰিব।"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক ফট’ তুলিবলৈ আৰু ভিডিঅ’ ৰেকৰ্ড কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত ফট’ তুলিবলৈ আৰু ভিডিঅ’ ৰেকৰ্ড কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"এই এপ্‌টোৱে সকলো সময়তে ফট’ তুলিবলৈ আৰু ভিডিঅ’ ৰেকৰ্ড কৰিবলৈ বিচাৰিব পাৰে, আনকি আপুনি এপ্‌টো ব্যৱহাৰ কৰি নথকাৰ সময়তো। "<annotation id="link">"ছেটিঙত অনুমতি দিয়ক।"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ৰ বাবে কেমেৰাৰ এক্সেছ সলনি কৰিবনে?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"এই এপ্‌টোৱে সকলো সময়তে ফট’ তুলিবলৈ আৰু ভিডিঅ’ ৰেকৰ্ড কৰিবলৈ বিচাৰিছে, আনকি আপুনি এপ্‌টো ব্যৱহাৰ কৰি নথকাৰ সময়তো। "<annotation id="link">"ছেটিঙত অনুমতি দিয়ক।"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ ফ\'ন কল লগ চাবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত আপোনাৰ ফ’নৰ কল লগ এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক ফ\'ন কল কৰিবলৈ আৰু পৰিচালনা কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত ফ’ন কল কৰিবলৈ আৰু পৰিচালনা কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ অৱস্থাৰ বিষয়ে ছেন্সৰৰ ডেটা লাভ কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ বিষয়ে ছেন্সৰৰ ডেটা এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"এই এপ্‌টোৱে সকলো সময়তে আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগৰ বিষয়ে ছেন্সৰৰ ডেটাৰ এক্সেছ বিচাৰে, আনকি আপুনি এপ্‌টো ব্যৱহাৰ কৰি নথকাৰ সময়তো। এই সালসলনিটো কৰিবলৈ, "<annotation id="link">"ছেটিঙলৈ যাওক।"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ অৱস্থাৰ বিষয়ে ছেন্সৰৰ ডেটাৰ এক্সেছ পাবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ বিষয়ে ছেন্সৰৰ ডেটা এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"এই এপ্‌টোক আপুনি এইটো ব্যৱহাৰ কৰি নথকা সময়কো ধৰি সকলো সময়তে শৰীৰৰ ছেন্সৰৰ ডেটা এক্সেছ কৰিবলৈ দিবলৈ, "<annotation id="link">"ছেটিঙলৈ যাওক।"</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"এপ্‌টো ব্যৱহাৰ কৰি থকাৰ সময়ত &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক শৰীৰৰ ছেন্সৰৰ ডেটা এক্সেছ কৰিবলৈ অনুমতি দি থাকিবনে?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"এপ্‌টো ব্যৱহাৰ কৰি থকাৰ সময়ত &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত শৰীৰৰ ছেন্সৰৰ ডেটা এক্সেছ কৰিবলৈ অনুমতি দি থাকিবনে?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনালৈ জাননী পঠিয়াবলৈ অনুমতি দিবনে?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ত আপোনালৈ জাননী পঠিয়াবলৈ অনুমতি দিবনে?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"নিয়ন্ত্ৰিত অনুমতিসমূহ"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ অৱস্থানৰ এক্সেছ আছে"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"আপোনাৰ প্ৰতিষ্ঠানে <xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ অৱস্থান এক্সেছ কৰাৰ অনুমতি দিয়ে"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"এই এপ্‌টোৱে তৃতীয় পক্ষৰ সৈতে অৱস্থানৰ ডেটা শ্বেয়াৰ কৰিব পাৰে বুলি জনাইছে"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ডেটা শ্বেয়াৰ কৰা আৰু অৱস্থান"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ডেটা শ্বেয়াৰ কৰাৰ তথ্যখিনি ক’ৰ পৰা আহে"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"এই এপ্‌টোৱে কেনেকৈ ডেটা শ্বেয়াৰ কৰে সেই বিষয়ে বিকাশকৰ্তাই নিৰ্মাতাক তথ্য দিছে। বিকাশকৰ্তাগৰাকীয়ে এই তথ্যখিনি সময়ৰ লগে লগে আপডে’ট কৰিব পাৰে।"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"এই এপ্‌টোৱে কেনেকৈ ডেটা শ্বেয়াৰ কৰে সেই বিষয়ে বিকাশকৰ্তাই "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"ক তথ্য দিছে। বিকাশকৰ্তাগৰাকীয়ে এই তথ্যখিনি সময়ৰ লগে লগে আপডে’ট কৰিব পাৰে।"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"এপ্‌টোৱে ইয়াৰ বাবে অৱস্থানৰ ডেটা শ্বেয়াৰ কৰিব পাৰে:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ডেটা শ্বেয়াৰ কৰা কার্যটো ভিন্ন হয়"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ডেটা সুৰক্ষা"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"অৱস্থানৰ ডেটা শ্বেয়াৰ কৰা হ’ব পাৰে"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"এই এপ্‌টোৱে তৃতীয় পক্ষৰ সৈতে আপোনাৰ অৱস্থানৰ ডেটা শ্বেয়াৰ কৰিব পাৰে বুলি জনাইছে"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"এই লিংকটো খুলিব নোৱাৰি"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"অৱস্থানৰ বাবে ডেটা শ্বেয়াৰ কৰাৰ আপডে’ট"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"আপোনাৰ অৱস্থানৰ ডেটা শ্বেয়াৰ কৰিব পৰাৰ ধৰণসমূহ সলনি কৰা এপ্‌সমূহ পৰ্যালোচনা কৰক"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"এই এপ্‌সমূহে আপোনাৰ অৱস্থানৰ ডেটা শ্বেয়াৰ কৰিব পৰাৰ ধৰণসমূহ সলনি কৰিছে। সেইবোৰে পূৰ্বে এয়া শ্বেয়াৰ নকৰিব পাৰে অথবা এতিয়া বিজ্ঞাপন অথবা মাৰ্কেটিঙৰ উদ্দেশ্যে শ্বেয়াৰ কৰিব পাৰে।"</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ডেটা শ্বেয়াৰ কৰা সম্পৰ্কীয় আপডে’ট"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"কিছুমান এপে আপোনাৰ অৱস্থানৰ ডেটা শ্বেয়াৰ কৰিব পৰাৰ ধৰণসমূহ সলনি কৰিছে"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ছেটিং"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g>ত এক্সেছ কৰিছিল"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"কালি <xliff:g id="TIME_DATE">%1$s</xliff:g>ত এক্সেছ কৰিছিল"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>ত এক্সেছ কৰিছিল"</string>
</resources>
diff --git a/PermissionController/res/values-az-v33/strings.xml b/PermissionController/res/values-az-v33/strings.xml
index c14a9cf99..da3e73e74 100644
--- a/PermissionController/res/values-az-v33/strings.xml
+++ b/PermissionController/res/values-az-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Daha çox siqnal"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Qapadılmış xəbərdarlıqlar"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Genişləndirin və daha bir xəbərdarlığa baxın}other{Genişləndirin və daha # xəbərdarlığa baxın}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Xəbərdarlıq. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Əməliyyat tamamlandı"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Cihazınıza qoruma əlavə edə biləcək ayarları yoxlayın"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Güvənlik və məxfilik sürətli ayarları"</string>
diff --git a/PermissionController/res/values-az/strings.xml b/PermissionController/res/values-az/strings.xml
index ee102d1ad..9ba86f9d6 100644
--- a/PermissionController/res/values-az/strings.xml
+++ b/PermissionController/res/values-az/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Ətraflı məlumat"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Hamısına icazə verin"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Həmişə hamısına icazə verin"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Məhdud girişə icazə verin"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Foto və videolar seçin"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Digərlərini seçin"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Daha seçməyin"</string>
@@ -41,7 +42,7 @@
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"İmtina edin"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə <xliff:g id="ACTION">%2$s</xliff:g> fəaliyyəti üçün icazə verilsin?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin <xliff:g id="ACTION">%2$s</xliff:g> əməliyyatına daima icazə verilsin?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin <xliff:g id="ACTION">%2$s</xliff:g> fəaliyyətinə hər zaman icazə verilsin?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Ancaq tətbiq istifadəsi zamanı"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Həmişə"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"İcazə verməyin və bir daha soruşmayın"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Tətbiq"</string>
<string name="app_permissions" msgid="3369917736607944781">"Tətbiq icazələri"</string>
<string name="unused_apps" msgid="2058057455175955094">"İşlədilməyən tətbiqlər"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Bu tətbiq üçün seçilmiş fotoları redaktə edin"</string>
<string name="no_unused_apps" msgid="12809387670415295">"İstifadə olunmayan tətbiq yoxdur"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 istifadə olunmayan tətbiq"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Son icazə qərarları"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Bütün icazələr"</string>
<string name="other_permissions" msgid="2901186127193849594">"Digər tətbiq imkanları"</string>
<string name="permission_request_title" msgid="8790310151025020126">"İcazə sorğusu"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Yükləmə/Sistemdən silmə fəaliyyətləri Wear\'də dəstəklənmir."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin daxil olacağı elementləri seçin"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; güncəlləndi. Bu tətbiqin daxil olacağı elementləri seçin."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Ləğv edin"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Tətbiq işlənməyəndə icazə ləğv edilsin"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"İcazələri silin və yer boşaldın"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"İstifadə edilmədikdə tətbiq fəaliyyətini durdurun"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"İstifadə edilmədikdə tətbiqi idarə edin"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"İcazələri silin, müvəqqəti faylları silin və bildirişləri dayandırın"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"İcazələri, müvəqqəti faylları silin, bildirişləri dayandırın və tətbiqi arxivə atın"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Bir neçə ay istifadə etmədiyiniz tətbiqlərdən icazələr datanızın qorunması məqsədilə silinib."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Bir neçə ay istifadə etmədiyiniz tətbiqlərdən icazələr datanızın qorunması məqsədilə silinib: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Bir neçə ay istifadə etmədiyiniz tətbiqlərdən icazələr datanızın qorunması məqsədilə silinib."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Qeyd tətbiqi"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Cihazınızda qeydlər aparmağa imkan verən tətbiqlər"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"qeydlər"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Cari defolt"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Bir daha soruşmayın"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Defolt olaraq seçin"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Assistent aktivasiya aşkarlanmasını göstərin"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mikrofonun istifadəsi zamanı səsli yardımı aktiv etmək üçün status panelində ikonanı göstərin"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin cihazdakı foto və mediaya daxil olmasına icazə verilsin?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında foto və mediaya giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə kontaktlara daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında kontaktlara giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə bu cihazın məkanına daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt; məkanına giriş icazəsi verilsin?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Tətbiq yalnız ondan istifadə etiyiniz zaman məkanı əldə edə bilər"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə bu cihazın məkanına daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> məkanına giriş icazəsi verilsin?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Bu tətbiq hətta ondan istifadə etmədiyiniz zaman belə məkanınıza daxil olmaq istəyə bilər. "<annotation id="link">"Ayarlarda icazə verin."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; üçün məkana giriş dəyişdirilsin?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; üçün məkana giriş dəyişilsin?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Bu tətbiq hətta ondan istifadə etmədiyiniz zaman belə məkanınıza daxil olmaq istəyir. "<annotation id="link">"Ayarlarda icazə verin."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə yaxınlıqdakı cihazları tapmaq, qoşulmaq və nisbi mövqeyini təyin etmək icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında yaxınlıqdakı cihazların nisbi yerini tapıb, təyin edib, qoşulsun?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə yaxınlıqdakı cihazları tapmaq, qoşulmaq və nisbi mövqeyini təyin etmək icazəsi verilsin? "<annotation id="link">"Ayarlarda icazə verin."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> tətbiqinin məkan girişi təxminidən dəqiqə dəyişdirilsin?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> tətbiqinin məkana girişi təxminidən dəqiqə dəyişilsin?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə bu cihazın təxmini məkanına daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazının təxmini məkanına giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Dəqiq"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Təxmini"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə təqvimə daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında təqvimə giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə SMS mesajları göndərmək və onlara baxmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında SMS mesajı göndərmək, onlara baxmaq icazəsi verilsin?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə cihazdakı foto, media və fayllara daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında foto, media və fayllara giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin bu cihazdakı &lt;b&gt;foto, video, musiqi və audiolara&lt;/b&gt; girişinə icazə verilsin?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin bu cihazdakı &lt;b&gt;foto, video, musiqi, audio və digər fayllara&lt;/b&gt; girişinə icazə verilsin?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə bu cihazdakı musiqi və audioya girişinə icazə verilsin?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında musiqi və audioya giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin cihazdakı foto və videolara girişinə icazə verilsin?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında foto və videolara giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə bu cihazda digər foto və videolara daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında digər foto və videolara giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə səs yazmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında audio yazmaq icazəsi verilsin?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Tətbiq yalnız ondan istifadə etiyiniz zaman audio yaza biləcək"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə audio yazmaq icazəsi verilsin?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında audio yazmaq icazəsi verilsin?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Bu tətbiq hətta ondan istifadə etmədiyiniz zaman belə audio yazmaq istəyə bilər. "<annotation id="link">"Ayarlarda icazə verin."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; üçün mikrofona giriş dəyişdirilsin?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; üçün mikrofona giriş dəyişilsin?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Bu tətbiq hətta ondan istifadə etmədiyiniz zaman belə audio yazmaq istəyir. "<annotation id="link">"Ayarlarda icazə verin."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin fiziki fəaliyyətinizə daxil olmasına icazə verilsin?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında fiziki fəaliyyətə giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə şəkil və video çəkmək icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında şəkil və video çəkmək icazəsi verilsin?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Tətbiq yalnız ondan istifadə etiyiniz zaman şəkil çəkə və video yaza biləcək"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə şəkil çəkmək və video yazmaq icazəsi verilsin?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında şəkil və video çəkmək icazəsi verilsin?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Bu tətbiq hətta ondan istifadə etmədiyiniz zaman belə şəkil çəkmək və video yazmaq istəyə bilər. "<annotation id="link">"Ayarlarda icazə verin."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; üçün kameraya giriş dəyişdirilsin?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında kameraya girişi dəyişilsin?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Bu tətbiq hətta ondan istifadə etmədiyiniz zaman belə şəkil çəkmək və video yazmaq istəyir. "<annotation id="link">"Ayarlarda icazə verin."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə telefonun zəng qeydlərinə daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında telefon zəngi qeydlərinə giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə telefon zəngləri etmək və onları idarə etmək icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında telefon zəngi etmək, idarə etmək icazəsi verilsin?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə həyati əlamətlər haqqında sensor dataya daxil olmaq icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; üçün &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında həyati göstəricilər üzrə sensor datasına giriş icazəsi verilsin?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Bu tətbiq hər zaman, hətta ondan istifadə etmədiyiniz zaman belə sağlamlıq göstəriciləriniz haqqında sensor datasına giriş etmək istəyir. Bu dəyişikliyi etmək üçün "<annotation id="link">"ayarlara keçin"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə sağlamlıq göstəriciləriniz haqqında sensor datasına giriş icazəsi verilsin?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; üçün &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında həyati göstəricilər üzrə sensor datasına giriş icazəsi verilsin?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Tətbiqdən istifadə etmədiyiniz zaman belə, bu tətbiqin bədən sensoru datasına hər zaman giriş etməsinə icazə vermək üçün "<annotation id="link">"ayarlara keçin."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinin istifadə zamanı bədən sensoru datasına giriş etməsinə icazə verilməyə davam edilsin?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; istifadə edilərkən ona &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında bədən sensoru datasına giriş icazəsi verilsin?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə sizə bildiriş göndərmək icazəsi verilsin?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tətbiqinə &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazında bildiriş göndərmək icazəsi verilsin?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"İdarə edilən icazələr"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinin məkan icazəsi var"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Təşkilat <xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinə məkan icazəsi verir"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Digər icazələr"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Sistem tərəfindən istifadə edilən icazə"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Yalnız sistem tətbiqləri tərəfindən istifadə edilən icazələr."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Bu tətbiq məkan datasını üçüncü tərəflərlə paylaşa biləcəyini bildirib"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Data paylaşımı və məkan"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Data paylaşma məlumatı haradan əldə edilir"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Developer bu tətbiqin datanı paylaşması haqqında cihaz istehsalçısına məlumat verib. Developer bu məlumatı vaxtaşırı yeniləyə bilər."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Developer tətbiqin datanı necə paylaşması haqqında məlumatı bu ünvana təqdim edib: "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". Developer bu məlumatı vaxtaşırı yeniləyə bilər."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Tətbiq bunun üçün məkan datasını paylaşa bilər:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Data paylaşma dəyişə bilər"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Data təhlükəsizliyi"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Məkan datası paylaşıla bilər"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Bu tətbiq məkan datasını üçüncü tərəflərlə paylaşa biləcəyini bildirib"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Bu linki açmaq olmur"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Məkan üzrə data paylaşma yenilikləri"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Məkan datasını paylaşma üsulunu dəyişən tətbiqləri nəzərdən keçirin"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Bu tətbiqlər məkan datasını paylaşma üsulunu dəyişib. Ola bilsin ki, onu daha öncə paylaşmayıblar və ya indi reklam, yaxud marketinq məqsədləri üçün paylaşırlar."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Data paylaşma yenilikləri"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Bəzi tətbiqlər məkan datasını paylaşma üsulunu dəyişib"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Ayarlar"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Daxil olunub: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Daxil olunub: dünən <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Daxil olunub: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-b+sr+Latn-v33/strings.xml b/PermissionController/res/values-b+sr+Latn-v33/strings.xml
index c3ec0e10d..acc79ac84 100644
--- a/PermissionController/res/values-b+sr+Latn-v33/strings.xml
+++ b/PermissionController/res/values-b+sr+Latn-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Još obaveštenja"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Odbačena obaveštenja"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Proširite i vidite još jedno obaveštenje}one{Proširite i vidite još # obaveštenje}few{Proširite i vidite još # obaveštenja}other{Proširite i vidite još # obaveštenja}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Obaveštenje. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Radnja je dovršena"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Proverite podešavanja koja mogu da dodaju zaštitu uređaju"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Brza podešavanja bezbednosti i privatnosti"</string>
diff --git a/PermissionController/res/values-b+sr+Latn/strings.xml b/PermissionController/res/values-b+sr+Latn/strings.xml
index f66592c90..f612261b4 100644
--- a/PermissionController/res/values-b+sr+Latn/strings.xml
+++ b/PermissionController/res/values-b+sr+Latn/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Više informacija"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Dozvoli sve"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Uvek dozvoli sve"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Dozvoli ograničen pristup"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Izaberite slike i video snimke"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Izaberite još"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ne biraj više"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ništa više"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ionako ne dozvoli"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Odbaci"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> od <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikacije"</string>
<string name="app_permissions" msgid="3369917736607944781">"Dozvole za aplikacije"</string>
<string name="unused_apps" msgid="2058057455175955094">"Aplikacije koje se ne koriste"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Menjaj izabrane slike za ovu aplikaciju"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nema aplik. koje se ne koriste"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 aplikac. koje se ne koriste"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nedavne odluke o dozvolama"</string>
@@ -93,7 +95,7 @@
<string name="location_warning" msgid="2381649060929040962">"<xliff:g id="APP_NAME">%1$s</xliff:g> pruža usluge lokacije za ovaj uređaj. Pristup lokaciji možete da izmenite u podešavanjima lokacije."</string>
<string name="system_warning" msgid="1173400963234358816">"Ako odbijete ovu dozvolu, osnovne funkcije uređaja možda neće više ispravno raditi."</string>
<string name="deny_read_media_visual_warning" msgid="3982586279917232827">"Ova aplikacija je dizajnirana za stariju verziju Android-a. Ako ovoj aplikaciji odbijete pristup za slike i video snimke, povlači se i pristup muzici i drugim audio snimcima."</string>
- <string name="deny_read_media_aural_warning" msgid="8928699919508646732">"Ova aplikacija je dizajnirana za stariju verziju Android-a. Ako ovoj aplikaciji odbijete pristup za muziku i druge audio snimke, povlači se i pristup slikama i video snimcima."</string>
+ <string name="deny_read_media_aural_warning" msgid="8928699919508646732">"Ova aplikacija je dizajnirana za stariju verziju Android-a. Ako ovoj aplikaciji odbijete pristup za muziku i druge audio snimke, povlači se i pristup slikama i videima."</string>
<string name="cdm_profile_revoke_warning" msgid="4443893270719106700">"Ako odbijete ovu dozvolu, neke funkcije uređaja kojima upravlja ova aplikacija možda neće više ispravno raditi."</string>
<string name="permission_summary_enforced_by_policy" msgid="4443598170942950519">"Primenjuje se u skladu sa smernicama"</string>
<string name="permission_summary_disabled_by_policy_background_only" msgid="221995005556362660">"Pristup u pozadini je onemogućen smernicama"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Dozvoli uvek"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Dozv. samo dok se apl. koristi"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Dozvoli samo dok se apl. koristi"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Ne dozvoli"</string>
<string name="loading" msgid="4789365003890741082">"Učitava se…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Sve dozvole"</string>
<string name="other_permissions" msgid="2901186127193849594">"Ostale mogućnosti aplikacije"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Zahtev za dozvolu"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Radnje Instaliraj/Deinstaliraj nisu podržane u Wear-u."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Izaberite čemu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; može da pristupa"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; je ažurirana. Izaberite čemu ova aplikacija može da pristupa."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Otkaži"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Ukloni dozvole ako se aplikacija ne koristi"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Ukloni dozvole i oslobodi prostor"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pauziraj aktivnosti ako se ne koristi"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Upravljajte aplikacijom ako se ne koristi"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Uklonite dozvole, izbrišite privremene fajlove i zaustavite obaveštenja"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Uklonite dozvole, izbrišite privremene fajlove, zaustavite obaveštenja i arhivirajte aplikaciju"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Radi zaštite podataka, dozvole za ovu aplikaciju se uklanjaju ako se aplikacija ne koristi par meseci."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Radi zaštite podataka, sledeće dozvole se uklanjaju ako se aplikacija ne koristi par meseci: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Radi zaštite podataka, dozvole su uklonjene iz aplikacija koje niste koristili par meseci."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Poslednji put otvoreno: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ako omogućite upravljanje svim datotekama, ova aplikacija može da pristupa svim datotekama u zajedničkom memorijskom prostoru na ovom uređaju ili povezanim uređajima za skladištenje i da menja i briše te datoteke. Aplikacija može da pristupa datotekama bez pitanja."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Želite li da dozvolite da ova aplikacija pristupa datotekama na uređaju ili svim povezanim uređajima za skladištenje i da menja i briše te datoteke? Ova aplikacija može da pristupa datotekama bez pitanja."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacije sa ovom dozvolom mogu <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacije sa tom dozvolom imaju ove mogućnosti: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Aplikacije sa ovom dozvolom mogu da pristupaju podacima o fizičkim aktivnostima, poput hodanja, vožnje bicikla, vožnje automobila, broja koraka i drugo"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Aplikacije sa ovom dozvolom mogu da pristupaju kalendaru"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Aplikacije sa ovom dozvolom mogu da čitaju i dodaju stavke u evidenciju poziva na telefonu"</string>
@@ -240,7 +242,7 @@
<string name="permission_description_summary_sms" msgid="725999468547768517">"Aplikacije sa ovom dozvolom mogu da šalju i pregledaju SMS-ove"</string>
<string name="permission_description_summary_storage" msgid="6575759089065303346">"Aplikacije sa ovom dozvolom mogu da pristupaju slikama, medijskom sadržaju i fajlovima na uređaju"</string>
<string name="permission_description_summary_read_media_aural" msgid="3354728149930482199">"Aplikacije sa ovom dozvolom mogu da pristupaju muzici i drugim audio fajlovima na ovom uređaju"</string>
- <string name="permission_description_summary_read_media_visual" msgid="4991801977881732641">"Aplikacije sa ovom dozvolom mogu da pristupaju slikama i video snimcima na ovom uređaju"</string>
+ <string name="permission_description_summary_read_media_visual" msgid="4991801977881732641">"Aplikacije sa ovom dozvolom mogu da pristupaju slikama i videima na ovom uređaju"</string>
<string name="app_permission_most_recent_summary" msgid="4292074449384040590">"Poslednji pristup: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"Trenutno odbijeno/poslednji pristup: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"Bez pristupa"</string>
@@ -397,10 +399,20 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i strimovanje aplikacija na povezanom uređaju."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ova usluga deli slike, medijski sadržaj i obaveštenja sa telefona na drugim uređajima."</string>
- <string name="role_notes_label" msgid="7451627001058089536">"Podrazumevana aplik za beleške"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Podrazumevana apl. za beleške"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikacija za beleške"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplikacije koje vam omogućavaju da pravite beleške na uređaju"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"beleške"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Trenutno podrazumevana"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ne pitaj ponovo"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Podesi kao podrazum."</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Prikazuj otkrivanje aktiviranja pomoćnika"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Prikazuje ikonu na statusnoj traci kada se mikrofon koristi za aktiviranje glasovnog pomoćnika"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Želite li da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa slikama i medijima na uređaju?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa slikama i medijima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa kontaktima?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa kontaktima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikacija će imati pristup lokaciji samo dok koristite aplikaciju"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Ova aplikacija možda želi da pristupa lokaciji sve vreme, čak i kada ne koristite aplikaciju. "<annotation id="link">"Dozvolite u podešavanjima."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Želite li da promenite pristup lokaciji za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Menjate pristup lokaciji za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Ova aplikacija želi da pristupa lokaciji sve vreme, čak i kada ne koristite aplikaciju. "<annotation id="link">"Dozvolite u podešavanjima."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pronalazi uređaje u blizini, povezuje se s njima i određuje im relativan položaj?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; može da nalazi uređaje u blizini, povezuje se sa njima i utvrđuje relativni položaj na: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pronalazi uređaje u blizini, povezuje se s njima i određuje im relativan položaj? "<annotation id="link">"Dozvolite u podešavanjima."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Želite li da promenite pristup aplikacije <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> iz približne lokacije na preciznu?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Menjate pristup aplikacije <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; iz približne u preciznu lokaciju?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Želite li da omogućite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa približnoj lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa približnoj lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precizna"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Približna"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa kalendaru?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa kalendaru na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje i pregleda SMS-ove?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje i pregleda SMS poruke na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa slikama, medijskim i drugim fajlovima na uređaju?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa slikama, medijima i fajlovima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Pristup &lt;b&gt;slikama, videu, muzici i zvuku&lt;/b&gt; na uređaju za &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Pristup slikama, videu, muzici, zvuku i drugom na uređaju za &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Dozvoljavate li pristup muzici i zvuku na ovom uređaju za &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa muzici i audio sadržaju na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Dozvoljavate li pristup slikama i videu na ovom uređaju za &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Dozvoljavate li da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa i drugim slikama i video snimcima na ovom uređaju?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa slikama i videima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Dozvoljavate li da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa i drugim slikama i videima na ovom uređaju?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa i drugim slikama i videima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima zvuk?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima audio sadržaj na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikacija će moći da snima zvuk samo dok koristite aplikaciju"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima zvuk?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima audio sadržaj na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Ova aplikacija možda želi da snima zvuk sve vreme, čak i kada ne koristite aplikaciju. "<annotation id="link">"Dozvolite u podešavanjima."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Želite da promenite pristup mikrofonu za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Menjate pristup mikrofonu za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Ova aplikacija želi da snima zvuk sve vreme, čak i kada ne koristite aplikaciju. "<annotation id="link">"Dozvolite u podešavanjima."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Želite li da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa fizičkim aktivnostima?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa podacima o fizičkim aktivnostima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima slike i video snimke?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Dozvolićete da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima slike i video snimke na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikacija će moći da snima slike i video snimke samo dok koristite aplikaciju"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima slike i video snimke?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima slike i video snimke na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Ova aplikacija možda želi da snima slike i video snimke sve vreme, čak i kada ne koristite aplikaciju. "<annotation id="link">"Dozvolite u podešavanjima."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Želite da promenite pristup kameri za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Menjate pristup kameri za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Ova aplikacija želi da snima slike i video snimke sve vreme, čak i kada ne koristite aplikaciju. "<annotation id="link">"Dozvolite u podešavanjima."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa evidencijama poziva na telefonu?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa evidencijama telefonskih poziva na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; upućuje pozive i upravlja njima?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; upućuje telefonske pozive i upravlja njima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Želite da dozvolite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa podacima senzora o vitalnim funkcijama?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa podacima senzora o vitalnim znacima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Ova aplikacija želi da sve vreme pristupa podacima senzora o vitalnim funkcijama, čak i kada ne koristite aplikaciju. Da biste obavili ovu izmenu, "<annotation id="link">"idite u podešavanja."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Želite da omogućite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa podacima senzora o vitalnim funkcijama?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa podacima senzora o vitalnim znacima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Da biste dozvolili ovoj aplikaciji da sve vreme pristupa podacima senzora za telo, čak i kada ne koristite aplikaciju, "<annotation id="link">"idite u podešavanja."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Želite da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; i dalje pristupa podacima senzora za telo dok se aplikacija koristi?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Dozvoljavate da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tokom korišćenja i dalje pristupa podacima senzora za telo na: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Želite da dozvolite da vam &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje obaveštenja?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Dozvoljavate da vam &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje obaveštenja na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontrolisane dozvole"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ima pristup lokaciji"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Organizacija dozvoljava da <xliff:g id="APP_NAME">%1$s</xliff:g> pristupa lokaciji"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Druge dozvole"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Dozvole koje koristi sistem"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Dozvole koje koriste samo sistemske aplikacije."</string>
@@ -560,18 +597,18 @@
<string name="media_confirm_dialog_title_a_to_p_aural_deny" msgid="7841428716317307685">"Ni pristup drugim fajlovima neće biti dozvoljen"</string>
<string name="media_confirm_dialog_title_a_to_p_visual_allow" msgid="6469086448310893751">"Biće dozvoljen pristup i drugim fajlovima"</string>
<string name="media_confirm_dialog_title_a_to_p_visual_deny" msgid="5767849609024384226">"Ni pristup drugim fajlovima neće biti dozvoljen"</string>
- <string name="media_confirm_dialog_title_q_to_s_aural_allow" msgid="3191904399336990537">"Biće dozvoljen pristup i slikama i video snimcima"</string>
- <string name="media_confirm_dialog_title_q_to_s_aural_deny" msgid="3128147568953297969">"Ni pristup slikama i video snimcima neće biti dozvoljen"</string>
+ <string name="media_confirm_dialog_title_q_to_s_aural_allow" msgid="3191904399336990537">"Biće dozvoljen pristup i slikama i videima"</string>
+ <string name="media_confirm_dialog_title_q_to_s_aural_deny" msgid="3128147568953297969">"Ni pristup slikama i videima neće biti dozvoljen"</string>
<string name="media_confirm_dialog_title_q_to_s_visual_allow" msgid="6310682466493330434">"Biće dozvoljen pristup i muzici i audio fajlovima"</string>
<string name="media_confirm_dialog_title_q_to_s_visual_deny" msgid="1123845663785900471">"Ni pristup muzici i audio fajlovima neće biti dozvoljen"</string>
- <string name="media_confirm_dialog_message_a_to_p_aural_allow" msgid="7865167246140107623">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija može da pristupa muzici i audio fajlovima, biće joj dozvoljeno i da pristupa slikama, video snimcima i drugim fajlovima."</string>
- <string name="media_confirm_dialog_message_a_to_p_aural_deny" msgid="287502523664804786">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija ne može da pristupa muzici i audio fajlovima, neće joj biti dozvoljeno ni da pristupa slikama, video snimcima i drugim fajlovima."</string>
- <string name="media_confirm_dialog_message_a_to_p_visual_allow" msgid="4952410892939590487">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija može da pristupa slikama i video snimcima, biće joj dozvoljeno i da pristupa muzici, audio i drugim fajlovima."</string>
- <string name="media_confirm_dialog_message_a_to_p_visual_deny" msgid="6609500525590757681">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija ne može da pristupa slikama i video snimcima, neće joj biti dozvoljeno ni da pristupa muzici, audio i drugim fajlovima."</string>
- <string name="media_confirm_dialog_message_q_to_s_aural_allow" msgid="1702402580147536160">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija može da pristupa muzici i audio fajlovima, biće joj dozvoljeno i da pristupa slikama i video snimcima."</string>
- <string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija ne može da pristupa muzici i audio fajlovima, neće joj biti dozvoljeno ni da pristupa slikama i video snimcima."</string>
- <string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija može da pristupa slikama i video snimcima, biće joj dozvoljeno i da pristupa muzici i audio fajlovima."</string>
- <string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija ne može da pristupa muzici i audio fajlovima, neće joj biti dozvoljeno ni da pristupa slikama i video snimcima."</string>
+ <string name="media_confirm_dialog_message_a_to_p_aural_allow" msgid="7865167246140107623">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija može da pristupa muzici i audio fajlovima, biće joj dozvoljeno i da pristupa slikama, videima i drugim fajlovima."</string>
+ <string name="media_confirm_dialog_message_a_to_p_aural_deny" msgid="287502523664804786">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija ne može da pristupa muzici i audio fajlovima, neće joj biti dozvoljeno ni da pristupa slikama, videima i drugim fajlovima."</string>
+ <string name="media_confirm_dialog_message_a_to_p_visual_allow" msgid="4952410892939590487">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija može da pristupa slikama i videima, biće joj dozvoljeno i da pristupa muzici, audio i drugim fajlovima."</string>
+ <string name="media_confirm_dialog_message_a_to_p_visual_deny" msgid="6609500525590757681">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija ne može da pristupa slikama i videima, neće joj biti dozvoljeno ni da pristupa muzici, audio i drugim fajlovima."</string>
+ <string name="media_confirm_dialog_message_q_to_s_aural_allow" msgid="1702402580147536160">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija može da pristupa muzici i audio fajlovima, biće joj dozvoljeno i da pristupa slikama i videima."</string>
+ <string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija ne može da pristupa muzici i audio fajlovima, neće joj biti dozvoljeno ni da pristupa slikama i videima."</string>
+ <string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija može da pristupa slikama i videima, biće joj dozvoljeno i da pristupa muzici i audio fajlovima."</string>
+ <string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ova aplikacija ne podržava najnoviju verziju Android-a. Ako ova aplikacija ne može da pristupa muzici i audio fajlovima, neće joj biti dozvoljeno ni da pristupa slikama i videima."</string>
<string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Pregledajte aplikaciju sa pristupom lokaciji u pozadini"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> uvek može da pristupa vašoj lokaciji, čak i kad je aplikacija zatvorena"</string>
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Pregledajte aplikaciju sa pristupom lokaciji u pozadini"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Ova aplikacija navodi da može da deli podatke sa trećim stranama"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Deljenje podataka i lokacija"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Odakle informacije o deljenju podataka potiču"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Programer je naveo informacije proizvođaču ovog uređaja o tome kako ova aplikacija deli podatke. Programer može vremenom da ažurira ove podatke."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Programer je naveo informacije o tome kako ova aplikacija deli podatke za:"<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". Programer može vremenom da ažurira ove podatke."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Ova aplikacija može da deli podatke o lokaciji za:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Deljenje podataka varira"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Bezbednost podataka"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Podaci o lokaciji mogu da se dele"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Ova aplikacija navodi da može da deli podatke o lokaciji sa trećim stranama"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Ne možemo da otvorimo ovaj link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Ažuriranja deljenja podataka za lokaciju"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Pregledajte aplikacije koje su promenile način na koji mogu da dele podatke o lokaciji"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Aplikacije su promenile način na koji mogu da dele podatke o lokaciji. Možda ih nisu delile ranije ili ih sada dele u svrhe oglašavanja ili marketinga."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Ažuriranja za deljenje podataka"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Neke aplikacije su promenile način na koji mogu da dele podatke o lokaciji"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Podešavanja"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Pristupano: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Pristupano juče: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Pristupano: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-be-v33/strings.xml b/PermissionController/res/values-be-v33/strings.xml
index 9d5fbc9af..511ed49c6 100644
--- a/PermissionController/res/values-be-v33/strings.xml
+++ b/PermissionController/res/values-be-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Іншыя абвесткі"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Адхіленыя абвесткі"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Разгарніце, каб убачыць яшчэ адну абвестку}one{Разгарніце, каб убачыць яшчэ # абвестку}few{Разгарніце, каб убачыць яшчэ # абвесткі}many{Разгарніце, каб убачыць яшчэ # абвестак}other{Разгарніце, каб убачыць яшчэ # абвесткі}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Абвестка. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Дзеянне завершана"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Праверце налады, якія могуць павысіць бяспеку вашай прылады"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Хуткія налады бяспекі і прыватнасці"</string>
diff --git a/PermissionController/res/values-be/strings.xml b/PermissionController/res/values-be/strings.xml
index fa54a396b..cd3e43197 100644
--- a/PermissionController/res/values-be/strings.xml
+++ b/PermissionController/res/values-be/strings.xml
@@ -34,13 +34,14 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Падрабязней"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Дазволіць усе"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Заўсёды дазваляць усе"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Дазволіць абмежаваны доступ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Выбраць фота і відэа"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Яшчэ"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Больш не выбіраць"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Усё роўна не дазваляць"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Адхіліць"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> з <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Дазволіць &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="permission_add_background_warning_template" msgid="1812914855915092273">"Заўсёды дазваляць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Толькі пры актыўнай праграме"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Заўсёды"</string>
@@ -49,17 +50,18 @@
<string name="permission_revoked_all" msgid="3397649017727222283">"усе адключаны"</string>
<string name="permission_revoked_none" msgid="9213345075484381180">"няма адключаных"</string>
<string name="grant_dialog_button_allow" msgid="5314677880021102550">"Дазволіць"</string>
- <string name="grant_dialog_button_allow_always" msgid="4485552579273565981">"Дазволіць заўсёды"</string>
+ <string name="grant_dialog_button_allow_always" msgid="4485552579273565981">"Дазваляць заўсёды"</string>
<string name="grant_dialog_button_allow_foreground" msgid="501896824973636533">"Падчас выкарыстання праграмы"</string>
<string name="grant_dialog_button_change_to_precise_location" msgid="3273115879467236033">"Пераключыцца на дакладнае вызначэнне месцазнаходжання"</string>
<string name="grant_dialog_button_keey_approximate_location" msgid="438025182769080011">"Пакінуць прыблізнае месцазнаходжанне"</string>
<string name="grant_dialog_button_allow_one_time" msgid="2618088516449706391">"Толькі ў гэты раз"</string>
- <string name="grant_dialog_button_allow_background" msgid="8236044729434367833">"Дазволіць заўсёды"</string>
+ <string name="grant_dialog_button_allow_background" msgid="8236044729434367833">"Дазваляць заўсёды"</string>
<string name="grant_dialog_button_allow_all_files" msgid="4955436994954829894">"Дазволіць кіраванне ўсімі файламі"</string>
<string name="grant_dialog_button_allow_media_only" msgid="4832877658422573832">"Дазволіць доступ да файлаў мультымедыя"</string>
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Праграмы"</string>
<string name="app_permissions" msgid="3369917736607944781">"Дазволы праграмы"</string>
<string name="unused_apps" msgid="2058057455175955094">"Праграмы, якія не выкарыстоўваюцца"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Змяніць спіс фота, да якіх гэта праграма мае доступ"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Няма нескарыстаных праграм"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 праграм не ў карыстанні"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Нядаўнія рашэнні наконт дазволаў"</string>
@@ -107,15 +109,13 @@
<!-- no translation found for background_access_chooser_dialog_choices:0 (1351721623256561996) -->
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
- <string name="permission_access_always" msgid="1474641821883823446">"Дазволіць заўсёды"</string>
+ <string name="permission_access_always" msgid="1474641821883823446">"Дазваляць заўсёды"</string>
<string name="permission_access_only_foreground" msgid="7801170728159326195">"Падчас карыстання праграмай"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Не дазваляць"</string>
<string name="loading" msgid="4789365003890741082">"Загрузка…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Усе дазволы"</string>
<string name="other_permissions" msgid="2901186127193849594">"Іншыя магчымасці праграмы"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Запыт дазволу"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Дзеянні па ўсталяванні або выдаленні не падтрымліваюцца на Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Выберыце, да чаго дазволіць доступ праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Праграма &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; была абноўлена. Выберыце, да чаго ёй дазволіць доступ."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Скасаваць"</string>
@@ -186,8 +186,8 @@
<string name="app_permission_button_allow" msgid="5808039516494774647">"Дазволіць"</string>
<string name="app_permission_button_allow_all_files" msgid="1792232272599018825">"Дазволіць кіраванне ўсімі файламі"</string>
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Дазволіць доступ толькі да мультымедыя"</string>
- <string name="app_permission_button_allow_always" msgid="4573292371734011171">"Дазволіць заўсёды"</string>
- <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Дазволіць толькі падчас карыстання праграмай"</string>
+ <string name="app_permission_button_allow_always" msgid="4573292371734011171">"Дазваляць заўсёды"</string>
+ <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Дазваляць толькі падчас карыстання праграмай"</string>
<string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Заўсёды дазваляць усе"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Заўсёды пытацца"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Не дазваляць"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Выдаляць дазволы, калі праграма не выкарыстоўваецца"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Выдаліць дазволы і вызваліць месца"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Прыпыніць дзеянні ў неактыўнай праграме"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Кіраваць праграмай, якой не карыстаюцца"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Выдаліць дазволы, часовыя файлы і спыніць апавяшчэнні"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Выдаліць дазволы і часовыя файлы, спыніць адпраўку апавяшчэнняў і архіваваць праграму"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Калі праграма не выкарыстоўваецца на працягу некалькіх месяцаў, то ў мэтах абароны вашых даных з яе будуць выдалены дазволы."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Калі праграма не выкарыстоўваецца на працягу некалькіх месяцаў, у мэтах абароны вашых даных будуць выдалены наступныя дазволы: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"У мэтах абароны вашых даных выдалены дазволы для праграм, якія не выкарыстоўваліся некалькі месяцаў."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Адкрывалася ў апошні раз <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Калі вы дазволіце кіраванне ўсімі файламі, гэта праграма зможа атрымліваць доступ да ўсіх файлаў у агульным сховішчы на гэтай прыладзе ці ў сховішчах падключаных прылад, а таксама змяняць і выдаляць гэтыя файлы. Праграма зможа атрымліваць доступ да файлаў без вашага ведама."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Дазволіць гэтай праграме атрымліваць доступ да файлаў на гэтай прыладзе і ў любых падключаных сховішчах, а такама змяняць і выдаляць файлы? Гэта праграма зможа атрымліваць доступ да файлаў без вашага ведама."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Характарыстыка дазволу: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Праграмы з гэтым дазволам могуць <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Праграмы з такім дазволам могуць мець доступ да звестак пра вашу фізічную актыўнасць, напрыклад перамяшчэнні пешшу, язду на веласіпедзе, на аўтамабілі, колькасць крокаў і многае іншае"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Праграмы з гэтым дазволам могуць мець доступ да календара"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Праграмы з гэтым дазволам могуць чытаць журнал выклікаў тэлефона і дадаваць у яго запісы"</string>
@@ -251,7 +253,7 @@
<string name="allowed_storage_scoped" msgid="5383645873719086975">"Дазволены доступ толькі да мультымедыя"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"Дазволена кіраванне ўсімі файламі"</string>
<string name="ask_header" msgid="2633816846459944376">"Заўсёды пытацца"</string>
- <string name="denied_header" msgid="903209608358177654">"Забаронена"</string>
+ <string name="denied_header" msgid="903209608358177654">"Забароненыя"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Праглядзець іншыя праграмы, якія маюць доступ да ўсіх файлаў"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 дзень}one{# дзень}few{# дні}many{# дзён}other{# дня}}"</string>
<string name="hours" msgid="7302866489666950038">"{count,plural, =1{# гадзіна}one{# гадзіна}few{# гадзіны}many{# гадзін}other{# гадзіны}}"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Праграма для нататак"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Праграмы, якія дазваляюць рабіць нататкі на прыладзе"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"нататкі"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Цяперашняя стандартная"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Больш не пытацца"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Зрабіць стандартнай"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Паказваць значок актывацыі памочніка"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Паказваць значок на панэлі стану, калі мікрафон выкарыстоўваецца для актывацыі галасавога памочніка"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да фота і мультымедыя на вашай прыладзе?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да фота і мультымедыя на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да кантактаў на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"Дазволіць праграме &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>’s&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Дазволіць праграме &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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Гэта праграма можа запытваць пастаянны доступ да звестак пра ваша месцазнаходжанне, нават калі яна не выкарыстоўваецца. "<annotation id="link">"Дайце дазвол у наладах."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Змяніць налады доступу да даных пра месцазнаходжанне для праграмы &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Змяніць для праграмы &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; налады доступу да даных пра месцазнаходжанне на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Гэта праграма запытвае пастаянны доступ да звестак пра ваша месцазнаходжанне, нават калі яна не выкарыстоўваецца. "<annotation id="link">"Дайце дазвол у наладах."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; знаходзіць прылады паблізу, падключацца да іх і вызначаць адлегласць да іх?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; знаходзіць прылады паблізу, падключацца да іх і вызначаць іх адноснае месцазнаходжанне на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; знаходзіць прылады паблізу, падключацца да іх і вызначаць адлегласць да такіх прылад? "<annotation id="link">"Дазволіць у наладах."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Памяняць у доступах праграмы \"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>\" прыблізнае месцазнаходжанне на дакладнае?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Дазволіць праграме \"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>\" доступ да даных пра дакладнае месцазнаходжанне прылады &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да даных пра прыблізнае месцазнаходжанне прылады &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да календара на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; адпраўляць і праглядаць SMS-паведамленні на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да фота, мультымедыя і файлаў на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да &lt;b&gt;фота, відэа, музыкі і аўдыяфайлаў&lt;/b&gt; на гэтай прыладзе?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да &lt;b&gt;фота, відэа, музыкі, аўдыя і файлаў&lt;/b&gt; на гэтай прыладзе?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да музыкі і аўдыя на гэтай прыладзе?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да музыкі і аўдыя на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да фота і відэа на гэтай прыладзе?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да фота і відэа на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да дадатковых фота і відэа на гэтай прыладзе?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да іншых фота і відэа на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; запісваць аўдыя?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; запісваць аўдыя на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Гэта праграма зможа запісваць аўдыя толькі падчас яе выкарыстання"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; запісваць аўдыя?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; запісваць аўдыя на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Гэта праграма можа запісваць аўдыя ўвесь час, нават калі яна не выкарыстоўваецца. "<annotation id="link">"Дайце дазвол у наладах."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Змяніць налады доступу да мікрафона для праграмы &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Змяніць для праграмы &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; налады доступу да мікрафона на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Гэта праграма запытвае дазвол запісваць аўдыя ўвесь час, нават калі яна не выкарыстоўваецца. "<annotation id="link">"Дайце дазвол у наладах."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да даных фізічнай актыўнасці?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да даных аб фізічнай актыўнасці на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; рабіць фота і запісваць відэа?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; знімаць фота і відэа на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Гэта праграма зможа рабіць фота і запісваць відэа толькі падчас яе выкарыстання"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; рабіць фота і запісваць відэа?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; знімаць фота і відэа на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Гэта праграма можа рабіць фота і запісваць відэа ўвесь час, нават калі яна не выкарыстоўваецца. "<annotation id="link">"Дайце дазвол у наладах."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Змяніць налады доступу да камеры для праграмы &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Змяніць для праграмы &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; налады доступу да камеры на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Гэта праграма запытвае дазвол рабіць фота і запісваць відэа ўвесь час, нават калі яна не выкарыстоўваецца. "<annotation id="link">"Дайце дазвол у наладах."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да журналаў выклікаў вашага тэлефона?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да журналаў тэлефонных выклікаў на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; рабіць тэлефонныя выклікі і кіраваць імі?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; рабіць тэлефонныя выклікі і кіраваць імі на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да даных з датчыкаў пра вашы асноўныя фізіялагічныя паказчыкі?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да даных датчыкаў з паказчыкамі арганізма на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Гэта праграма запытвае пастаянны доступ да даных датчыкаў з паказчыкамі вашага арганізма, нават калі яна не выкарыстоўваецца. Каб змяніць дазвол, "<annotation id="link">"перайдзіце ў налады"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да даных датчыкаў з паказчыкамі вашага арганізма?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ да даных датчыкаў з паказчыкамі арганізма на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Каб дазволіць гэтай праграме мець пастаянны доступ да даных датчыкаў цела, нават калі яна не выкарыстоўваецца, "<annotation id="link">"перайдзіце ў налады."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Захаваць для праграмы \"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;” дазвол на доступ да даных датчыкаў цела ў час яе выкарыстання?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Захаваць для праграмы &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; дазвол на доступ да даных датчыкаў цела падчас яе выкарыстання на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; адпраўляць вам апавяшчэнні?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Дазволіць праграме &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; адпраўляць вам апавяшчэнні на прыладзе &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Кіраваныя дазволы"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" мае доступ да даных геалакацыі"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Ваша арганізацыя дазволіла праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" мець доступ да вашага месцазнаходжання"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Iншыя дазволы"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Дазвол, які выкарыстоўваецца сістэмай"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Дазволы, якія выкарыстоўваюцца толькі сістэмнымі праграмамі."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Гэта праграма можа абагульваць даныя пра месцазнаходжанне з трэцімі бакамі"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Абагульванне даных і даныя пра месцазнаходжанне"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Адкуль бярэцца інфармацыя пра абагульванне даных"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Распрацоўшчык перадаў вытворцы прылады інфармацыю пра тое, як гэтая праграма абагульвае даныя. З цягам часу гэта інфармацыя можа быць зменена распрацоўшчыкам."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Распрацоўшчык дадаў (сюды: "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>") інфармацыю пра тое, як гэтая праграма абагульвае даныя. З цягам часу гэтая інфармацыя можа быць зменена распрацоўшчыкам."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Праграма можа абагульваць геаданыя для наступнага:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Абагульванне даных залежыць ад розных умоў"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Бяспека даных"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Дазвол на абагульванне даных пра месцазнаходжанне"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Гэта праграма можа абагульваць даныя пра месцазнаходжанне з трэцімі бакамі"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Не ўдалося адкрыць гэтую спасылку"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Змяненні ў абагульванні даных пра месцазнаходжанне"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Праглядзець праграмы, для якіх быў зменены спосаб абагульвання даных пра месцазнаходжанне"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Для гэтых праграм спосаб абагульвання даных пра месцазнаходжанне змяніўся. Магчыма, яны раней увогуле не абагульвалі такія даныя альбо цяпер пачалі іх абагульваць у мэтах рэкламы ці маркетынгу."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Змяненні ў абагульванні даных"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Для некаторых праграм спосаб абагульвання даных пра месцазнаходжанне змяніўся"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Налады"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Апошні раз доступ быў атрыманы ў <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Апошні раз доступ быў атрыманы ўчора ў <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Апошні раз доступ быў атрыманы ў <xliff:g id="TIME_DATE_1">%2$s</xliff:g> <xliff:g id="TIME_DATE_0">%1$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-bg-v33/strings.xml b/PermissionController/res/values-bg-v33/strings.xml
index d93187d03..6080b29b8 100644
--- a/PermissionController/res/values-bg-v33/strings.xml
+++ b/PermissionController/res/values-bg-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Още сигнали"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Отхвърлени сигнали"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Разгънете и вижте още един сигнал}other{Разгънете и вижте още # сигнала}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Сигнал. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Действието е завършено"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Проверете настройките, които могат да подобрят защитата на устройството ви"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Бързи настройки за сигурността и поверителността"</string>
diff --git a/PermissionController/res/values-bg/strings.xml b/PermissionController/res/values-bg/strings.xml
index 8b7f76a6a..3226f41c0 100644
--- a/PermissionController/res/values-bg/strings.xml
+++ b/PermissionController/res/values-bg/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Още информация"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Разрешаване на пълен достъп"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Винаги да се разрешава пълен достъп"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Разрешаване на ограничения достъп"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Избиране на снимки и видеоклипове"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Избиране на още"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Без избиране на още"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Приложения"</string>
<string name="app_permissions" msgid="3369917736607944781">"Разрешения за приложенията"</string>
<string name="unused_apps" msgid="2058057455175955094">"Неизползвани приложения"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Редактиране на избраните снимки за това приложение"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Няма неизползвани приложения"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 неизползвани приложения"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Скорошни решения за разрешения"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Всички разрешения"</string>
<string name="other_permissions" msgid="2901186127193849594">"Други възможности на приложението"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Заявка за разрешение"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Действията инсталиране и деинсталиране не се поддържат на устройства с Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Изберете до какво да има достъп &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Приложението &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; е актуализирано. Изберете до какво да има достъп."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Отказ"</string>
@@ -126,11 +126,11 @@
<string name="app_name_unknown" msgid="1319665005754048952">"Неизвестно"</string>
<string name="permission_usage_title" msgid="1568233336351734538">"Управление на поверителността"</string>
<string name="auto_permission_usage_summary" msgid="7335667266743337075">"Преглед на приложенията, които наскоро са използвали разрешения"</string>
- <string name="permission_group_usage_title" msgid="2595013198075285173">"Използване на <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
+ <string name="permission_group_usage_title" msgid="2595013198075285173">"Използване на: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Вижте други разрешения"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
<string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> и още <xliff:g id="NUM">%3$s</xliff:g>"</string>
- <string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"Хронология за използването на <xliff:g id="PERMGROUP">%1$s</xliff:g> от приложенията през последните 24 часа"</string>
+ <string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"Хронология за използването на „<xliff:g id="PERMGROUP">%1$s</xliff:g>“ от приложенията през последните 24 часа"</string>
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Хронология за използването на <xliff:g id="PERMGROUP">%1$s</xliff:g> от приложенията през последните 7 дни"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Кога това приложение е използвало разрешението за достъп до <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Научете повече"</string>
@@ -197,14 +197,16 @@
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Когато точното местоположение е изключено, приложенията могат да осъществяват достъп до приблизителното ви местоположение"</string>
<string name="app_permission_title" msgid="2090897901051370711">"Разрешение за: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_header" msgid="2951363137032603806">"Достъп до „<xliff:g id="PERM">%1$s</xliff:g>“ за това приложение"</string>
- <string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Преглед на всички разрешения, предоставени за <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Преглед на всички разрешения, предоставени за: <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Преглед на всички приложения с това разрешение"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Показване на употребата на микрофона за Асистент"</string>
<string name="unused_apps_category_title" msgid="2988455616845243901">"Настройки за неизползваните приложения"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"Премахване на разрешенията, ако приложението не се използва"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Премахване на разреш. и освоб. на място"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Поставяне на активн. в прилож. на пауза, ако не се ползва"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Управление на прилож., ако не се ползва"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Премахване на разрешенията, изтриване на временните файлове и спиране на известията"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Премахване на разрешенията, изтриване на временните файлове, спиране на известията и архивиране на приложението"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"За да защитим данните ви, разрешенията за това приложение ще бъдат премахнати, ако не го използвате няколко месеца."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"За да защитим данните ви, следните разрешения ще бъдат премахнати, ако не използвате приложението няколко месеца: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"За да защитим данните ви, премахнахме разрешенията за приложенията, които не сте използвали от няколко месеца."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Последно отваряне на <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ако разрешите управлението на всички файлове, това приложение може да осъществява достъп до, да променя и изтрива всички файлове в стандартното хранилище на устройството или в свързаните хранилища. Приложението може да осъществява достъп до файловете, без да ви пита."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Да се разреши ли на това приложение да осъществява достъп до, да променя и изтрива файлове на устройството или в свързаните хранилища? Приложението може да осъществява достъп до файловете, без да ви пита."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Приложенията с това разрешение могат да осъществяват <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Приложенията с това разрешение могат да <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Приложенията с това разрешение имат достъп до физическата ви активност, като например ходене, колоездене, шофиране, брой крачки и др."</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Приложенията с това разрешение имат достъп до календара ви"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Приложенията с това разрешение могат да четат списъка с телефонните обаждания и да записват в него"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Приложение за бележки"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Приложения, които ви дават възможност да си водите бележки на устройството си"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"бележки"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Текущо стандартно приложение"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Без повторно питане"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Задаване"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Показване на икона за готовност на асистент"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Показване на икона в лентата на състоянието, когато микрофонът се използва за активиране на гласовия асистент"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да има достъп до снимките и мултимедията на устройството ви?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до снимките и мултимедията на вашия &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до контактите ви на вашия &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"Да се разреши ли достъп на &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Да се разреши ли достъп на &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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Това приложение може да иска да осъществява постоянен достъп до местоположението ви – дори когато не го използвате. "<annotation id="link">"Разрешете от настройките"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Да се промени ли достъпът до местоположението за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Да се промени ли достъпът на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до местоположението на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Това приложение иска да осъществява постоянен достъп до местоположението ви – дори когато не го използвате. "<annotation id="link">"Разрешете от настройките"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да намира у-ва в близост, да се свързва с тях и да определя относит. им позиция?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Разреш. на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да намира, да се свързва със и да опред. отн. поз. на у-ва в близост до вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да намира у-ва в близост, да се свързва с тях и да определя относит. им позиция? "<annotation id="link">"Разрешаване от настройките"</annotation>"."</string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Да се промени ли достъпът на <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> от приблизително местоположение на точно?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Да се промени ли достъпът на <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> до местоположението на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до приблизителното местоположение на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до календара ви на вашия &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да изпраща и преглежда SMS съобщения на вашия &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до снимките, мултимедията и файловете на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Разрешаване на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; достъп до &lt;b&gt;снимките, видео- и аудиосъдържанието&lt;/b&gt; на устройството ви?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Разр. на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; достъп до &lt;b&gt;снимките, видео- и аудиосъдърж. и другите файлове&lt;/b&gt; на у-вото?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да осъществява достъп до музиката и аудиофайловете на това устройство?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до музиката и аудиото на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да осъществява достъп до снимките и видеоклиповете на това устройство?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до снимките и видеоклиповете на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да осъществява достъп до още снимки и видеоклипове на това устройство?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до още снимки и видеоклипове на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да записва аудио?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да записва аудио на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Приложението ще може да записва аудио само когато го използвате"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да записва аудио?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да записва аудио на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Това приложение може да иска да записва аудио по всяко време – дори когато не го използвате. "<annotation id="link">"Разрешете от настройките."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Да се промени ли достъпът до микрофона за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Да се промени ли достъпът на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до микрофона на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Това приложение иска да записва аудио по всяко време – дори когато не го използвате. "<annotation id="link">"Разрешете от настройките."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да осъществява достъп до физическата ви активност?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до физическата ви активност на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да прави снимки и да записва видеоклипове?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да прави снимки и да записва видеоклипове на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Приложението ще може да прави снимки и записва видеоклипове само когато го използвате"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да прави снимки и да записва видеоклипове?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да прави снимки и да записва видеоклипове на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Това приложение може да иска да прави снимки и да записва видеоклипове по всяко време – дори когато не го използвате. "<annotation id="link">"Разрешете от настройките."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Да се промени ли достъпът до камерата за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Да се промени ли достъпът на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до камерата на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Това приложение иска да прави снимки и да записва видеоклипове по всяко време – дори когато не го използвате. "<annotation id="link">"Разрешете от настройките."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да осъществява достъп до списъците с телефонните ви обаждания?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до списъците с телефонните ви обаждания на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да извършва и управлява телефонни обаждания?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да извършва и управлява телефонни обаждания на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да осъществява достъп до данните от сензорите за жизнените ви показатели?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до данните за жизнените ви показатели на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Това приложение иска постоянен достъп до данните от сензорите за жизнените ви показатели – дори когато не го използвате. За да извършите тази промяна, "<annotation id="link">"отворете настройките"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да осъществява достъп до данните от сензорите за жизнените ви показатели?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Да се разреши ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до данните за жизнените ви показатели на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"За да разрешите на това приложение да осъществява достъп до данните от сензорите за тяло по всяко време – дори когато не го използвате, "<annotation id="link">"отворете настройките"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Да се предоставя ли достъп на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до данните от сензорите за тяло, докато приложението се използва?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Да има ли достъп &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до данните от сенз. за тяло на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;, докато прил. се ползва?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да ви изпраща известия?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Да се разреши ли на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да ви изпраща известия на вашия &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Контролирани разрешения"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> има достъп до местоположението"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Организацията ви разрешава на <xliff:g id="APP_NAME">%1$s</xliff:g> да осъществява достъп до местоположението ви"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Други разрешения"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Разрешения, използвани от системата"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Разрешения, които се използват само от системните приложения."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Това приложение посочи, че може да споделя с трети страни данни за местоположението"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Споделяне на данни и достъп до местоположението"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Източници на информацията за споделянето на данни"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Програмистът предостави на производителя на това устройство информация за начина, по който приложението споделя данни. Програмистът може да актуализира съответната информация с течение на времето."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Програмистът предостави на "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" информация за начина, по който това приложение споделя данни. Програмистът може да актуализира съответната информация с течение на времето."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Това прил. може да споделя данни за местоп. с цел:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Споделянето на данни варира"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Безопасност на данните"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Възможно е да бъдат споделяни данни за местоположението"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Това приложение посочи, че може да споделя с трети страни данни за местоположението ви"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Тази връзка не може да се отвори"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Актуализации за споделянето на данни за местоположението"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Прегледайте приложенията, променили начина, по който могат да споделят данни за местоположението ви"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Тези приложения са променили начина, по който могат да споделят данни за местоположението ви. Може да не са ги споделяли преди или вече да го правят с рекламни или маркетингови цели."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Актуализации за споделянето на данни"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Някои приложения са променили как може да споделят данни за местоположението ви"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Настройки"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Осъществен достъп: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Осъществен достъп: вчера, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Осъществен достъп: <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-bn-v33/strings.xml b/PermissionController/res/values-bn-v33/strings.xml
index 28c18f23a..6bef7e90d 100644
--- a/PermissionController/res/values-bn-v33/strings.xml
+++ b/PermissionController/res/values-bn-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"আরও সতর্কতা"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"বাতিল করা সতর্কতা"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{বড় করুন ও আরও একটি সতর্কতা দেখুন}one{বড় করুন ও আরও #টি সতর্কতা দেখুন}other{বড় করুন ও আরও #টি সতর্কতা দেখুন}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"সতর্কতা। <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"অ্যাকশন সম্পূর্ণ হয়েছে"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"আপনার ডিভাইসকে আরও সুরক্ষিত করতে পারে এমন সেটিংস দেখুন"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"সুরক্ষা ও গোপনীয়তা সংক্রান্ত দ্রুত সেটিংস"</string>
diff --git a/PermissionController/res/values-bn/strings.xml b/PermissionController/res/values-bn/strings.xml
index f87e4303d..86ddee9c4 100644
--- a/PermissionController/res/values-bn/strings.xml
+++ b/PermissionController/res/values-bn/strings.xml
@@ -34,23 +34,24 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"আরও তথ্য"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"সব অনুমোদন করুন"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"সবসময় সব অনুমতি দিন"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"সীমিত অ্যাক্সেসের অনুমতি দিন"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ফটো এবং ভিডিও বেছে নিন"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"আরও বেছে নিন"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"আর বেছে নেবেন না"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"যাই হোক, অনুমতি দেবেন না"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"বাতিল করুন"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>টির মধ্যে <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> নম্বর"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপটিকে <xliff:g id="ACTION">%2$s</xliff:g> করার অনুমতি দেবেন?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপটিকে সব সময় <xliff:g id="ACTION">%2$s</xliff:g> করার অনুমতি দেবেন?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপটিকে এটি করার অনুমতি দেবেন?: <xliff:g id="ACTION">%2$s</xliff:g>"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপটিকে সব সময় এটি করার অনুমতি দেবেন?: <xliff:g id="ACTION">%2$s</xliff:g>"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"শুধুমাত্র অ্যাপ ব্যবহার করার সময়"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"সব সময়"</string>
- <string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"অনুমতি দেবেন না এবং আর জিজ্ঞাসা করবেন না"</string>
+ <string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"অনুমতি দেবেন না ও আবার জিজ্ঞাসা করা হোক তা চান না"</string>
<string name="permission_revoked_count" msgid="4785082705441547086">"<xliff:g id="COUNT">%1$d</xliff:g>টি বন্ধ করা হয়েছে"</string>
<string name="permission_revoked_all" msgid="3397649017727222283">"সবগুলি বন্ধ করা হয়েছে"</string>
<string name="permission_revoked_none" msgid="9213345075484381180">"কোনওটিই বন্ধ করা হয়নি"</string>
<string name="grant_dialog_button_allow" msgid="5314677880021102550">"অনুমতি দিন"</string>
<string name="grant_dialog_button_allow_always" msgid="4485552579273565981">"সর্বদা অনুমতি দিন"</string>
- <string name="grant_dialog_button_allow_foreground" msgid="501896824973636533">"অ্যাপ ব্যবহার করার সময়"</string>
+ <string name="grant_dialog_button_allow_foreground" msgid="501896824973636533">"শুধুমাত্র অ্যাপ ব্যবহার করার সময়"</string>
<string name="grant_dialog_button_change_to_precise_location" msgid="3273115879467236033">"সুনির্দিষ্ট লোকেশনে পরিবর্তন করুন"</string>
<string name="grant_dialog_button_keey_approximate_location" msgid="438025182769080011">"আনুমানিক লোকেশন রাখুন"</string>
<string name="grant_dialog_button_allow_one_time" msgid="2618088516449706391">"শুধুমাত্র এই সময়ে"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"অ্যাপ"</string>
<string name="app_permissions" msgid="3369917736607944781">"অ্যাপের অনুমতি"</string>
<string name="unused_apps" msgid="2058057455175955094">"অব্যবহৃত অ্যাপ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"এই অ্যাপের জন্য বেছে নেওয়া ফটো এডিট করুন"</string>
<string name="no_unused_apps" msgid="12809387670415295">"অব্যবহৃত কোনও অ্যাপ নেই"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"ব্যবহার না করা একটিও অ্যাপ নেই"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"অনুমতি সংক্রান্ত সাম্প্রতিক সিদ্ধান্ত"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"সব অনুমতি"</string>
<string name="other_permissions" msgid="2901186127193849594">"অ্যাপের অন্যান্য কার্যক্ষমতা"</string>
<string name="permission_request_title" msgid="8790310151025020126">"অনুমতির অনুরোধ"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear-এ ইনস্টল/আনইনস্টল করা যাবে না।"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপটিকে কিসে কিসে অ্যাক্সেস দেবেন তা বেছে নিন"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; আপডেট করা হয়েছে৷ অ্যাপটিকে কিসে কিসে অ্যাক্সেস দেবেন তা বেছে নিন।"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"বাতিল করুন"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"অ্যাপ ব্যবহার করা না হলে সেটি থেকে অনুমতি প্রত্যাহার করে নিন"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"অনুমতি সরান এবং স্পেস খালি করুন"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"ব্যবহার না হলে অ্যাপ অ্যাক্টিভিটি পজ করুন"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ব্যবহার না করা হলে অ্যাপ ম্যানেজ করুন"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"অনুমতি সরান, অস্থায়ী ফাইল মুছুন এবং বিজ্ঞপ্তি বন্ধ করুন"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"অনুমতি সরান, অস্থায়ী ফাইল মুছুন, বিজ্ঞপ্তি বন্ধ করুন এবং অ্যাপ আর্কাইভ করুন"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"আপনার ডেটা সুরক্ষিত রাখতে এই অ্যাপ কয়েক মাস ব্যবহার করা না হলে, এটিকে দেওয়া অনুমতি প্রত্যাহার করে নেওয়া হবে।"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"আপনার ডেটা সুরক্ষিত রাখতে অ্যাপটি কয়েক মাস ব্যবহার করা না হলে, এই অনুমতি প্রত্যাহার করে নেওয়া হবে: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"আপনার ডেটা সুরক্ষিত রাখতে যেসব অ্যাপ গত কয়েক মাস ব্যবহার করা হয়নি সেগুলি থেকে অনুমতি প্রত্যাহার করে নেওয়া হয়েছে।"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"নোট অ্যাপ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"অ্যাপ, যা আপনার ডিভাইসে নোট নেওয়ার অনুমতি দেয়"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"নোট"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"বর্তমান ডিফল্ট"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"আর দেখতে চাই না"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ডিফল্ট হিসেবে রাখুন"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"অ্যাসিস্ট্যান্ট ট্রিগার ডিটেকশন দেখুন"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"ভয়েস অ্যাসিস্ট্যান্ট চালু করতে মাইক্রোফোন ব্যবহার হলে স্ট্যাটাস বারে আইকন দেখায়"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে আপনার ডিভাইসের ফটো এবং মিডিয়াতে অ্যাক্সেস দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_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="2270563860206654757">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_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="6641436550953715107">"আপনার &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="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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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> ডিভাইসের লোকেশন অ্যাক্সেস করার অনুমতি দিতে চান?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"এই অ্যাপ হয়ত সবসময় আপনার লোকেশন অ্যাক্সেস করতে চায়, এমনকি আপনার অ্যাপ চালু না থাকলেও। "<annotation id="link">"সেটিংস বিকল্প থেকে অনুমতি দিন।"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-এর জন্য লোকেশন অ্যাক্সেস পরিবর্তন করতে চান?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"এই অ্যাপটি সবসময় আপনার লোকেশন অ্যাক্সেস করতে চায়, এমনকি আপনার অ্যাপ চালু না থাকলেও। "<annotation id="link">"সেটিংস বিকল্প থেকে অনুমতি দিন।"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"কাছাকাছি ডিভাইস খুঁজে দেখতে, কানেক্ট করতে এবং সেটির আপেক্ষিক অবস্থান নির্ধারণ করতে &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপকে অনুমতি দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"কাছাকাছি ডিভাইস খুঁজে দেখতে, কানেক্ট করতে এবং সেটির আপেক্ষিক অবস্থান নির্ধারণ করতে &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপকে অনুমতি দেবেন? "<annotation id="link">"সেটিংস থেকে অনুমতি দিন।"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>-এ লোকেশন অ্যাক্সেস, আনুমানিক থেকে সুনির্দিষ্ট লোকেশনে পরিবর্তন করতে চান?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ডিভাইসে <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> অ্যাপের লোকেশন আনুমানিক থেকে সঠিকে পরিবর্তন করতে চান?"</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="9001956706241104626">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_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="3103987548035171850">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে এসএমএস দেখতে ও পাঠাতে দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_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="872629037299467086">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_storage_q_to_s" msgid="8213701872983685505">"এই ডিভাইসে &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে &lt;b&gt;ফটো, ভিডিও, মিউজিক এবং অডিও&lt;/b&gt; অ্যাক্সেসের অনুমতি দেবেন?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"এই ডিভাইসে &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে &lt;b&gt;ফটো, ভিডিও, মিউজিক, অডিও ও অন্যান্য ফাইল&lt;/b&gt; অ্যাক্সেসের অনুমতি দেবেন?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"এই ডিভাইসে &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে মিউজিক ও অডিও ফাইল অ্যাক্সেসের অনুমতি দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_read_media_visual" msgid="5548780620779729975">"এই ডিভাইসে &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে ফটো ও ভিডিও অ্যাক্সেসের অনুমতি দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_more_photos" msgid="128933814654231321">"এই ডিভাইসে &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে আরও ফটো ও ভিডিও অ্যাক্সেসের অনুমতি দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে অডিও রেকর্ড করার অনুমতি দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপকে আপনার &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ডিভাইসে অডিও রেকর্ড করার অনুমতি দিতে চান?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"আপনি এই অ্যাপ ব্যবহার করার সময়েই শুধুমাত্র সেটি অডিও রেকর্ড করতে পারবে"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে অডিও রেকর্ড করার অনুমতি দিতে চান?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপকে আপনার &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ডিভাইসে অডিও রেকর্ড করার অনুমতি দিতে চান?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"এই অ্যাপ হয়ত সবসময় এমনকি আপনি যখন অ্যাপ ব্যবহার করছেন না তখনও অডিও রেকর্ড করতে চাইতে পারে। "<annotation id="link">"সেটিংস থেকে অনুমতি দিন।"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-এর জন্য মাইক্রোফোন অ্যাক্সেস পরিবর্তন করতে চান?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"এই অ্যাপ হয়ত সবসময় এমনকি আপনি যখন অ্যাপ ব্যবহার করছেন না তখনও অডিও রেকর্ড করতে চাইবে। "<annotation id="link">"সেটিংস থেকে অনুমতি দিন।"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে আপনার শারীরিক অ্যাক্টিভিটি অ্যাক্সেস করার অনুমতি দিতে চান?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে ফটো তোলা ও ভিডিও রেকর্ড করার অনুমতি দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_camera" msgid="9085323239764667883">"আপনি এই অ্যাপ ব্যবহার করার সময়েই শুধুমাত্র সেটি ছবি তুলতে এবং ভিডিও রেকর্ড করতে পারবে"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপকে ফটো তুলতে এবং ভিডিও রেকর্ড করার অনুমতি দিতে চান?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"এই অ্যাপ হয়ত সবসময় এমনকি আপনি যখন অ্যাপ ব্যবহার করছেন না তখনও ছবি তুলতে এবং ভিডিও রেকর্ড করতে চাইতে পারে। "<annotation id="link">"সেটিংস থেকে অনুমতি দিন।"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-এর জন্য ক্যামেরা অ্যাক্সেস পরিবর্তন করতে চান?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"এই অ্যাপ সবসময় এমনকি আপনি যখন অ্যাপ ব্যবহার করছেন না তখনও ছবি তুলতে এবং ভিডিও রেকর্ড করতে চাইবে। "<annotation id="link">"সেটিংস থেকে অনুমতি দিন।"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে আপনার ফোন কল লগ অ্যাক্সেস করার অনুমতি দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে কল করতে এবং কল পরিচালনা করতে দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে সেন্সর থেকে আপনার ভাইটাল সাইনের ডেটা অ্যাক্সেস করতে দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"এই অ্যাপ সবসময় শারীরবৃত্তীয় লক্ষণ সংক্রান্ত সেন্সর ডেটা অ্যাক্সেস করার অনুমতি চায়, এমনকী আপনি যখন অ্যাপটি ব্যবহার করছেন না, তখনও। এই পরিবর্তন চালু করতে, "<annotation id="link">"সেটিংসে যান।"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে আপনার বেঁচে থাকার গুরুত্বপূর্ণ লক্ষণ সম্পর্কিত সেন্সর ডেটা অ্যাক্সেস করার অনুমতি দিতে চান?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"অ্যাপটি ব্যবহার না করলেও, সেটিকে সবসময় বডি সেন্সর ডেটাতে অ্যাক্সেস দিতে "<annotation id="link">"সেটিংসে যান"</annotation>"।"</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ব্যবহার করার সময় &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপকে বডি সেন্সর ডেটার অ্যাক্সেস দিয়ে রাখতে চান?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"ব্যবহার করার সময় &lt;b&gt;<xliff:g id="DEVICE">%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_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে বিজ্ঞপ্তি পাঠানোর অনুমতি দেবেন?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"আপনার &lt;b&gt;<xliff:g id="DEVICE">%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="auto_granted_permissions" msgid="6009452264824455892">"নিয়ন্ত্রিত অনুমতি"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর লোকেশন অ্যাক্সেস আছে"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"আপনার সংস্থা <xliff:g id="APP_NAME">%1$s</xliff:g>-কে আপনার লোকেশন অ্যাক্সেস করার অনুমতি দেয়"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"অন্যান্য অনুমতি"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"যেসব অনুমতি শুধু সিস্টেম অ্যাপ ব্যবহার করেছে"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"যেসব অনুমতি শুধুমাত্র সিস্টেম অ্যাপ্লিকেশনে ব্যবহার করা হয়।"</string>
@@ -577,20 +614,21 @@
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"ব্যাকগ্রাউন্ডে লোকেশন অ্যাক্সেস করার অনুমতি আছে এমন অ্যাপ পর্যালোচনা করুন"</string>
<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="safety_center_view_recent_location_access" msgid="3524391299490678243">"লোকেশন ব্যবহারের সাম্প্রতিক তথ্য দেখুন"</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>
<string name="mic_toggle_description" msgid="9163104307990677157">"অ্যাপ ও পরিষেবার জন্য। এই সেটিং বন্ধ থাকলেও, মাইক্রোফোনের ডেটা শেয়ার করা যেতে পারে। আপনি কোনও জরুরি নম্বরে কল করলে এমন হতে পারে।"</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"লোকেশনে অ্যাক্সেস রয়েছে এমন অ্যাপ ও পরিষেবা দেখা"</string>
- <string name="show_clip_access_notification_title" msgid="5168467637351109096">"ক্লিপবোর্ড অ্যাক্সেস দেখায়"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"ক্লিপবোর্ড অ্যাক্সেস সংক্রান্ত তথ্য দেখানো"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"আপনার কপি করা টেক্সট, ছবি বা অন্যান্য কন্টেন্ট অ্যাপ অ্যাক্সেস করলে মেসেজ দেখায়"</string>
<string name="show_password_title" msgid="2877269286984684659">"পাসওয়ার্ড দেখুন"</string>
<string name="show_password_summary" msgid="1110166488865981610">"টাইপ করার সময় অক্ষরগুলি কয়েক মুহূর্তের জন্য দেখুন"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"এই অ্যাপ, থার্ড-পার্টির সাথে লোকেশন ডেটা শেয়ার করার অনুমতি চাইতে পারে"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ডেটা শেয়ারিং ও লোকেশন"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ডেটা শেয়ারিং সম্পর্কিত তথ্য কোথা থেকে পাওয়া যায়"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"কীভাবে এই অ্যাপ ডেটা শেয়ার করে তার ব্যাপারে ডেভেলপার ডিভাইসের প্রস্তুতকারককে তথ্য প্রদান করেছে। ভবিষ্যতে ডেভেলপার এই তথ্য আপডেট করতে পারে।"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"কীভাবে এই অ্যাপ ডেটা শেয়ার করে, তার ব্যাপারে ডেভেলপার "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"-কে তথ্য প্রদান করেছে। ভবিষ্যতে ডেভেলপার এই তথ্য আপডেট করতে পারে।"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"এই অ্যাপ যে জন্য লোকেশন ডেটা শেয়ার করতে পারে:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ডেটা শেয়ারিংয়ের ক্ষেত্রে হওয়া পরিবর্তন"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ডেটা সুরক্ষা"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"লোকেশন ডেটা শেয়ার করা হতে পারে"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"এই অ্যাপ জানিয়েছে যে, এটি থার্ড পার্টির সাথে আপনার লোকেশন ডেটা শেয়ার করতে পারে"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"এই লিঙ্কটি খুলতে পারা যাচ্ছে না"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"লোকেশনের জন্য ডেটা শেয়ারিং সম্পর্কিত আপডেট"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"যেসব অ্যাপ আপনার লোকেশন ডেটা শেয়ার করার উপায়ের ক্ষেত্রে পরিবর্তন করেছে, সেগুলি পর্যালোচনা করুন"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"এইসব অ্যাপ আপনার লোকেশন ডেটা শেয়ার করার উপায়ের ক্ষেত্রে পরিবর্তন করেছে। এগুলি আগে হয়ত শেয়ার করেনি অথবা এখন বিজ্ঞাপন বা মার্কেটিং সংক্রান্ত উদ্দেশ্যে শেয়ার করতে পারে।"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ডেটা শেয়ারিং সংক্রান্ত আপডেট"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"কিছু অ্যাপ আপনার লোকেশন ডেটা শেয়ার করার উপায়ের ক্ষেত্রে পরিবর্তন করেছে"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"সেটিংস"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g>-এ অ্যাক্সেস করা হয়েছে"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"গতকাল <xliff:g id="TIME_DATE">%1$s</xliff:g>-এ অ্যাক্সেস করা হয়েছে"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g><xliff:g id="TIME_DATE_1">%2$s</xliff:g>-এ অ্যাক্সেস করা হয়েছে"</string>
</resources>
diff --git a/PermissionController/res/values-bs-television/strings.xml b/PermissionController/res/values-bs-television/strings.xml
index 997588205..117b35bd5 100644
--- a/PermissionController/res/values-bs-television/strings.xml
+++ b/PermissionController/res/values-bs-television/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="grant_dialog_button_deny_dont_ask_again" msgid="747769682501286250">"Odbij i ne pitaj ponovo"</string>
- <string name="grant_dialog_how_to_change" msgid="997462845048160559">"Ovo možete kasnije promijeniti u odjeljku Postavke i Aplikacije"</string>
+ <string name="grant_dialog_how_to_change" msgid="997462845048160559">"Ovo možete kasnije promijeniti u odjeljku Postavke &gt; Aplikacije"</string>
<string name="current_permission_template" msgid="6240787325714651204">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="preference_show_system_apps" msgid="4262140518693221093">"Prikaži sistemske aplikacije"</string>
<string name="app_permissions_decor_title" msgid="7438716722786036814">"Odobrenja za aplikaciju"</string>
diff --git a/PermissionController/res/values-bs-v33/strings.xml b/PermissionController/res/values-bs-v33/strings.xml
index 4df792c5e..598dc6a6c 100644
--- a/PermissionController/res/values-bs-v33/strings.xml
+++ b/PermissionController/res/values-bs-v33/strings.xml
@@ -40,7 +40,7 @@
<string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Prebaci. <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">"Uključi/isključi"</string>
<string name="safety_center_qs_open_action" msgid="2760200829912423728">"Otvori"</string>
- <string name="safety_center_review_settings_button" msgid="938981137942443930">"Pregledaj postavke"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Pregledajte postavke"</string>
<string name="safety_center_gear_label" msgid="5175877094379694098">"Postavke"</string>
<string name="safety_center_info_label" msgid="8993181584061825412">"Informacije"</string>
</resources>
diff --git a/PermissionController/res/values-bs/strings.xml b/PermissionController/res/values-bs/strings.xml
index cd722859d..a0a82320a 100644
--- a/PermissionController/res/values-bs/strings.xml
+++ b/PermissionController/res/values-bs/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Više informacija"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Dozvoli sve"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Uvijek dozvoli sve"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Dozvoli ograničeni pristup"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Odabir fotografija i videozapisa"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Odaberi više"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nemoj odabrati više"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Svejedno nemoj dozvoliti"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Odbaci"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> od <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Želite li dozvoliti da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uradi sljedeće: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Uvijek dozvoliti da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uradi sljedeće: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da uradi sljedeće: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Uvijek dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da uradi sljedeće: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Samo dok se koristi aplikacija"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Uvijek"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Nemoj dozvoliti i ne pitaj ponovo"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikacije"</string>
<string name="app_permissions" msgid="3369917736607944781">"Odobrenja za aplikaciju"</string>
<string name="unused_apps" msgid="2058057455175955094">"Nekorištene aplikacije"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Uredite odabrane fotografije za aplikaciju"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nema nekorištenih aplikacija"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 nekorištenih aplikacija"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nedavne odluke o odobrenjima"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Dozvoli sve vrijeme"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Dozvoli samo dok se koristi"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Dozvoli samo dok se aplikacija koristi"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Nemoj dozvoliti"</string>
<string name="loading" msgid="4789365003890741082">"Učitavanje…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Sva odobrenja"</string>
<string name="other_permissions" msgid="2901186127193849594">"Ostale mogućnosti aplikacije"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Zahtjev za odobrenje"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Instaliranje/deinstaliranje nije podržano na Wearu."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Izaberite čemu aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&amp;Lt;/b&gt; može pristupiti"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Aplikacija &amp;Lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&amp;Lt;/b&gt; je ažurirana. Izaberite čemu ova aplikacija može pristupiti."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Otkaži"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Ukloni odobrenja ako se aplikacija ne koristi"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Ukloni odobrenja i oslobodi prostor"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pauziraj aktivnost apl. ako se ne koristi"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Upravljaj aplikacijom ako se ne koristi"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Uklonite odobrenja, izbrišite privremene fajlove i zaustavite obavještenja"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Uklonite odobrenja, izbrišite privremene fajlove, zaustavite obavještenja i arhivirajte aplikaciju"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Zbog zaštite vaših podataka, odobrenja za ovu aplikaciju će se ukloniti ako se ona ne bude koristila nekoliko mjeseci."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Radi zaštite vaših podataka, ako se aplikacija ne bude koristila nekoliko mjeseci, uklonit će se sljedeća odobrenja: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Zbog zaštite vaših podataka uklonjena su odobrenja iz aplikacija koje niste koristili nekoliko mjeseci."</string>
@@ -226,20 +228,20 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Posljednji put otvoreno na dan <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ako dozvolite upravljanje svim fajlovima, ova aplikacija može pristupati, mijenjati i brisati sve fajlove u zajedničkoj pohrani na ovom uređaju ili na povezanim uređajima za pohranu. Aplikacija može pristupati fajlovima bez prethodnog pitanja."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Dozvoliti ovoj aplikaciji da pristupa, mijenja i briše fajlove na uređaju ili na svim povezanim uređajima za pohranu? Ova aplikacija može pristupati fajlovima bez prethodnog pitanja."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacije s ovim odobrenjem mogu <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacije s ovim odobrenjem mogu raditi sljedeće: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Aplikacije s ovim odobrenjem mogu pristupiti informacijama o vašim fizičkim aktivnostima kao što su hodanje, vožnja bicikla, vožnja, broj koraka i još mnogo toga"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Aplikacije s ovim odobrenjem mogu pristupiti vašem kalendaru"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Aplikacije s ovim odobrenjem mogu čitati i pisati zapisnike telefonskih poziva"</string>
<string name="permission_description_summary_camera" msgid="108004375101882069">"Aplikacije s ovim odobrenjem mogu snimati fotografije i videozapise"</string>
<string name="permission_description_summary_contacts" msgid="2337798886460408996">"Aplikacije s ovim odobrenjem mogu pristupiti vašim kontaktima"</string>
- <string name="permission_description_summary_location" msgid="2817531799933480694">"Aplikacije s ovim odobrenjem mogu pristupiti lokaciji uređaja"</string>
+ <string name="permission_description_summary_location" msgid="2817531799933480694">"Aplikacije s ovim odobrenjem mogu pristupati lokaciji uređaja"</string>
<string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"Aplikacije s ovim odobrenjem mogu pronaći uređaje u blizini, povezati se s njima te odrediti njihov relativni položaj"</string>
<string name="permission_description_summary_microphone" msgid="630834800308329907">"Aplikacije s ovim odobrenjem mogu snimati zvuk"</string>
<string name="permission_description_summary_phone" msgid="4515277217435233619">"Aplikacije s ovim odobrenjem mogu upućivati pozive i upravljati njima"</string>
<string name="permission_description_summary_sensors" msgid="1836045815643119949">"Aplikacije s ovim odobrenjem mogu pristupiti podacima senzora o vašim vitalnim znakovima"</string>
<string name="permission_description_summary_sms" msgid="725999468547768517">"Aplikacije s ovim odobrenjem mogu slati i pregledati SMS poruke"</string>
<string name="permission_description_summary_storage" msgid="6575759089065303346">"Aplikacije s ovim odobrenjem mogu pristupiti fotografijama, medijima i drugim fajlovima na vašem uređaju"</string>
- <string name="permission_description_summary_read_media_aural" msgid="3354728149930482199">"Aplikacije s ovim odobrenjem mogu pristupiti muzičkim i drugim audio fajlovima na ovom uređaju"</string>
+ <string name="permission_description_summary_read_media_aural" msgid="3354728149930482199">"Aplikacije s ovim odobrenjem mogu pristupati muzičkim i drugim audio fajlovima na ovom uređaju"</string>
<string name="permission_description_summary_read_media_visual" msgid="4991801977881732641">"Aplikacije s ovim odobrenjem mogu pristupiti fotografijama i videozapisima na ovom uređaju"</string>
<string name="app_permission_most_recent_summary" msgid="4292074449384040590">"Posljednji pristup: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"Trenutno odbijeno/posljednji pristup: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikacija za bilješke"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplikacije koje vam dozvoljavaju da pravite bilješke na uređaju"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"bilješke"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Trenutno zadano"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ne pitaj ponovo"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Postavi kao zadano"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Prikaži otkrivanje aktiviranja asistenta"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Prikaz ikone na statusnoj traci kada se mikrofon koristi za aktiviranje glasovne pomoći"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fotografijama i medijima na vašem uređaju?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fotografijama i medijskim fajlovima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa vašim kontaktima?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa kontaktima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikacija će imati pristup lokaciji isključivo dok je koristite"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Moguće je da će aplikacija željeti pristup vašoj lokaciji sve vrijeme, čak i kada je ne budete koristili. "<annotation id="link">"Dozvolite u postavkama."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Promijeniti pristup lokaciji za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Promijeniti pristup lokaciji za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Ova aplikacija želi pristup vašoj lokaciji sve vrijeme, čak i kada je ne koristite. "<annotation id="link">"Dozvolite u postavkama."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pronađe uređaje u blizini, poveže se s njima te odredi njihov relativni položaj?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da traži, poveže se i odredi položaj uređaja u blizini na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pronađe uređaje u blizini, poveže se s njima te odredi njihov relativni položaj? "<annotation id="link">"Dozvolite u postavkama."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Promijeniti pristup aplikacije <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> lokaciji iz približne u tačnu?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Promijeniti pristup aplikacije <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> lokaciji na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; iz približne u tačnu?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa približnoj lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa približnoj lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Tačno"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Približno"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupi vašem kalendaru?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa kalendaru na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da šalje i pregleda SMS poruke?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da šalje i pregleda SMS poruke na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fotografijama, medijima i fajlovima na vašem uređaju?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fotografijama, medijima i fajlovima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Dozvoliti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa &lt;b&gt;foto/video/muzičkim/audio fajlovima&lt;/b&gt; na ovom uređaju?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Dozvoliti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa &lt;b&gt;foto/video/muzičkim/audio i drugim fajlovima&lt;/b&gt; na uređaju?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Dozvoliti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa muzici i zvuku na ovom uređaju?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa muzici i audio zapisima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fotografijama i videozapisima na ovom uređaju?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fotografijama i videozapisima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa većem broju fotografija i videozapisa na uređaju?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa većem broju fotografija i videozapisa na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima zvuk?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima zvuk na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikacija će moći snimati zvuk samo za vrijeme korištenja"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snimanje zvuka?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima zvuk na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Ova aplikacija može tražiti da snima zvuk sve vrijeme, čak i kada je ne koristite. "<annotation id="link">"Dozvolite u postavkama."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Promijeniti pristup mikrofonu za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Promijeniti pristup mikrofonu za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Ova aplikacija traži da snima zvuk sve vrijeme, čak i kada je ne koristite. "<annotation id="link">"Dozvolite u postavkama."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa informacijama o vašoj fizičkoj aktivnosti?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fizičkoj aktivnosti na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima fotografije i videozapise?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima slike i videozapise na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikacija će moći snimati slike i videozapise samo za vrijeme korištenja"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snimanje slika i videozapisa?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima slike i videozapise na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Ova aplikacija može tražiti da snima slike i videozapise sve vrijeme, čak i kada je ne koristite. "<annotation id="link">"Dozvolite u postavkama."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Promijeniti pristup kameri za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Promijeniti pristup kameri za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Ova aplikacija traži da snima slike i videozapise sve vrijeme, čak i kada je ne koristite. "<annotation id="link">"Dozvolite u postavkama."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa zapisnicima poziva?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa zapisnicima telefonskih poziva na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da upućuje pozive i upravlja njima?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da uspostavlja telefonske pozive i upravlja njima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa senzornim podacima o vašim vitalnim znakovima?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa podacima senzora o vitalnim znakovima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Ova aplikacija želi pristupati podacima senzora o vašim vitalnim znakovima sve vrijeme, čak i kada je ne koristite. Da to promijenite, "<annotation id="link">"idite u postavke."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa podacima senzora o vašim vitalnim znakovima?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa podacima senzora o vitalnim znakovima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Da dozvolite aplikaciji da pristupa podacima tjelesnih senzora sve vrijeme, čak i kada je ne koristite, "<annotation id="link">"idite u postavke."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Nastaviti dozvoljavati aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa podacima tjelesnih senzora dok se koristi?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Nastaviti dozvoljavati aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa podacima tjelesnih senzora na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; dok je koristite?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da vam šalje obavještenja?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da šalje obavještenja na uređaj &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontrolirana odobrenja"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ima pristup lokaciji"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Vaša organizacija dozvoljava aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> da pristupa vašoj lokaciji"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Aplikacija je navela da može dijeliti podatke o lokaciji s trećim stranama"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Dijeljenje podataka i lokacija"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Odakle dolaze informacije o dijeljenju podataka"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Programer je proizvođaču uređaja naveo informacije o tome kako ova aplikacija dijeli podatke. Programer može povremeno ažurirati ove informacije."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Programer je usluzi "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" naveo informacije o tome kako ova aplikacija dijeli podatke. Programer može tokom vremena ažurirati ove informacije."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Aplikacija može dijeliti podatke o lokaciji za:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Dijeljenje podataka se razlikuje"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Sigurnost podataka"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Podaci o lokaciji se mogu dijeliti"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Aplikacija je navela da može dijeliti podatke o lokaciji s trećim stranama"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Nije moguće otvoriti ovu vezu"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Promjene u dijeljenju podataka za lokaciju"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Pregledajte aplikacije koje su promijenile način na koji mogu dijeliti podatke o lokaciji"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Ove aplikacije su promijenile način na koji mogu dijeliti podatke o lokaciji. Možda ih prije nisu dijelile ili ih sada dijele u svrhe oglašavanja ili marketinga."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Promjene u dijeljenju podataka"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Neke aplikacije mogu promijeniti način na koji mogu dijeliti podatke o lokaciji"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Postavke"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Pristupljeno je u <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Pristupljeno je jučer u <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Pristupljeno je <xliff:g id="TIME_DATE_0">%1$s</xliff:g> u <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-ca-v33/strings.xml b/PermissionController/res/values-ca-v33/strings.xml
index 60ca34dc3..0526fffbc 100644
--- a/PermissionController/res/values-ca-v33/strings.xml
+++ b/PermissionController/res/values-ca-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Més alertes"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertes ignorades"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Desplega i consulta 1 alerta més}many{Desplega i consulta # alertes més}other{Desplega i consulta # alertes més}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerta. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Acció completa"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Comprova les opcions de configuració que puguin afegir protecció al dispositiu"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Configuració ràpida de la seguretat i la privadesa"</string>
diff --git a/PermissionController/res/values-ca-v34/strings.xml b/PermissionController/res/values-ca-v34/strings.xml
index 651a36b0b..8aad7b657 100644
--- a/PermissionController/res/values-ca-v34/strings.xml
+++ b/PermissionController/res/values-ca-v34/strings.xml
@@ -20,8 +20,8 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Seguretat i privadesa"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controls"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Salut connectada"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Gestiona l\'accés de l\'aplicació a les dades de salut"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Gestiona l\'accés de les aplicacions a les dades de salut"</string>
<string name="location_settings" msgid="8863940440881290182">"Accés a la ubicació"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Per a aplicacions i serveis. Si aquesta opció de configuració està desactivada, és possible que les dades del micròfon es continuïn compartint quan truquis a un número d\'emergència."</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Per a aplicacions i serveis. És possible que les dades del micròfon es comparteixin si truques a un número d\'emergència encara que aquesta opció estigui desactivada."</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Per a aplicacions i serveis"</string>
</resources>
diff --git a/PermissionController/res/values-ca/strings.xml b/PermissionController/res/values-ca/strings.xml
index 23df40f90..1f6b33c4e 100644
--- a/PermissionController/res/values-ca/strings.xml
+++ b/PermissionController/res/values-ca/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Més informació"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Permet-ho tot"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Permet sempre tot"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Permet l\'accés limitat"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Selecciona fotos i vídeos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Selecciona\'n més"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"No seleccionis més"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"No permetis de cap manera"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Ignora"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Vols permetre a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Vols permetre a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Permetre sempre a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Permetre sempre a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Només mentre s\'utilitzi l\'aplicació"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Sempre"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"No permetis i no m\'ho tornis a preguntar"</string>
@@ -51,7 +52,7 @@
<string name="grant_dialog_button_allow" msgid="5314677880021102550">"Permet"</string>
<string name="grant_dialog_button_allow_always" msgid="4485552579273565981">"Permet sempre"</string>
<string name="grant_dialog_button_allow_foreground" msgid="501896824973636533">"Mentre s\'utilitza l\'aplicació"</string>
- <string name="grant_dialog_button_change_to_precise_location" msgid="3273115879467236033">"Canvia a la ubicació exacta"</string>
+ <string name="grant_dialog_button_change_to_precise_location" msgid="3273115879467236033">"Canvia a la ubicació precisa"</string>
<string name="grant_dialog_button_keey_approximate_location" msgid="438025182769080011">"Mantén la ubicació aproximada"</string>
<string name="grant_dialog_button_allow_one_time" msgid="2618088516449706391">"Només aquesta vegada"</string>
<string name="grant_dialog_button_allow_background" msgid="8236044729434367833">"Permet sempre"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplicacions"</string>
<string name="app_permissions" msgid="3369917736607944781">"Permisos d\'aplicacions"</string>
<string name="unused_apps" msgid="2058057455175955094">"Aplicacions no utilitzades"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edita les fotos seleccionades per a aquesta aplicació"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Cap aplicació sense utilitzar"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 aplicacions no utilitzades"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Decisions recents de permisos"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Tots els permisos"</string>
<string name="other_permissions" msgid="2901186127193849594">"Altres competències de l\'aplicació"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Sol·licitud de permís"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Les accions d\'instal·lar o de desinstal·lar no s\'admeten a Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Tria a què vols que tingui accés &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"S\'ha actualitzat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;. Tria a què vols que tingui accés aquesta aplicació."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancel·la"</string>
@@ -191,20 +191,22 @@
<string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Permet sempre tot"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Pregunta sempre"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"No permetis"</string>
- <string name="precise_image_description" msgid="6349638632303619872">"Ubicació exacta"</string>
+ <string name="precise_image_description" msgid="6349638632303619872">"Ubicació precisa"</string>
<string name="approximate_image_description" msgid="938803699637069884">"Ubicació aproximada"</string>
- <string name="app_permission_location_accuracy" msgid="7166912915040018669">"Utilitza la ubicació exacta"</string>
- <string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Quan la ubicació exacta està desactivada, les aplicacions poden accedir a la teva ubicació aproximada"</string>
+ <string name="app_permission_location_accuracy" msgid="7166912915040018669">"Utilitza la ubicació precisa"</string>
+ <string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Quan la ubicació precisa està desactivada, les aplicacions poden accedir a la teva ubicació aproximada"</string>
<string name="app_permission_title" msgid="2090897901051370711">"Permís d\'accés a <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_header" msgid="2951363137032603806">"Accés a <xliff:g id="PERM">%1$s</xliff:g> per a aquesta aplicació"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Mostra tots els permisos per a <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Mostra totes les aplicacions que tenen aquest permís"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Mostra l\'ús del micròfon de l\'Assistent"</string>
- <string name="unused_apps_category_title" msgid="2988455616845243901">"Configuració d\'apps no utilitzades"</string>
+ <string name="unused_apps_category_title" msgid="2988455616845243901">"Configuració d\'aplicació no utilitzada"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"Suprimeix els permisos si no s\'utilitza l\'aplicació"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Suprimeix els permisos i allibera espai"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Activitat a l\'app en pausa si no s\'usa"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gestiona l\'aplicació si no s\'utilitza"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Suprimeix els permisos i els fitxers temporals, i atura les notificacions"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Suprimeix els permisos i els fitxers temporals, atura les notificacions i arxiva l\'aplicació"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Per protegir les teves dades, els permisos d\'aquesta aplicació se suprimiran si no la utilitzes durant uns mesos."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Si l\'aplicació no s\'utilitza durant uns mesos, se suprimiran els permisos següents per protegir les teves dades: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Per protegir les teves dades, s\'han suprimit els permisos de les aplicacions que no has utilitzat durant els darrers mesos."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Oberta per darrera vegada el dia <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Si permets la gestió de tots els fitxers, aquesta aplicació podrà accedir als fitxers, així com modificar-los i suprimir-los, que es trobin a l\'emmagatzematge comú d\'aquest dispositiu o als dispositius d\'emmagatzematge connectats. L\'aplicació podrà accedir als fitxers sense demanar-te permís."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Vols permetre que aquesta aplicació accedeixi als fitxers, o els modifiqui o suprimeixi, en aquest dispositiu o en qualsevol altre dispositiu d\'emmagatzematge connectat? Aquesta aplicació podrà accedir als fitxers sense demanar-te permís."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Les aplicacions amb aquest permís poden <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Les aplicacions amb aquest permís poden fer el següent: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Les aplicacions amb aquest permís poden accedir a la teva activitat física, com ara els passejos a peu, els trajectes amb bici o cotxe, el recompte de passos, etc."</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Les aplicacions amb aquest permís poden accedir al teu calendari"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Les aplicacions amb aquest permís poden llegir i editar el registre de trucades del telèfon"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplicació de notes"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplicacions que et permeten prendre notes al dispositiu"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notes"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Predeterminada actualment"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"No m\'ho tornis a preguntar"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Estableix com a predeterminada"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Mostra la detecció d\'activador de l\'assistent"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mostra una icona a la barra d\'estat quan s\'utilitzi el micròfon per activar l\'assistent de veu"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les fotos i al contingut multimèdia del dispositiu?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les fotos i al contingut multimèdia del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi als contactes?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi als contactes del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la ubicació del dispositiu?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la ubicació del dispositiu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"L\'aplicació només tindrà accés a la ubicació quan l\'estiguis utilitzant"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la ubicació del dispositiu?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la ubicació del dispositiu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Aquesta aplicació vol tenir accés a la teva ubicació sempre, fins i tot quan no l\'estiguis utilitzant. "<annotation id="link">"Pots permetre-ho a Configuració"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Vols canviar l\'accés a la ubicació per a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Vols canviar l\'accés a la ubicació de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Aquesta aplicació vol tenir accés a la teva ubicació sempre, fins i tot quan no l\'estiguis utilitzant. "<annotation id="link">"Pots permetre-ho a Configuració"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; cerqui els dispositius propers, s\'hi connecti i en determini la posició relativa?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; cerqui la posició relativa de disp. propers, la determini i s\'hi connecti al &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; cerqui els dispositius propers, s\'hi connecti i en determini la posició relativa? "<annotation id="link">"Permet a Configuració"</annotation>"."</string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Vols canviar l\'accés a la ubicació que té <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> d\'aproximada a exacta?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Vols canviar l\'accés a la ubicació de <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; d\'Aproximada a Exacta?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la ubicació aproximada del dispositiu?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la ubicació aproximada del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exacta"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aproximada"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi al calendari?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi al calendari del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; enviï i llegeixi missatges SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; enviï i llegeixi missatges SMS al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a fotos, contingut multimèdia i fitxers del dispositiu?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a fotos, contingut multimèdia i fitxers del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi als &lt;b&gt;vídeos, fotos, música i àudio&lt;/b&gt; del dispositiu?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi als &lt;b&gt;vídeos, fotos, música, àudio i altres fitxers&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la música i l\'àudio d\'aquest dispositiu?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la música i l\'àudio del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les fotos i els vídeos d\'aquest dispositiu?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les fotos i als vídeos del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a més fotos i vídeos d\'aquest dispositiu?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a més fotos i vídeos del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gravi àudio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gravi àudio al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"L\'aplicació només podrà gravar àudio mentre l\'estiguis utilitzant"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gravi àudio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gravi àudio al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"És possible que aquesta aplicació vulgui gravar àudio sempre, fins i tot quan no l\'estiguis utilitzant. "<annotation id="link">"Pots permetre-ho a la configuració"</annotation>"."</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Vols canviar l\'accés al micròfon de l\'aplicació &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Vols canviar l\'accés al micròfon de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Aquesta aplicació vol gravar àudio sempre, fins i tot quan no l\'estiguis utilitzant. "<annotation id="link">"Pots permetre-ho a la configuració"</annotation>"."</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la teva activitat física?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la teva activitat física al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci fotos i gravi vídeos?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci fotos i gravi vídeos al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"L\'aplicació només podrà fer fotos i gravar vídeos mentre l\'estiguis utilitzant"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci fotos i gravi vídeos?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci fotos i gravi vídeos al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"És possible que aquesta app vulgui fer fotos i gravar vídeos sempre, fins i tot quan no l\'estiguis utilitzant. "<annotation id="link">"Pots permetre-ho a la configuració"</annotation>"."</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Vols canviar l\'accés a la càmera de l\'aplicació &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Vols canviar l\'accés a la càmera de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Aquesta aplicació vol fer fotos i gravar vídeos sempre, fins i tot quan no l\'estiguis utilitzant. "<annotation id="link">"Pots permetre-ho a la configuració"</annotation>"."</string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi als registres de trucades del telèfon?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi als registres de trucades del dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci trucades telefòniques i les gestioni?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci trucades i les gestioni al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les dades del sensor de constants vitals?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les dades del sensor sobre les constants vitals al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Aquesta aplicació vol accedir a les dades del sensor sobre les constants vitals sempre, fins i tot quan no l\'utilitzis. Per fer aquest canvi, "<annotation id="link">"ves a la configuració"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les dades dels sensors sobre les constants vitals?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les dades del sensor sobre les constants vitals al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Per permetre que l\'aplicació accedeixi sempre a les dades del sensor corporal, fins i tot quan no la utilitzis, "<annotation id="link">"ves a la configuració"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Vols continuar permetent que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les dades del sensor corporal mentre s\'utilitza?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a les dades del sensor corporal del &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mentre s\'utilitza?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; t\'enviï notificacions?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; t\'enviï notificacions al dispositiu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Permisos controlats"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> té accés a la ubicació"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"La teva organització permet a <xliff:g id="APP_NAME">%1$s</xliff:g> accedir a la teva ubicació"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Altres permisos"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permís utilitzat pel sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permisos utilitzats només per les aplicacions del sistema."</string>
@@ -520,7 +557,7 @@
<string name="blocked_microphone_title" msgid="1631517143648232585">"El micròfon del dispositiu està bloquejat"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"La ubicació del dispositiu està desactivada"</string>
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Per a aplicacions i serveis"</string>
- <string name="blocked_mic_summary" msgid="8960466941528458347">"És possible que les dades del micròfon es continuïn compartint quan truquis a un número d\'emergència."</string>
+ <string name="blocked_mic_summary" msgid="8960466941528458347">"És possible que les dades del micròfon es comparteixin si truques a un número d\'emergència."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Canvia"</string>
<string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Seguretat i privadesa"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"Analitza el dispositiu"</string>
@@ -582,7 +619,7 @@
<string name="camera_toggle_title" msgid="1251201397431837666">"Accés a la càmera"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Accés al micròfon"</string>
<string name="perm_toggle_description" msgid="7801326363741451379">"Per a aplicacions i serveis"</string>
- <string name="mic_toggle_description" msgid="9163104307990677157">"Per a aplicacions i serveis. Si aquesta opció de configuració està desactivada, és possible que les dades del micròfon es continuïn compartint quan truquis a un número d\'emergència."</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Per a aplicacions i serveis. És possible que les dades del micròfon es comparteixin si truques a un número d\'emergència encara que aquesta opció estigui desactivada."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Mostra les aplicacions i els serveis que tinguin accés a la ubicació"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Mostra l\'accés al porta-retalls"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Mostra un missatge quan les aplicacions accedeixen al text, a les imatges o a qualsevol altre contingut que hagis copiat"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Aquesta aplicació ha indicat que és possible que comparteixi dades d\'ubicació amb tercers"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Compartició de dades i ubicació"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"D\'on prové la informació de la compartició de dades"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"El desenvolupador ha proporcionat informació al fabricant del dispositiu sobre com comparteix dades aquesta app. És possible que el desenvolupador actualitzi aquesta informació al llarg del temps."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"El desenvolupador ha proporcionat informació a "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" sobre com comparteix dades aquesta aplicació. És possible que el desenvolupador actualitzi aquesta informació al llarg del temps."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"L\'aplicació pot compartir dades d\'ubicació per a:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"La compartició de dades varia"</string>
@@ -608,11 +646,9 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Seguretat de les dades"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Pot ser que les dades d\'ubicació es comparteixin"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Aquesta aplicació ha indicat que és possible que comparteixi les teves dades d\'ubicació amb tercers"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"No es pot obrir aquest enllaç"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Canvis en la compartició de dades per a la ubicació"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Revisa les aplicacions que han canviat la manera en què poden compartir les teves dades d\'ubicació"</string>
- <string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Aquestes aplicacions han canviat la manera en què poden compartir les teves dades d\'ubicació. Pot ser que no les hagin compartit abans o que ara les comparteixin amb finalitats publicitàries o de màrqueting."</string>
+ <string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Aquestes aplicacions han canviat la manera en què poden compartir les teves dades d\'ubicació. Pot ser que no les hagin compartit abans o que ara les comparteixin amb finalitats de màrqueting o publicitat."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Els desenvolupadors d\'aquestes aplicacions han proporcionat informació sobre les seves pràctiques de compartició de dades a una botiga d\'aplicacions. És possible que actualitzin la informació al llarg del temps.\n\nLes pràctiques de compartició de dades poden variar segons la versió de l\'aplicació, l\'ús, la regió i l\'edat."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Informació sobre la compartició de dades"</string>
<string name="shares_location_with_third_parties" msgid="2278051743742057767">"Les teves dades d\'ubicació ara es comparteixen amb tercers"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Canvis en la compartició de dades"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Algunes aplicacions han canviat la manera en què poden compartir les teves dades d\'ubicació"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Configuració"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"S\'hi ha accedit a les <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"S\'hi va accedir ahir a les <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"S\'hi ha accedit el dia <xliff:g id="TIME_DATE_0">%1$s</xliff:g> a les <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-cs-v33/strings.xml b/PermissionController/res/values-cs-v33/strings.xml
index e4dc33497..2e30db000 100644
--- a/PermissionController/res/values-cs-v33/strings.xml
+++ b/PermissionController/res/values-cs-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Další upozornění"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Zavřená upozornění"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Rozbalením zobrazíte jedno další upozornění}few{Rozbalením zobrazíte # další upozornění}many{Rozbalením zobrazíte # dalšího upozornění}other{Rozbalením zobrazíte # dalších upozornění}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Upozornění. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Akce dokončena"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Zkontrolujte nastavení, která mohou zvýšit ochranu vašeho zařízení"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Rychlé nastavení ochrany soukromí a zabezpečení"</string>
diff --git a/PermissionController/res/values-cs-v34/strings.xml b/PermissionController/res/values-cs-v34/strings.xml
index 828529402..b7e982b21 100644
--- a/PermissionController/res/values-cs-v34/strings.xml
+++ b/PermissionController/res/values-cs-v34/strings.xml
@@ -20,8 +20,8 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Zabezpečení a ochrana soukromí"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Ovládací prvky"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Spravovat přístup aplikací ke zdravotním údajům"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Správa přístupu aplikací ke zdravotním údajům"</string>
<string name="location_settings" msgid="8863940440881290182">"Přístup k poloze"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Aplikace a služby. Pokud je toto nastavení vypnuté a zavoláte na číslo tísňového volání, mohou být nadále sdílena data z mikrofonu"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Aplikace a služby. Pokud je toto nastavení vypnuté a zavoláte na číslo tísňového volání, data z mikrofonu bude možné nadále sdílet"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Aplikace a služby"</string>
</resources>
diff --git a/PermissionController/res/values-cs/strings.xml b/PermissionController/res/values-cs/strings.xml
index 22c104568..571606828 100644
--- a/PermissionController/res/values-cs/strings.xml
+++ b/PermissionController/res/values-cs/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Další informace"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Povolit vše"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Vždy zobrazit vše"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Povolit omezený přístup"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Vybrat fotky a videa"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Vybrat další"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nevybírat další"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikace"</string>
<string name="app_permissions" msgid="3369917736607944781">"Oprávnění aplikace"</string>
<string name="unused_apps" msgid="2058057455175955094">"Nepoužívané aplikace"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Upravit vybrané fotky pro tuto aplikaci"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Žádné nepoužívané aplikace"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Žádné nepoužívané aplikace"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nedávná rozhodnutí o oprávnění"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Všechna oprávnění"</string>
<string name="other_permissions" msgid="2901186127193849594">"Ostatní oprávnění aplikace"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Žádost o oprávnění"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Akce instalace/odinstalace nejsou v zařízení Wear podporovány."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Určete, k čemu aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povolíte přístup"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; byla aktualizována. Určete, k čemu jí povolíte přístup."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Zrušit"</string>
@@ -196,7 +196,7 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"Používat přesnou polohu"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Když je přesná poloha vypnutá, aplikace mají přístup k vaší přibližné poloze"</string>
<string name="app_permission_title" msgid="2090897901051370711">"Oprávnění: <xliff:g id="PERM">%1$s</xliff:g>"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"Aplikace má přístup k: <xliff:g id="PERM">%1$s</xliff:g>"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"Přístup této aplikace k oprávnění: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Zobrazit všechna oprávnění aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Zobrazit všechny aplikace s tímto oprávněním"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Zobrazit používání mikrofonu asistentem"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Odebrat oprávnění, pokud se aplikace nepoužívá"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Odebrat oprávnění a uvolnit místo"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pozastavit aktivitu při nepoužívání"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Spravovat aplikaci, pokud se nepoužívá"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Odebrat oprávnění, smazat dočasné soubory a zastavit oznámení"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Odebrat oprávnění, smazat dočasné soubory, zastavit oznámení a archivovat aplikaci"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Pokud tuto aplikaci několik měsíců nepoužijete, kvůli ochraně vašich dat jí budou oprávnění odebrána."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Pokud tuto aplikaci několik měsíců nepoužijete, budou jí kvůli ochraně vašich dat odebrána následující oprávnění: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Za účelem ochrany vašich dat byla odebrána oprávnění aplikacím, které jste několik měsíců nepoužili."</string>
@@ -399,8 +401,18 @@
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Tato služba sdílí vaše fotky, média a oznámení z telefonu s ostatními zařízeními."</string>
<string name="role_notes_label" msgid="7451627001058089536">"Výchozí aplikace pro poznámky"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikace pro poznámky"</string>
- <string name="role_notes_description" msgid="8496852798616883551">"Aplikace, které umožňují dělat si na zařízení poznámky"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"Aplikace, které umožňují dělat si na zařízení poznámky."</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"poznámky"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Aktuálně výchozí"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Příště se neptat"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Změnit na výchozí"</string>
@@ -431,7 +443,7 @@
<string name="default_app_no_apps" msgid="115720991680586885">"Žádné aplikace"</string>
<string name="car_default_app_selected" msgid="5416420830430644174">"Vybráno"</string>
<string name="car_default_app_selected_with_info" msgid="1932204186080593500">"Vybráno – <xliff:g id="ADDITIONAL_INFO">%1$s</xliff:g>"</string>
- <string name="special_app_access_search_keyword" msgid="8032347212290774210">"přístup ke speciálním aplikacím"</string>
+ <string name="special_app_access_search_keyword" msgid="8032347212290774210">"zvláštní přístup aplikací"</string>
<string name="special_app_access" msgid="5019319067120213797">"Přístupy pro aplikace"</string>
<string name="no_special_app_access" msgid="6950277571805106247">"Žádný přístup ke spec. aplik."</string>
<string name="special_app_access_no_apps" msgid="4102911722787886970">"Žádné aplikace"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Zobrazit detekci spuštění asistenta"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Zobrazovat na stavovém řádku ikonu, když bude pomocí mikrofonu aktivován hlasový asistent"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k fotkám a mediálnímu obsahu v zařízení?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k fotkám a médiím v zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup ke kontaktům?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; přístup k vašim kontaktům?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k poloze tohoto zařízení?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k poloze zařízení &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikace bude mít přístup k poloze, pouze když ji budete používat"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k poloze tohoto zařízení?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k poloze zařízení &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Aplikace může požadovat přístup k poloze vždy, i když ji nebudete používat. "<annotation id="link">"Povolit ho můžete v nastavení"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Změnit přístup k poloze pro aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Změnit na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; přístup aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; k poloze?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Aplikace požaduje přístup k poloze vždy, i když ji nebudete používat. "<annotation id="link">"Povolit ho můžete v nastavení"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; najít zařízení v okolí, připojit se k nim a zjistit jejich relativní polohu?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; najít zařízení v okolí, připojit se k nim a zjistit jejich relativní polohu?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; najít zařízení v okolí, připojit se k nim a zjistit jejich relativní polohu? "<annotation id="link">"Povolit to můžete v nastavení."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Změnit přístup aplikace <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> k poloze z přibližné na přesnou?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Změnit na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; přístup aplikace <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> k poloze z přibližné na přesnou?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k přibližné poloze tohoto zařízení?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k přibližné poloze zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Přesná"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Přibližná"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup ke kalendáři?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup ke kalendáři na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; odesílat a zobrazovat SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; odesílat a zobrazovat SMS?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k fotkám, mediálnímu obsahu a souborům v zařízení?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k fotkám, médiím a videím v zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k &lt;b&gt;fotkám, videím, hudbě a zvuku&lt;/b&gt; v zařízení?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k &lt;b&gt;fotkám, videím, hudbě, zvuku a dalším souborům&lt;/b&gt; v zařízení?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k hudbě a zvuku v zařízení?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k hudbě a zvukovému obsahu v zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k fotkám a videím v zařízení?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k fotkám a videím v zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k dalším fotkám a videím v zařízení?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k dalším fotkám a videím v zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?​"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nahrávat zvuk?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nahrávat na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; zvuk?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikace bude moci zaznamenávat zvuk, pouze když ji budete používat"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nahrávat zvuk?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nahrávat na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; zvuk?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Tato aplikace může chtít zaznamenávat zvuk kdykoli, dokonce i když ji nepoužíváte. "<annotation id="link">"Povolit v nastavení"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Změnit přístup k mikrofonu pro aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Změnit na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; přístup aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; k mikrofonu?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Tato aplikace chce zaznamenávat zvuk kdykoli, dokonce i když ji nepoužíváte. "<annotation id="link">"Povolit v nastavení"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k vaší fyzické aktivitě?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; přístup k vaší fyzické aktivitě?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotit a nahrávat videa?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotit na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; a nahrávat na něm video?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikace bude moci pořizovat snímky a nahrávat videa, pouze když ji budete používat"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotit a nahrávat videa?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotit na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; a nahrávat na něm video?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Tato aplikace může chtít pořizovat snímky a nahrávat videa kdykoli, dokonce i když ji nepoužíváte. "<annotation id="link">"Povolit v nastavení"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Změnit přístup k fotoaparátu pro aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Změnit na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; přístup aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; k mikrofonu?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Tato aplikace chce pořizovat snímky a nahrávat videa kdykoli, dokonce i když ji nepoužíváte. "<annotation id="link">"Povolit v nastavení"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k seznamu telefonních hovorů?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k vašim seznamům hovorů na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uskutečňovat a spravovat telefonní hovory?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uskutečňovat a spravovat na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; telefonní hovory?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k údajům ze senzorů vašich životních funkcí?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; přístup k datům ze senzorů životních funkcí?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Aplikace požaduje přístup k datům ze senzorů vašich životních funkcí vždy, i když ji nebudete používat. Pokud tuto změnu chcete provést, "<annotation id="link">"přejděte do nastavení."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; přístup k datům ze senzorů vašich životních funkcí?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; přístup k datům ze senzorů životních funkcí?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Pokud chcete této aplikaci povolit trvalý přístup k datům z tělesných senzorů, i když aplikaci nepoužíváte, "<annotation id="link">"přejděte do nastavení"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Chcete, aby aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dál měla přístup k datům z tělesných senzorů během používání aplikace?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Chcete, aby aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; měla během používání i nadále přístup k datům z tělesných senzorů?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; odesílat oznámení?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Povolit aplikaci &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; odesílat na zařízení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; oznámení?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Spravovaná oprávnění"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> má přístup k poloze"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Vaše organizace umožňuje aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g> přístup k vaší poloze"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Jiná oprávnění"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Oprávnění používaná systémem"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Oprávnění, která jsou používaná pouze systémovými aplikacemi."</string>
@@ -518,7 +555,7 @@
<string name="exempt_info_label" msgid="6286190981253476699">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> je chráněna Androidem. Protože se vaše data zpracovávají na tomto zařízení, oprávnění používaná touto aplikací se nezobrazují na panelu ochrany soukromí."</string>
<string name="blocked_camera_title" msgid="1128510551791284384">"Fotoaparát zařízení je blokován"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"Mikrofon zařízení je blokován"</string>
- <string name="blocked_location_title" msgid="2005608279812892383">"Ukládání polohy zařízení je vypnuté"</string>
+ <string name="blocked_location_title" msgid="2005608279812892383">"Zjišťování polohy zařízení je vypnuté"</string>
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Pro aplikace a služby"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Když zavoláte na číslo tísňového volání, mohou být nadále sdílena data z mikrofonu."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Změnit"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Tato aplikace uvedla, že může sdílet údaje o poloze se třetími stranami"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Sdílení dat a poloha"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Odkud informace o sdílení dat pocházejí"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Vývojář poskytl výrobci tohoto zařízení informace o tom, jak tato aplikace sdílí data. Tyto informace může vývojář průběžně aktualizovat."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Vývojář poskytl obchodu "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" informace o tom, jak tato aplikace sdílí data. Tyto informace může vývojář průběžně aktualizovat."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Možné účely sdílení údajů o poloze touto aplikací:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Sdílení dat se liší"</string>
@@ -608,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Zabezpečení údajů"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Mohou být sdíleny údaje o poloze"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Tato aplikace uvedla, že může sdílet údaje o vaší poloze se třetími stranami"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Odkaz nelze otevřít"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Aktualizace sdílení údajů o poloze"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"Zkontrolujte aplikace, které změnily způsob, jakým mohou sdílet údaje o vaší poloze"</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"Kontrola aplikací, které změnily způsob, jakým mohou sdílet údaje o vaší poloze"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Tyto aplikace změnily způsob, jakým mohou sdílet údaje o vaší poloze. Buď je dříve nesdílely, nebo je nyní mohou sdílet pro reklamní nebo marketingové účely."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Vývojáři těchto aplikací poskytli obchodu s aplikacemi informace o svých postupech sdílení dat. Tyto informace mohou průběžně aktualizovat.\n\nPostupy sdílení dat se mohou lišit v závislosti na verzi aplikace, použití, oblasti a věku uživatele."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Informace o sdílení dat"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Aktualizace sdílení dat"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Některé aplikace změnily způsob, kterým mohou sdílet údaje o vaší poloze"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Nastavení"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Poslední přístup: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Poslední přístup: včera v <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Poslední přístup: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-da-v33/strings.xml b/PermissionController/res/values-da-v33/strings.xml
index 91351105a..3e532459f 100644
--- a/PermissionController/res/values-da-v33/strings.xml
+++ b/PermissionController/res/values-da-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Flere underretninger"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Lukkede underretninger"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Udvid for at se én yderligere advarsel}one{Udvid for at se # yderligere advarsel}other{Udvid for at se # yderligere advarsler}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Underretning. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Handlingen er udført"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Tjek indstillinger, der kan øge sikkerheden på din enhed"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Kvikmenu for sikkerheds- og privatlivsindstillinger"</string>
diff --git a/PermissionController/res/values-da/strings.xml b/PermissionController/res/values-da/strings.xml
index b34c8adc1..0f1534caa 100644
--- a/PermissionController/res/values-da/strings.xml
+++ b/PermissionController/res/values-da/strings.xml
@@ -31,9 +31,10 @@
<string name="grant_dialog_button_deny_and_dont_ask_again" msgid="1748925431574312595">"Tillad ikke, og spørg ikke igen"</string>
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Behold \"Mens appen er i brug\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Behold \"Kun denne ene gang\""</string>
- <string name="grant_dialog_button_more_info" msgid="213350268561945193">"Mere info"</string>
+ <string name="grant_dialog_button_more_info" msgid="213350268561945193">"Flere oplysninger"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Tillad alle"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Tillad altid alle"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Tillad begrænset adgang"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Vælg billeder og videoer"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Vælg flere"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Vælg ikke flere"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"Apptilladelser"</string>
<string name="unused_apps" msgid="2058057455175955094">"Apps, du ikke bruger"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Rediger valget af billeder for denne app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Ingen ubrugte apps"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Der er 0 ubrugte apps"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nylige beslutninger om tilladelser"</string>
@@ -68,7 +70,7 @@
<string name="auto_permission_manager_summary" msgid="9157438376234301354">"Administrer adgang til data for kalender, opkaldshistorik m.m."</string>
<string name="granted_permission_decision" msgid="7824827491551861365">"Du har givet <xliff:g id="APP_NAME">%1$s</xliff:g> adgang til <xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
<string name="denied_permission_decision" msgid="5308961501779563781">"Du har nægtet <xliff:g id="APP_NAME">%1$s</xliff:g> adgang til <xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
- <string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{I dag}=1{For 1 dag siden}one{for # dag siden}other{for # dage siden}}"</string>
+ <string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{I dag}=1{1 dag siden}one{# dag siden}other{# dage siden}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"Deaktiver appen"</string>
<string name="app_disable_dlg_text" msgid="3126943217146120240">"Hvis du deaktiverer denne app, kan det medføre, at Android-apps og andre apps ikke fungerer korrekt. Vær opmærksom på, at du ikke kan slette denne app, da den er forudinstalleret på din enhed. Hvis du slår appen fra, deaktiveres og skjules den på din enhed."</string>
<string name="app_permission_manager" msgid="3903811137630909550">"Tilladelses­administrator"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Alle tilladelser"</string>
<string name="other_permissions" msgid="2901186127193849594">"Andre app-egenskaber"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Anmodning om tilladelse"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Det er ikke muligt at installere/afinstallere på Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Vælg, hvad &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; må få adgang til"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; er blevet opdateret. Vælg, hvad denne app må få adgang til."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Annuller"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Fjern tilladelser, hvis appen ikke bruges"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Fjern tilladelser, og frigør plads"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Sæt appaktivitet på pause ved inaktivitet"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Administrer appen, hvis den ikke bruges"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Fjern tilladelser, slet midlertidige filer, og stop notifikationer"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Fjern tilladelser, slet midlertidige filer, deaktiver notifikationer, og arkivér appen"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Hvis appen ikke bliver brugt i et par måneder, fjernes tilladelser for appen for at beskytte dine data."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Hvis appen ikke bliver brugt i et par måneder, fjernes følgende tilladelser for at beskytte dine data: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Tilladelserne til apps, du ikke har brugt i et par måneder, er blevet fjernet for at beskytte dine data."</string>
@@ -263,7 +265,7 @@
<string name="auto_revoke_permission_reminder_notification_content" msgid="4492228990462107487">"Nogle tilladelser blev fjernet for at beskytte dit privatliv. Tryk for at gennemgå dem"</string>
<string name="auto_revoke_permission_notification_title" msgid="2629844160853454657">"Tilladelser er fjernet for ubrugte apps"</string>
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Nogle apps er ikke blevet brugt i et par måneder. Tryk for at gennemgå dem."</string>
- <string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ubrugt app}one{# ubrugt app}other{# ubrugt apps}}"</string>
+ <string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ubrugt app}one{# ubrugt app}other{# ubrugte apps}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Tilladelser og midlertidige filer er blevet fjernet, og notifikationer blev stoppet. Tryk for at se."</string>
<string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Gennemgå apps, som har fået fjernet tilladelser"</string>
<string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Tilladelser og midlertidige filer for de apps, du ikke har brugt for nylig, blev fjernet, og notifikationer ophørte."</string>
@@ -295,13 +297,13 @@
<string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Se apps med fuld adgang"</string>
<string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Adgangen er blevet fjernet"</string>
<string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android-system"</string>
- <string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Apptilladelserne blev fjernet for at beskytte dine personlige oplysninger"</string>
+ <string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Apptilladelserne blev fjernet for at beskytte dit privatliv"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> er ikke blevet brugt i et par måneder. Tryk for at gennemgå."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> og 1 anden app er ikke blevet brugt i et par måneder. Tryk for at gennemgå."</string>
<string name="auto_revoke_after_notification_content_many" msgid="4774106206289751220">"<xliff:g id="APP_NAME">%1$s</xliff:g> og <xliff:g id="NUMBER_OF_APPS">%2$s</xliff:g> andre apps er ikke blevet brugt i et par måneder. Tryk for at gennemgå."</string>
<string name="auto_revoke_before_notification_title_one" msgid="6758024954464359876">"1 app bruges ikke"</string>
<string name="auto_revoke_before_notification_title_many" msgid="4415543943846385685">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> apps bruges ikke"</string>
- <string name="auto_revoke_before_notification_content_one" msgid="1156635373417068822">"Tilladelserne fjernes for at beskytte dine personlige oplysninger. Tryk for at gennemgå."</string>
+ <string name="auto_revoke_before_notification_content_one" msgid="1156635373417068822">"Tilladelserne fjernes for at beskytte dit privatliv. Tryk for at gennemgå."</string>
<string name="unused_apps_title" msgid="8589298917717872239">"Apps, du ikke bruger"</string>
<string name="unused_apps_subtitle_after" msgid="2034267519506357898">"Tilladelserne blev fjernet fra"</string>
<string name="unused_apps_subtitle_before" msgid="5233302577076132427">"Tilladelserne fjernes fra"</string>
@@ -373,7 +375,7 @@
<string name="role_emergency_request_title" msgid="8469579020654348567">"Vil du angive <xliff:g id="APP_NAME">%1$s</xliff:g> som din standardnødapp?"</string>
<string name="role_emergency_request_description" msgid="131645948770262850">"Der kræves ingen tilladelser"</string>
<string name="role_emergency_search_keywords" msgid="1920007722599213358">"i nødsituationer"</string>
- <string name="role_home_label" msgid="3871847846649769412">"Standardstartapp"</string>
+ <string name="role_home_label" msgid="3871847846649769412">"Standard­startapp"</string>
<string name="role_home_short_label" msgid="8544733747952272337">"Startapp"</string>
<string name="role_home_description" msgid="7997371519626556675">"Apps (ofte kaldet launchers), som erstatter startskærmene på din Android-enhed og giver dig adgang til indhold og funktioner på din enhed"</string>
<string name="role_home_request_title" msgid="738136983453341081">"Vil du angive <xliff:g id="APP_NAME">%1$s</xliff:g> som din standardstartapp?"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"App til notetagning"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps, som giver dig mulighed for at tage noter på din enhed"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"noter"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Nuværende standardapp"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Spørg ikke igen"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Angiv som standard"</string>
@@ -443,7 +455,7 @@
<string name="incident_report_notification_text" msgid="3376480583513587923">"<xliff:g id="APP_NAME">%1$s</xliff:g> vil gerne uploade fejretningsoplysninger."</string>
<string name="incident_report_dialog_title" msgid="669104389325204095">"Vil du dele fejlretningsdata?"</string>
<string name="incident_report_dialog_intro" msgid="5897733669850951832">"Systemet har registreret et problem."</string>
- <string name="incident_report_dialog_text" msgid="5675553296891757523">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> anmoder om at uploade en fejlrapport fra denne enhed, som stammer fra <xliff:g id="DATE">%2$s</xliff:g> kl. <xliff:g id="TIME">%3$s</xliff:g>. Fejlrapporter indeholder personlige oplysninger om din enhed eller registreres af apps, f.eks. brugernavne, steddata, enheds-id\'er og netværksoplysninger. Oplysningerne i fejlrapporterne må kun deles med personer og apps, du har tillid til. Vil du give <xliff:g id="APP_NAME_1">%4$s</xliff:g> tilladelse til at uploade en fejlrapport?"</string>
+ <string name="incident_report_dialog_text" msgid="5675553296891757523">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> anmoder om at uploade en fejlrapport fra denne enhed, som stammer fra <xliff:g id="DATE">%2$s</xliff:g> kl. <xliff:g id="TIME">%3$s</xliff:g>. Fejlrapporter indeholder personlige oplysninger om din enhed eller registreres af apps, f.eks. brugernavne, lokationsdata, enheds-id\'er og netværksoplysninger. Oplysningerne i fejlrapporterne må kun deles med personer og apps, du har tillid til. Vil du give <xliff:g id="APP_NAME_1">%4$s</xliff:g> tilladelse til at uploade en fejlrapport?"</string>
<string name="incident_report_error_dialog_text" msgid="4189647113387092272">"Der opstod en fejl i behandlingen af fejlrapporten for <xliff:g id="APP_NAME">%1$s</xliff:g>. Det er derfor ikke muligt at dele detaljerede fejlretningsdata. Vi beklager ulejligheden."</string>
<string name="incident_report_dialog_allow_label" msgid="2970242967721155239">"Tillad"</string>
<string name="incident_report_dialog_deny_label" msgid="3535314290677579383">"Afvis"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Vis aktiveringsregistrering for assistenten"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Vis ikon på statusbjælken, når mikrofonen bruges til at aktivere taleassistenten"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til billeder og medier på din enhed?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til billeder og medier på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til dine kontakter?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til dine kontakter på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til enhedens lokation?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til lokationen for din &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Appen har kun adgang til lokationen, når du bruger appen"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til enhedens lokation?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til lokationen for din &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Denne app vil muligvis gerne have adgang til din lokation hele tiden, også når du ikke bruger appen. "<annotation id="link">"Giv tilladelse under Indstillinger."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Vil du skifte lokationsadgang for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Vil du ændre lokationsadgangen for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Appen vil gerne have adgang til din lokation hele tiden, også når du ikke bruger appen. "<annotation id="link">"Giv appen tilladelse i Indstillinger."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Skal &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kunne finde, oprette forbindelse til og fastslå den relative placering af enheder i nærheden?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at finde, oprette forbindelse til og bestemme den relative position af enheder i nærheden på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Skal &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kunne finde, oprette forbindelse til og fastslå den relative placering af enheder i nærheden? "<annotation id="link">"Tillad i Indstillinger."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Vil du skifte lokationsadgang for <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> fra omtrentlig til nøjagtig?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Vil du ændre lokationsadgangen for <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; fra omtrentlig til præcis?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til enhedens omtrentlige lokation?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til den omtrentlige lokation for din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Præcis"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Omtrentlig"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til din kalender?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til din kalender på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at sende og se sms-beskeder?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at sende og se sms-beskeder på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til billeder, medier og filer på din enhed?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til billeder, medier og filer på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til &lt;b&gt;billeder, videoer, musik og lyd&lt;/b&gt; på denne enhed?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til &lt;b&gt;billeder, videoer, musik, lyd og andre filer&lt;/b&gt; på denne enhed?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til musik og lyd på denne enhed?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til musik og lyd på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til billeder og videoer på denne enhed?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til billeder og videoer på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at tilgå flere billeder og videoer på denne enhed?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til flere billeder og videoer på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at optage lyd?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at optage lyd på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Appen kan kun optage lyd, mens du bruger appen"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at optage lyd?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at optage lyd på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Denne app vil gerne optage lyd hele tiden, også når du ikke bruger appen. "<annotation id="link">"Tillad dette i indstillingerne"</annotation>"."</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Vil du skifte mikrofonadgang for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Vil du ændre mikrofonadgangen for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Denne app vil gerne optage lyd hele tiden, også når du ikke bruger appen. "<annotation id="link">"Tillad dette i indstillingerne"</annotation>"."</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Vil du tillade, at &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; får adgang til din fysiske aktivitet?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til din fysiske aktivitet på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at tage billeder og optage video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at tage billeder og optage video på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Appen kan kun tage billeder og optage video, mens du bruger appen"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at tage billeder og optage video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at tage billeder og optage video på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Denne app vil gerne tage billeder og optage video hele tiden, også når du ikke bruger appen. "<annotation id="link">"Tillad dette i indstillingerne"</annotation>"."</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Vil du skifte kameraadgang for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Vil du ændre kameraadgangen for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Denne app vil gerne tage billeder og optage video hele tiden, også når du ikke bruger appen. "<annotation id="link">"Tillad dette i indstillingerne"</annotation>"."</string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til dine opkaldslister?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til din historik over telefonopkald på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at foretage og administrere telefonopkald?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at foretage og administrere telefonopkald på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til sensordata om dine vitale værdier?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til sensordata om dine vitale værdier på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Denne app anmoder om at tilgå sensordataene om dine vitale værdier hele tiden, også når du ikke bruger appen. Du kan foretage denne ændring ved at "<annotation id="link">"gå til indstillingerne."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til sensordataene om dine vitale værdier?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til sensordataene om dine vitale værdier på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Du kan give denne app adgang til kropssensordata hele tiden – selv når du ikke bruger appen – ved at "<annotation id="link">"gå til indstillingerne."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Vil du fortsætte med at give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til kropssensordata, mens appen er i brug?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Vil du fortsat give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til kropssensordata på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;, mens appen er i brug?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at sende dig notifikationer?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilladelse til at sende dig notifikationer på din &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Administrerede tilladelser"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> har lokationsadgang"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Din organisation har givet <xliff:g id="APP_NAME">%1$s</xliff:g> tilladelse til at tilgå din lokation"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Andre tilladelser"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Tilladelse, der anvendes af systemet"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Tilladelser, der kun anvendes af systemapps"</string>
@@ -591,11 +628,12 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Denne app har angivet, at den muligvis deler lokationsdata med tredjeparter"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Datadeling og lokation"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Hvor oplysninger om datadeling stammer fra"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Udvikleren har stillet oplysninger om, hvordan denne app deler data, til rådighed for producenten af denne enhed. Udvikleren opdaterer muligvis disse oplysninger senere."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Udvikleren gav oplysninger til "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" om, hvordan denne app deler data. Udvikleren opdaterer muligvis disse oplysninger senere."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Denne app deler muligvis lokationsdata for:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datadeling varierer"</string>
- <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Databehandlingen kan variere afhængigt af din appversion, din brug, dit område og din alder. "<annotation id="link">"Flere oplysninger om datadeling"</annotation></string>
- <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Databehandlingen kan variere afhængigt af din appversion, din brug, dit område og din alder."</string>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Databehandlingen kan variere afhængigt af din appversion, din brug, din region og din alder. "<annotation id="link">"Flere oplysninger om datadeling"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Databehandlingen kan variere afhængigt af din appversion, din brug, din region og din alder."</string>
<string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Dine lokationsdata"</string>
<string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Skift denne apps adgang i "<annotation id="link">"privatlivsindstillingerne"</annotation></string>
<string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Appfunktionalitet"</string>
@@ -603,17 +641,15 @@
<string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Kommunikation fra udvikleren"</string>
<string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Annoncering eller marketing"</string>
<string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Sikkerhed, overholdelse og forebyggelse af svindel"</string>
- <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Tilpasning"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personlig tilpasning"</string>
<string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Kontoadministration"</string>
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Datasikkerhed"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Lokationsdata deles muligvis"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Denne app har angivet, at den muligvis deler dine lokationsdata med tredjeparter"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Dette link kan ikke åbnes"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Opdateringer om deling af lokationsdata"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Gennemse apps, der har ændret måden, hvorpå de kan dele dine lokationsdata"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Disse apps har ændret den måde, hvorpå de kan dele dine lokationsdata. De har muligvis ikke delt dataene før eller kan nu anvende dem til annoncering eller marketing."</string>
- <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Udviklerne af disse apps har givet oplysninger om deres procedurer for datadeling til en appbutik. De kan opdatere procedurerne med tiden.\n\nProcedurer for datadeling kan variere afhængigt af din appversion, din brug, dit område og din alder."</string>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Udviklerne af disse apps har givet oplysninger om deres procedurer for datadeling til en appbutik. De kan opdatere procedurerne med tiden.\n\nProcedurer for datadeling kan variere afhængigt af din appversion, din brug, din region og din alder."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Få flere oplysninger om deling af data"</string>
<string name="shares_location_with_third_parties" msgid="2278051743742057767">"Dine lokationsdata deles nu med tredjeparter"</string>
<string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Dine lokationsdata deles nu med tredjeparter med henblik på annoncering eller marketing"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Opdateringer om datadeling"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Nogle apps har ændret måden, hvorpå de kan dele dine lokationsdata"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Indstillinger"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Tilgået kl. <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Tilgået i går kl. <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Tilgået <xliff:g id="TIME_DATE_0">%1$s</xliff:g> kl. <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-de-v33/strings.xml b/PermissionController/res/values-de-v33/strings.xml
index 023368660..d82bd4619 100644
--- a/PermissionController/res/values-de-v33/strings.xml
+++ b/PermissionController/res/values-de-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Weitere Benachrichtigungen"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Ausgeblendete Benachrichtigungen"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Maximieren und eine weitere Warnung anzeigen}other{Maximieren und # weitere Warnungen anzeigen}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Warnung. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Aktion abgeschlossen"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Einstellungen aufrufen, mit denen sich der Schutz meines Geräts verbessern lässt"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Schnelleinstellungen für Sicherheit und Datenschutz"</string>
diff --git a/PermissionController/res/values-de-v34/strings.xml b/PermissionController/res/values-de-v34/strings.xml
index 4a97b4d4b..ed699cce3 100644
--- a/PermissionController/res/values-de-v34/strings.xml
+++ b/PermissionController/res/values-de-v34/strings.xml
@@ -17,12 +17,11 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="security_privacy_brand_name" msgid="7303621734258440812">"Sicherheit &amp; Datenschutz"</string>
+ <string name="security_privacy_brand_name" msgid="7303621734258440812">"Datenschutz &amp; Sicherheit"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Einstellungen"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
<string name="health_connect_summary" msgid="815473513776882296">"App-Zugriff auf Gesundheitsdaten verwalten"</string>
<string name="location_settings" msgid="8863940440881290182">"Standortzugriff"</string>
- <!-- no translation found for mic_toggle_description (1504101620086616040) -->
- <skip />
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Für Apps und Dienste. Wenn du eine Notrufnummer wählst, können Mikrofondaten trotz Deaktivierung dieser Berechtigung weitergegeben werden."</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Für Apps und Dienste"</string>
</resources>
diff --git a/PermissionController/res/values-de/strings.xml b/PermissionController/res/values-de/strings.xml
index e3855033e..00f09e921 100644
--- a/PermissionController/res/values-de/strings.xml
+++ b/PermissionController/res/values-de/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Weitere Infos"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Vollen Zugriff erlauben"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Immer vollen Zugriff erlauben"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Eingeschränkten Zugriff zulassen"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Fotos und Videos auswählen"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Mehr auswählen"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Keine weiteren auswählen"</string>
@@ -58,8 +59,9 @@
<string name="grant_dialog_button_allow_all_files" msgid="4955436994954829894">"Verwaltung aller Dateien zulassen"</string>
<string name="grant_dialog_button_allow_media_only" msgid="4832877658422573832">"Zugriff auf Mediendateien zulassen"</string>
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
- <string name="app_permissions" msgid="3369917736607944781">"App-Berechtigungen"</string>
+ <string name="app_permissions" msgid="3369917736607944781">"App-Berech­tigungen"</string>
<string name="unused_apps" msgid="2058057455175955094">"Nicht verwendete Apps"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Für diese App ausgewählte Fotos bearbeiten"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Keine nicht verwendeten Apps"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Keine nicht verwendeten Apps"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Aktuelle Berechtigungsentscheidungen"</string>
@@ -71,7 +73,7 @@
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{Heute}=1{Vor 1 Tag}other{Vor # Tagen}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"App deaktivieren"</string>
<string name="app_disable_dlg_text" msgid="3126943217146120240">"Bei Deaktivierung dieser App funktionieren Android und andere Apps möglicherweise nicht mehr ordnungsgemäß. Beachte hierbei, dass du diese App nicht löschen kannst, weil sie auf deinem Gerät vorinstalliert war. Durch die Deaktivierung schaltest du diese App ab und blendest sie auf deinem Gerät aus."</string>
- <string name="app_permission_manager" msgid="3903811137630909550">"Berechtigungs­manager"</string>
+ <string name="app_permission_manager" msgid="3903811137630909550">"Berechti­gungsmanager"</string>
<string name="never_ask_again" msgid="4728762438198560329">"Nicht mehr fragen"</string>
<string name="no_permissions" msgid="3881676756371148563">"Keine Berechtigungen"</string>
<string name="additional_permissions" msgid="5801285469338873430">"Zusätzliche Berechtigungen"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Alle Berechtigungen"</string>
<string name="other_permissions" msgid="2901186127193849594">"Andere App-Funktionen"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Berechtigungsanfrage"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Installations-/Deinstallationsaktion auf Android Wear nicht unterstützt."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Worauf darf die App &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; zugreifen?"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Die App &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; wurde aktualisiert. Worauf darf diese App zugreifen?"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Abbrechen"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Berechtigungen entfernen, wenn die App nicht verwendet wird"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Berechtigungen löschen und Speicherplatz freigeben"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"App-Aktivität bei Nichtnutzung stoppen"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"App-Verhalten bei Nichtnutzung verwalten"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Berechtigungen entfernen, temporäre Dateien löschen und Benachrichtigungen stoppen"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Berechtigungen entfernen, temporäre Dateien löschen, Benachrichtigungen stoppen und die App archivieren"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Zum Schutz deiner Daten werden dieser App die Berechtigungen entzogen, wenn du sie einige Monate nicht verwendest."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Zum Schutz deiner Daten werden dieser App die folgenden Berechtigungen entzogen, wenn du sie einige Monate nicht verwendest: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Zum Schutz deiner Daten wurden Apps, die du einige Monate nicht verwendet hast, Berechtigungen entzogen."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Notizen-App"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps zum Erstellen von Notizen auf deinem Gerät"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"Notizen"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Aktueller Standard"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Nicht mehr fragen"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Als Standard festlegen"</string>
@@ -426,7 +438,7 @@
<string name="default_apps_more" msgid="4078194675848858093">"Weitere Standard-Apps"</string>
<string name="default_apps_manage_domain_urls" msgid="6775566451561036069">"Links öffnen"</string>
<string name="default_apps_for_work" msgid="4970308943596201811">"Standard-Apps für Arbeit"</string>
- <string name="default_app_none" msgid="9084592086808194457">"Keine App"</string>
+ <string name="default_app_none" msgid="9084592086808194457">"Keine"</string>
<string name="default_app_system_default" msgid="6218386768175513760">"(System-Standardeinstellung)"</string>
<string name="default_app_no_apps" msgid="115720991680586885">"Keine Apps"</string>
<string name="car_default_app_selected" msgid="5416420830430644174">"Ausgewählt"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Auslösererkennung für Assistenten anzeigen"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Symbol in der Statusleiste anzeigen, wenn das Mikrofon verwendet wird, um den Sprachassistenten zu aktivieren"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf Fotos und Medien auf deinem Gerät zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf Fotos und Medien zugreifen?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ erlauben, auf deine Kontakte zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf die Kontakte zugreifen?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, den Gerätestandort abzurufen?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>s&lt;/b&gt; auf die Standortdaten zugreifen?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Die App hat nur Zugriff auf den Gerätestandort, solange du sie verwendest"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, den Gerätestandort abzurufen?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;b&gt; auf die Standortdaten zugreifen?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Diese App möchte eventuell Zugriff auf deinen Standort haben, auch wenn du sie nicht verwendest. "<annotation id="link">"Du kannst das in den Einstellungen zulassen."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Standortzugriff für &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ändern?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Standortzugriff für &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ändern?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Diese App möchte jederzeit Zugriff auf deinen Standort haben, auch wenn du sie nicht verwendest. "<annotation id="link">"Du kannst das in den Einstellungen zulassen."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Zulassen, dass &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; Geräte in der Nähe finden, sich mit ihnen verbinden und ihre relative Position bestimmen kann?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; die relative Position von Geräten in der Nähe bestimmen und sich verbinden?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Zulassen, dass &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; Geräte in der Nähe finden, sich mit ihnen verbinden und ihre relative Position bestimmen kann? "<annotation id="link">"In den Einstellungen zulassen."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Soll der Standortzugriff von <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> von „Ungefähr“ zu „Genau“ geändert werden?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Standortzugriff von &lt;b&gt;<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; von „ungefähr“ zu „genau“ ändern?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, den ungefähren Gerätestandort abzurufen?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>s&lt;/b&gt; auf die Angaben zum ungefähren Standort zugreifen?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Genau"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Ungefähr"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf deinen Kalender zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf den Kalender zugreifen?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, SMS zu senden und aufzurufen?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dir auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; SMS-Nachrichten senden und auf sie zugreifen?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf Fotos, Medien und Dateien auf deinem Gerät zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf Fotos, Medien und Dateien zugreifen?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf &lt;b&gt;Foto-, Video-, Musik- und Audiodateien&lt;/b&gt; auf diesem Gerät zuzugreifen?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf &lt;b&gt;Foto-, Video-, Musik-, Audio- und andere Dateien&lt;/b&gt; auf diesem Gerät zuzugreifen?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf Musik- und Audiodateien auf diesem Gerät zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf Musik- und Audiodateien zugreifen?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf Fotos und Videos auf diesem Gerät zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf Fotos und Videos zugreifen?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf weitere Fotos und Videos auf diesem Gerät zugreifen?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf weitere Fotos und Videos zugreifen?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, Audioaufnahmen zu machen?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mit deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; Audioaufnahmen machen?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Diese App kann nur Audioaufnahmen machen, solange du sie verwendest"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, Audioaufnahmen zu machen?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mit deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; Audioaufnahmen machen?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Diese App möchte ggf. jederzeit Audioaufnahmen machen können, auch wenn du sie nicht verwendest. "<annotation id="link">"Du kannst das in den Einstellungen zulassen."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Mikrofonzugriff für &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ändern?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Mikrofonzugriff für &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ändern?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Diese App möchte jederzeit Audioaufnahmen machen können, auch wenn du sie nicht verwendest. "<annotation id="link">"Du kannst das in den Einstellungen zulassen."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf deine körperliche Aktivität zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf die Daten zu deinen körperlichen Aktivitäten zugreifen?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, Bilder und Videos aufzunehmen?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mit deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; Foto- und Videoaufnahmen machen?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Diese App kann nur Bilder und Videos aufnehmen, solange du sie verwendest"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, Bilder und Videos aufzunehmen?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mit deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; Foto- und Videoaufnahmen machen?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Diese App möchte ggf. jederzeit Bilder und Videos aufnehmen können, auch wenn du sie nicht verwendest. "<annotation id="link">"Du kannst das in den Einstellungen zulassen."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Kamerazugriff für &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ändern?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Kamerazugriff für &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ändern?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Diese App möchte jederzeit Bilder und Videos aufnehmen können, auch wenn du sie nicht verwendest. "<annotation id="link">"Du kannst das in den Einstellungen zulassen."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf deine Anrufliste zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf die Anruflisten zugreifen?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, Anrufe zu starten und zu verwalten?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; Anrufe starten und verwalten?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf Sensordaten zu deinen Vitalfunktionen zuzugreifen?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf Sensordaten zu deinen Vitalzeichen zugreifen?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Die App möchte jederzeit auf die Sensordaten zu deinen Vitalfunktionen zugreifen, auch wenn du sie nicht verwendest. Du kannst das "<annotation id="link">"in den Einstellungen ändern"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, auf Sensordaten zu deinen Vitalfunktionen zuzugreifen?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; auf die Sensordaten zu deinen Vitalzeichen zugreifen?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Damit diese App dauerhaft auf Daten des Körpersensors zugreifen kann, auch dann, wenn sie nicht verwendet wird, "<annotation id="link">"rufe die Einstellungen auf"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; Zugriff auf Körpersensordaten bei Verwendung weiter erlauben?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bei Nutzung der App weiter auf Körpersensordaten auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; zugreifen?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erlauben, dir Benachrichtigungen zu senden?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Darf &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dir auf deinem &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; Benachrichtigungen senden?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Erteilte Berechtigungen"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> hat Standortzugriff"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Deine Organisation erlaubt <xliff:g id="APP_NAME">%1$s</xliff:g> den Zugriff auf deinen Standort"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Weitere Berechtigungen"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Berechtigungen, die vom System verwendet werden"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Berechtigungen, die nur von Systemanwendungen verwendet werden."</string>
@@ -522,7 +559,7 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Für Apps und Dienste"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Die Mikrofondaten können immer noch geteilt werden, wenn du den Notruf wählst."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Ändern"</string>
- <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sicherheit und Datenschutz"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Datenschutz &amp; Sicherheit"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"Gerät prüfen"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Schließen"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Diese Warnung schließen?"</string>
@@ -533,7 +570,7 @@
<string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Sicherheits- und Datenschutzstatus. <xliff:g id="OVERALL_SAFETY_STATUS">%1$s</xliff:g>. <xliff:g id="SUMMARY_OF_DEVICE_STATUS">%2$s</xliff:g>"</string>
<string name="security_settings" msgid="3808106921175271317">"Sicherheitseinstellungen"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"Berechtigungen"</string>
- <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sicherheit und Datenschutz"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Datenschutz &amp; Sicherheit"</string>
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Status prüfen"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Datenschutzeinstellungen"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Weitere Einstellungen"</string>
@@ -591,13 +628,14 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"In dieser App wurde angegeben, dass sie eventuell Standortdaten an Dritte weitergibt"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Datenweitergabe und Standort"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Ursprung der Informationen zur Datenweitergabe"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Die Informationen darüber, wie diese App Daten weitergibt, hat der Hersteller des Geräts vom Entwickler erhalten. Der Entwickler kann die Art und Weise der Datenweitergabe jederzeit ändern."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Der Entwickler hat "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" Informationen darüber zur Verfügung gestellt, wie diese App Daten weitergibt. Der Entwickler kann diese Informationen jederzeit ändern."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Diese App kann Standortdaten weitergeben für:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datenweitergabe variiert"</string>
<string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Die Art der Datennutzung kann von der Version und Verwendung der App, von der Region und vom Alter des Nutzers abhängen. "<annotation id="link">"Weitere Informationen zur Datenweitergabe"</annotation></string>
<string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Die Datenschutz- und Sicherheitspraktiken können je nach App-Version, Verwendung, Region und Alter des Nutzers variieren."</string>
<string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Deine Standortdaten"</string>
- <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Du kannst den Zugriff dieser App in den "<annotation id="link">"Datenschutzeinstellungen"</annotation>" ändern"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Du kannst den Zugriff dieser App in den "<annotation id="link">"Daten­schutz­ein­stel­lun­gen"</annotation>" ändern"</string>
<string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funktionen der App"</string>
<string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytics"</string>
<string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Mitteilungen des Entwicklers"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Datensicherheit"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Die App kann Standortdaten weitergeben"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Für diese App wurde angegeben, dass deine Standortdaten an Dritte weitergegeben werden können"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Link konnte nicht geöffnet werden"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Änderungen bei der Weitergabe von Standortdaten"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Apps ansehen, bei denen sich die Art der Weitergabe deiner Standortdaten geändert hat"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Bei diesen Apps hat sich die Art der Weitergabe deiner Standortdaten geändert. Möglicherweise wurden sie zuvor nicht weitergegeben oder sie werden jetzt zu Werbe- oder Marketingzwecken weitergegeben."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Änderungen bei der Datenweitergabepraxis"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Bei einigen Apps hat sich die Art der Weitergabe deiner Standortdaten geändert"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Einstellungen"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Zugriff: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Zugriff: gestern, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Zugriff: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-el-v33/strings.xml b/PermissionController/res/values-el-v33/strings.xml
index 97291b070..4cefe7f04 100644
--- a/PermissionController/res/values-el-v33/strings.xml
+++ b/PermissionController/res/values-el-v33/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="role_dialer_request_description" msgid="6188305064871543419">"Αυτή η εφαρμογή θα μπορεί να σας στέλνει ειδοποιήσεις και θα έχει πρόσβαση στην κάμερα, τις επαφές, το μικρόφωνο, το τηλέφωνο και τα SMS."</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Αυτή η εφαρμογή θα μπορεί να σας στέλνει ειδοποιήσεις και θα έχει πρόσβαση στην κάμερα, τις επαφές, τα αρχεία, το μικρόφωνο, το τηλέφωνο και τα SMS."</string>
- <string name="permission_description_summary_storage" msgid="1917071243213043858">"Οι εφαρμογές με αυτήν την άδεια μπορούν να έχουν πρόσβαση σε όλα τα αρχεία αυτής της συσκευής"</string>
+ <string name="permission_description_summary_storage" msgid="1917071243213043858">"Οι εφαρμογές με αυτή την άδεια μπορούν να έχουν πρόσβαση σε όλα τα αρχεία αυτής της συσκευής"</string>
<string name="work_policy_title" msgid="832967780713677409">"Οι πληροφορίες πολιτικής εργασίας σας"</string>
<string name="work_policy_summary" msgid="3886113358084963931">"Η διαχείριση των ρυθμίσεων πραγματοποιείται από τον διαχειριστή IT"</string>
<string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Ανάπτυξη και εμφάνιση λίστας"</string>
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Περισσότερες ειδοποιήσεις"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Ειδοποιήσεις που παραβλέφθηκαν"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Αναπτύξτε και δείτε μία ακόμη ειδοποίηση}other{Αναπτύξτε και δείτε # ακόμη ειδοποιήσεις}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Ειδοποίηση. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Η ενέργεια ολοκληρώθηκε"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Ελέγξτε ρυθμίσεις που μπορούν να προσθέσουν προστασία στη συσκευή σας"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Γρήγορες ρυθμίσεις ασφάλειας και απορρήτου"</string>
diff --git a/PermissionController/res/values-el/strings.xml b/PermissionController/res/values-el/strings.xml
index 5d0031ed9..1e98d4ccb 100644
--- a/PermissionController/res/values-el/strings.xml
+++ b/PermissionController/res/values-el/strings.xml
@@ -32,8 +32,9 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Διατήρηση της επιλογής \"Όταν χρησιμοποιείται η εφαρμογή\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Διατήρηση μόνο αυτήν τη φορά"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Περισσότερα"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Να επιτρέπονται όλα"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Να επιτρέπεται"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Να επιτρέπονται πάντα όλα"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Να επιτρέπεται περιορισμένη πρόσβαση"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Επιλογή φωτογραφιών και βίντεο"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Επιλέξτε περισσότερα"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Να μην γίνει επιλογή περισσότερων"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Εφαρμογές"</string>
<string name="app_permissions" msgid="3369917736607944781">"Άδειες εφαρμογών"</string>
<string name="unused_apps" msgid="2058057455175955094">"Εφαρ. που δεν χρησιμοποιούνται"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Επεξεργασία επιλεγμένων φωτογραφιών για αυτή την εφαρμογή"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Όλες οι εφαρμογές χρησ/νται"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 εφαρμογές που δεν χρησ/νται"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Πρόσφατες αποφάσεις για άδειες"</string>
@@ -70,7 +72,7 @@
<string name="denied_permission_decision" msgid="5308961501779563781">"Δεν επιτρέψατε στην εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> να έχει πρόσβαση στην άδεια <xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{Σήμερα}=1{Πριν από 1 ημέρα}other{Πριν από # ημέρες}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"Απενεργοποίηση εφαρμογής"</string>
- <string name="app_disable_dlg_text" msgid="3126943217146120240">"Εάν απενεργοποιήσετε αυτήν την εφαρμογή, η λειτουργία του Android και άλλων εφαρμογών ενδέχεται να μην είναι η αναμενόμενη. Λάβετε υπόψη ότι δεν είναι δυνατή η διαγραφή αυτής της εφαρμογής καθώς ήταν προεγκατεστημένη στη συσκευή σας. Με την απενεργοποίηση, απενεργοποιείτε αυτήν την εφαρμογή και την αποκρύπτετε στη συσκευή σας."</string>
+ <string name="app_disable_dlg_text" msgid="3126943217146120240">"Εάν απενεργοποιήσετε αυτή την εφαρμογή, η λειτουργία του Android και άλλων εφαρμογών ενδέχεται να μην είναι η αναμενόμενη. Λάβετε υπόψη ότι δεν είναι δυνατή η διαγραφή αυτής της εφαρμογής καθώς ήταν προεγκατεστημένη στη συσκευή σας. Με την απενεργοποίηση, απενεργοποιείτε αυτή την εφαρμογή και την αποκρύπτετε στη συσκευή σας."</string>
<string name="app_permission_manager" msgid="3903811137630909550">"Διαχείριση αδειών"</string>
<string name="never_ask_again" msgid="4728762438198560329">"Να μην ερωτηθώ ξανά"</string>
<string name="no_permissions" msgid="3881676756371148563">"Δεν υπάρχουν άδειες"</string>
@@ -78,8 +80,8 @@
<string name="app_permissions_info_button_label" msgid="7633312050729974623">"Άνοιγμα πληροφοριών εφαρμογής"</string>
<string name="additional_permissions_more" msgid="5681220714755304407">"{count,plural, =1{# ακόμη}other{# ακόμη}}"</string>
<string name="old_sdk_deny_warning" msgid="2382236998845153919">"Αυτή η εφαρμογή σχεδιάστηκε για παλαιότερη έκδοση του Android. Η άρνηση παραχώρησης άδειας μπορεί να έχει ως αποτέλεσμα να διακοπεί η κανονική λειτουργία της."</string>
- <string name="storage_supergroup_warning_allow" msgid="103093462784523190">"Αυτή η εφαρμογή σχεδιάστηκε για παλαιότερη έκδοση του Android. Εάν επιτρέψετε αυτήν την άδεια, τότε θα επιτρέπεται η πρόσβαση σε όλο τον αποθηκευτικό χώρο (συμπεριλαμβανομένων φωτογραφιών, βίντεο, μουσικής, ήχου και άλλων αρχείων)."</string>
- <string name="storage_supergroup_warning_deny" msgid="6420765672683284347">"Αυτή η εφαρμογή σχεδιάστηκε για παλαιότερη έκδοση του Android. Εάν δεν επιτρέψετε αυτήν την άδεια, τότε δεν θα επιτρέπεται η πρόσβαση σε όλο τον αποθηκευτικό χώρο (συμπεριλαμβανομένων φωτογραφιών, βίντεο, μουσικής, ήχου και άλλων αρχείων)."</string>
+ <string name="storage_supergroup_warning_allow" msgid="103093462784523190">"Αυτή η εφαρμογή σχεδιάστηκε για παλαιότερη έκδοση του Android. Εάν επιτρέψετε αυτή την άδεια, τότε θα επιτρέπεται η πρόσβαση σε όλο τον αποθηκευτικό χώρο (συμπεριλαμβανομένων φωτογραφιών, βίντεο, μουσικής, ήχου και άλλων αρχείων)."</string>
+ <string name="storage_supergroup_warning_deny" msgid="6420765672683284347">"Αυτή η εφαρμογή σχεδιάστηκε για παλαιότερη έκδοση του Android. Εάν δεν επιτρέψετε αυτή την άδεια, τότε δεν θα επιτρέπεται η πρόσβαση σε όλο τον αποθηκευτικό χώρο (συμπεριλαμβανομένων φωτογραφιών, βίντεο, μουσικής, ήχου και άλλων αρχείων)."</string>
<string name="default_permission_description" msgid="4624464917726285203">"εκτέλεση άγνωστης ενέργειας"</string>
<string name="app_permissions_group_summary" msgid="8788419008958284002">"Επιτρέπονται <xliff:g id="COUNT_0">%1$d</xliff:g> από <xliff:g id="COUNT_1">%2$d</xliff:g> εφαρμογές"</string>
<string name="app_permissions_group_summary2" msgid="4329922444840521150">"Επιτρέπονται <xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g> εφαρμογές"</string>
@@ -91,10 +93,10 @@
<string name="no_apps" msgid="2412612731628386816">"Δεν υπάρχουν εφαρμογές"</string>
<string name="location_settings" msgid="3624412509133422562">"Ρυθμίσεις τοποθεσίας"</string>
<string name="location_warning" msgid="2381649060929040962">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> είναι ο πάροχος των υπηρεσιών τοποθεσίας για τη συγκεκριμένη συσκευή. Μπορείτε να τροποποιήσετε την πρόσβαση τοποθεσίας από τις ρυθμίσεις τοποθεσίας."</string>
- <string name="system_warning" msgid="1173400963234358816">"Εάν αρνηθείτε να παραχωρήσετε αυτήν την άδεια, ορισμένες βασικές λειτουργίες της συσκευής σας μπορεί να μην εκτελούνται πλέον με τον αναμενόμενο τρόπο."</string>
+ <string name="system_warning" msgid="1173400963234358816">"Εάν αρνηθείτε να παραχωρήσετε αυτή την άδεια, ορισμένες βασικές λειτουργίες της συσκευής σας μπορεί να μην εκτελούνται πλέον με τον αναμενόμενο τρόπο."</string>
<string name="deny_read_media_visual_warning" msgid="3982586279917232827">"Αυτή η εφαρμογή σχεδιάστηκε για παλαιότερη έκδοση του Android. Εάν δεν επιτρέψετε την πρόσβαση αυτής της εφαρμογής στις φωτογραφίες και τα βίντεο, δεν θα επιτρέπεται επίσης η πρόσβαση στη μουσική και άλλους ήχους."</string>
<string name="deny_read_media_aural_warning" msgid="8928699919508646732">"Αυτή η εφαρμογή σχεδιάστηκε για παλαιότερη έκδοση του Android. Εάν δεν επιτρέψετε την πρόσβαση αυτής της εφαρμογής στη μουσική και άλλους ήχους, δεν θα επιτρέπεται επίσης η πρόσβαση στις φωτογραφίες και τα βίντεο."</string>
- <string name="cdm_profile_revoke_warning" msgid="4443893270719106700">"Εάν απορρίψετε αυτήν την άδεια, ορισμένες λειτουργίες της συσκευής σας τις οποίες διαχειρίζεται αυτή η εφαρμογή, ενδέχεται να μην λειτουργούν με τον αναμενόμενο τρόπο."</string>
+ <string name="cdm_profile_revoke_warning" msgid="4443893270719106700">"Εάν απορρίψετε αυτή την άδεια, ορισμένες λειτουργίες της συσκευής σας τις οποίες διαχειρίζεται αυτή η εφαρμογή, ενδέχεται να μην λειτουργούν με τον αναμενόμενο τρόπο."</string>
<string name="permission_summary_enforced_by_policy" msgid="4443598170942950519">"Επιβάλλεται βάσει πολιτικής"</string>
<string name="permission_summary_disabled_by_policy_background_only" msgid="221995005556362660">"Η πρόσβαση στο παρασκήνιο απενεργοποιήθηκε βάσει πολιτικής"</string>
<string name="permission_summary_enabled_by_policy_background_only" msgid="8287675974767104279">"Η πρόσβαση στο παρασκήνιο ενεργοποιήθηκε βάσει πολιτικής"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Όλες οι άδειες"</string>
<string name="other_permissions" msgid="2901186127193849594">"Άλλες δυνατότητες εφαρμογής"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Αίτημα άδειας"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Οι ενέργειες εγκατάστασης/απεγκατάστασης δεν υποστηρίζονται στο Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Επιλέξτε σε τι θα έχει πρόσβαση η εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Η εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ενημερώθηκε. Επιλέξτε σε τι θα έχει πρόσβαση αυτή η εφαρμογή."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Ακύρωση"</string>
@@ -196,16 +196,18 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"Χρήση ακριβούς τοποθεσίας"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Όταν είναι απενεργοποιημένη η ακριβής τοποθεσία, οι εφαρμογές μπορούν να έχουν πρόσβαση στην κατά προσέγγιση τοποθεσία σας"</string>
<string name="app_permission_title" msgid="2090897901051370711">"Άδεια - <xliff:g id="PERM">%1$s</xliff:g>"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"Πρόσβαση σε <xliff:g id="PERM">%1$s</xliff:g> για αυτήν την εφαρμογή"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"Πρόσβαση σε <xliff:g id="PERM">%1$s</xliff:g> για αυτή την εφαρμογή"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Εμφάνιση όλων των αδειών της εφαρμογής <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Εμφάνιση όλων των εφαρμογών με αυτήν την άδεια"</string>
+ <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Εμφάνιση όλων των εφαρμογών με αυτή την άδεια"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Εμφάνιση χρήσης μικροφώνου βοηθού"</string>
<string name="unused_apps_category_title" msgid="2988455616845243901">"Ρυθμίσεις μη χρησιμοποιούμενων εφαρμογών"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"Καταργήστε τις άδειες, εάν η εφαρμογή δεν χρησιμοποιείται."</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Κατάργηση αδειών και απελευθέρωση χώρου"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Παύση δραστηριότητας αδρανούς εφαρμογής"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Διαχείρ. εφαρμ. αν δεν χρησιμοποιείται"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Κατάργηση αδειών, διαγραφή προσωρινών αρχείων και διακοπή ειδοποιήσεων"</string>
- <string name="auto_revoke_summary" msgid="5867548789805911683">"Για την προστασία των δεδομένων σας, οι άδειες για αυτήν την εφαρμογή θα καταργηθούν εάν η εφαρμογή δεν χρησιμοποιηθεί για μερικούς μήνες."</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Κατάργηση αδειών, διαγραφή προσωρινών αρχείων, διακοπή ειδοποιήσεων και αρχειοθέτηση της εφαρμογής"</string>
+ <string name="auto_revoke_summary" msgid="5867548789805911683">"Για την προστασία των δεδομένων σας, οι άδειες για αυτή την εφαρμογή θα καταργηθούν εάν η εφαρμογή δεν χρησιμοποιηθεί για μερικούς μήνες."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Για την προστασία των δεδομένων σας, εάν δεν έχει χρησιμοποιηθεί η εφαρμογή για μερικούς μήνες, οι παρακάτω άδειες θα καταργηθούν: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Για την προστασία των δεδομένων σας, έχουν καταργηθεί οι άδειες εφαρμογών που δεν έχετε χρησιμοποιήσει κατά τους τελευταίους μήνες."</string>
<string name="auto_revoke_open_app_message" msgid="8075556291711205039">"Εάν θέλετε να επιτραπούν ξανά οι άδειες, ανοίξτε την εφαρμογή."</string>
@@ -225,22 +227,22 @@
<string name="last_opened_summary" msgid="5248984030024968808">"Τελευταίο άνοιγμα εφαρμογής <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Τελευταίο άνοιγμα <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Εάν επιτρέψετε τη διαχείριση όλων των αρχείων, αυτή η εφαρμογή θα μπορεί να αποκτήσει πρόσβαση, να τροποποιήσει και να διαγράψει τυχόν αρχεία στον κοινό αποθηκευτικό χώρο αυτής της συσκευής ή συνδεδεμένων συσκευών αποθηκευτικού χώρου. Η εφαρμογή θα μπορεί να αποκτήσει πρόσβαση σε αρχεία χωρίς να σας ρωτήσει."</string>
- <string name="special_file_access_dialog" msgid="583804114020740610">"Να επιτρέπεται σε αυτήν την εφαρμογή η πρόσβαση, τροποποίηση και διαγραφή αρχείων στη συσκευή ή τυχόν συνδεδεμένες συσκευές αποθηκευτικού χώρου; Η εφαρμογή θα μπορεί να αποκτήσει πρόσβαση σε αρχεία χωρίς να σας ρωτήσει."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Οι εφαρμογές με αυτήν την άδεια μπορούν να <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
- <string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Οι εφαρμογές με αυτήν την άδεια έχουν πρόσβαση σε φυσικές δραστηριότητες, όπως το περπάτημα, η ποδηλασία, η οδήγηση, ο αριθμός βημάτων και άλλα"</string>
- <string name="permission_description_summary_calendar" msgid="103329982944411010">"Οι εφαρμογές με αυτήν την άδεια μπορούν να αποκτήσουν πρόσβαση στο ημερολόγιό σας"</string>
- <string name="permission_description_summary_call_log" msgid="7321437186317577624">"Οι εφαρμογές με αυτήν την άδεια, έχουν δυνατότητα ανάγνωσης και εγγραφής στο αρχείο καταγραφής κλήσεων"</string>
- <string name="permission_description_summary_camera" msgid="108004375101882069">"Οι εφαρμογές με αυτήν την άδεια μπορούν να τραβούν φωτογραφίες και να εγγράφουν βίντεο"</string>
- <string name="permission_description_summary_contacts" msgid="2337798886460408996">"Οι εφαρμογές με αυτήν την άδεια μπορούν να αποκτήσουν πρόσβαση στις επαφές σας"</string>
- <string name="permission_description_summary_location" msgid="2817531799933480694">"Οι εφαρμογές με αυτήν την άδεια μπορούν να αποκτήσουν πρόσβαση στην τοποθεσία αυτής της συσκευής"</string>
- <string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"Οι εφαρμογές με αυτήν την άδεια μπορούν να βρίσκουν, να συνδέονται και να προσδιορίζουν τη σχετική τοποθεσία κοντινών συσκευών"</string>
- <string name="permission_description_summary_microphone" msgid="630834800308329907">"Οι εφαρμογές με αυτήν την άδεια μπορούν να εγγράφουν ήχο"</string>
- <string name="permission_description_summary_phone" msgid="4515277217435233619">"Οι εφαρμογές με αυτήν την άδεια έχουν δυνατότητα πραγματοποίησης και διαχείρισης τηλεφωνικών κλήσεων"</string>
- <string name="permission_description_summary_sensors" msgid="1836045815643119949">"Οι εφαρμογές με αυτήν την άδεια μπορούν να αποκτήσουν πρόσβαση στα δεδομένα αισθητήρα σχετικά με τις ζωτικές ενδείξεις σας"</string>
- <string name="permission_description_summary_sms" msgid="725999468547768517">"Οι εφαρμογές με αυτήν την άδεια μπορούν να στέλνουν και να προβάλλουν μηνύματα SMS"</string>
- <string name="permission_description_summary_storage" msgid="6575759089065303346">"Οι εφαρμογές με αυτήν την άδεια έχουν πρόσβαση σε φωτογραφίες, μέσα και αρχεία στη συσκευή σας"</string>
- <string name="permission_description_summary_read_media_aural" msgid="3354728149930482199">"Οι εφαρμογές με αυτήν την άδεια μπορούν να αποκτήσουν πρόσβαση στη μουσική και σε άλλα αρχεία ήχου αυτής της συσκευής"</string>
- <string name="permission_description_summary_read_media_visual" msgid="4991801977881732641">"Οι εφαρμογές με αυτήν την άδεια μπορούν να αποκτήσουν πρόσβαση στις φωτογραφίες και τα βίντεο αυτής της συσκευής"</string>
+ <string name="special_file_access_dialog" msgid="583804114020740610">"Να επιτρέπεται σε αυτή την εφαρμογή η πρόσβαση, τροποποίηση και διαγραφή αρχείων στη συσκευή ή τυχόν συνδεδεμένες συσκευές αποθηκευτικού χώρου; Η εφαρμογή θα μπορεί να αποκτήσει πρόσβαση σε αρχεία χωρίς να σας ρωτήσει."</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Οι εφαρμογές με αυτή την άδεια μπορούν να <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Οι εφαρμογές με αυτή την άδεια έχουν πρόσβαση σε φυσικές δραστηριότητες, όπως το περπάτημα, η ποδηλασία, η οδήγηση, ο αριθμός βημάτων και άλλα"</string>
+ <string name="permission_description_summary_calendar" msgid="103329982944411010">"Οι εφαρμογές με αυτή την άδεια μπορούν να αποκτήσουν πρόσβαση στο ημερολόγιό σας"</string>
+ <string name="permission_description_summary_call_log" msgid="7321437186317577624">"Οι εφαρμογές με αυτή την άδεια, έχουν δυνατότητα ανάγνωσης και εγγραφής στο αρχείο καταγραφής κλήσεων"</string>
+ <string name="permission_description_summary_camera" msgid="108004375101882069">"Οι εφαρμογές με αυτή την άδεια μπορούν να τραβούν φωτογραφίες και να εγγράφουν βίντεο"</string>
+ <string name="permission_description_summary_contacts" msgid="2337798886460408996">"Οι εφαρμογές με αυτή την άδεια μπορούν να αποκτήσουν πρόσβαση στις επαφές σας"</string>
+ <string name="permission_description_summary_location" msgid="2817531799933480694">"Οι εφαρμογές με αυτή την άδεια μπορούν να αποκτήσουν πρόσβαση στην τοποθεσία αυτής της συσκευής"</string>
+ <string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"Οι εφαρμογές με αυτή την άδεια μπορούν να βρίσκουν, να συνδέονται και να προσδιορίζουν τη σχετική τοποθεσία κοντινών συσκευών"</string>
+ <string name="permission_description_summary_microphone" msgid="630834800308329907">"Οι εφαρμογές με αυτή την άδεια μπορούν να εγγράφουν ήχο"</string>
+ <string name="permission_description_summary_phone" msgid="4515277217435233619">"Οι εφαρμογές με αυτή την άδεια έχουν δυνατότητα πραγματοποίησης και διαχείρισης τηλεφωνικών κλήσεων"</string>
+ <string name="permission_description_summary_sensors" msgid="1836045815643119949">"Οι εφαρμογές με αυτή την άδεια μπορούν να αποκτήσουν πρόσβαση στα δεδομένα αισθητήρα σχετικά με τις ζωτικές ενδείξεις σας"</string>
+ <string name="permission_description_summary_sms" msgid="725999468547768517">"Οι εφαρμογές με αυτή την άδεια μπορούν να στέλνουν και να προβάλλουν μηνύματα SMS"</string>
+ <string name="permission_description_summary_storage" msgid="6575759089065303346">"Οι εφαρμογές με αυτή την άδεια έχουν πρόσβαση σε φωτογραφίες, μέσα και αρχεία στη συσκευή σας"</string>
+ <string name="permission_description_summary_read_media_aural" msgid="3354728149930482199">"Οι εφαρμογές με αυτή την άδεια μπορούν να αποκτήσουν πρόσβαση στη μουσική και σε άλλα αρχεία ήχου αυτής της συσκευής"</string>
+ <string name="permission_description_summary_read_media_visual" msgid="4991801977881732641">"Οι εφαρμογές με αυτή την άδεια μπορούν να αποκτήσουν πρόσβαση στις φωτογραφίες και τα βίντεο αυτής της συσκευής"</string>
<string name="app_permission_most_recent_summary" msgid="4292074449384040590">"Τελευταία πρόσβαση: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"Απορρίφθηκε αυτήν τη φορά/Τελευταία πρόσβαση: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"Δεν έγινε ποτέ πρόσβαση"</string>
@@ -284,7 +286,7 @@
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Αυτή η εφαρμογή μπορεί να έχει πάντα πρόσβαση στην τοποθεσία σας. Πατήστε για να αλλάξετε τη ρύθμιση."</string>
<string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Έλεγχος εφαρμογής που έχει πρόσβαση στις ειδοποιήσεις σας"</string>
<string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"Η εφαρμογή <xliff:g id="APP_NAME">%s</xliff:g> μπορεί να παραβλέψει ειδοποιήσεις, να εκτελέσει ενέργειες σε αυτές και να αποκτήσει πρόσβαση σε περιεχόμενο στο εσωτερικό τους"</string>
- <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Αυτή η εφαρμογή μπορεί να παραβλέψει ειδοποιήσεις, να εκτελέσει ενέργειες σε αυτές και να αποκτήσει πρόσβαση σε περιεχόμενο στο εσωτερικό τους. Ορισμένες εφαρμογές χρειάζονται αυτήν την πρόσβαση για να λειτουργούν όπως προβλέπεται."</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Αυτή η εφαρμογή μπορεί να παραβλέψει ειδοποιήσεις, να εκτελέσει ενέργειες σε αυτές και να αποκτήσει πρόσβαση σε περιεχόμενο στο εσωτερικό τους. Ορισμένες εφαρμογές χρειάζονται αυτή την πρόσβαση για να λειτουργούν όπως προβλέπεται."</string>
<string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Κατάργηση πρόσβασης"</string>
<string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Εμφάνιση περισσότερων επιλογών"</string>
<string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Η πρόσβαση καταργήθηκε"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Εφαρμογή σημειώσεων"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Εφαρμογές που σας επιτρέπουν να κρατάτε σημειώσεις στη συσκευή σας"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"σημειώσεις"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Τρέχουσα προεπιλογή"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Να μην ερωτηθώ ξανά"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Προεπιλογή"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Εμφάνιση εντοπισμού ενεργοποίησης βοηθού"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Εμφάνιση εικονιδίου στη γραμμή κατάστασης όταν το μικρόφωνο χρησιμοποιείται για την ενεργοποίηση του φωνητικού βοηθού"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να έχει πρόσβαση σε φωτογραφίες και μέσα στη συσκευή σας;"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε φωτογραφίες και μέσα στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στις επαφές σας στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"Επιτρέπεται στην εφαρμογή &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Επιτρέπεται στην εφαρμογή &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>;"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Αυτή η εφαρμογή θέλει να έχει συνεχώς πρόσβαση στην τοποθεσία σας, ακόμη και όταν δεν χρησιμοποιείτε την εφαρμογή. "<annotation id="link">"Εγκρίνετε το αίτημα στις ρυθμίσεις."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Αλλαγή πρόσβασης στην τοποθεσία για την εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;;"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Αλλαγή της πρόσβασης σε τοποθεσία για την εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Αυτή η εφαρμογή θέλει να έχει συνεχώς πρόσβαση στην τοποθεσία σας, ακόμη και όταν δεν χρησιμοποιείτε την εφαρμογή. "<annotation id="link">"Εγκρίνετε το αίτημα στις ρυθμίσεις."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Να επιτρέπεται η εύρεση, η σύνδεση κι ο προσδιορισμός σχετικής τοποθεσίας των κοντινών συσκευών από &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;;"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; εύρεση, σύνδεση και προσδιορ. σχετ. θέσης κοντινών συσκευών στο &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Να επιτρέπεται η εύρεση, η σύνδεση κι ο προσδιορισμός σχετικής τοποθεσίας των κοντινών συσκευών από &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;; "<annotation id="link">"Έγκριση στις Ρυθμίσεις."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Αλλαγή της πρόσβασης της εφαρμογής <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> στην τοποθεσία από κατά προσέγγιση σε ακριβή;"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Αλλαγή της πρόσβασης της εφαρμογής <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> στην τοποθεσία της συσκευής &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"Επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στην τοποθεσία κατά προσέγγιση της συσκευής &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στο ημερολόγιό σας στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η αποστολή και η προβολή μηνυμάτων SMS στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"Επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε φωτογραφίες, μέσα και αρχεία στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε &lt;b&gt;φωτογραφίες, βίντεο, μουσική και ήχο&lt;/b&gt; της συσκευής;"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε &lt;b&gt;φωτογραφίες, βίντεο, μουσική, ήχο και άλλα αρχεία&lt;/b&gt; της συσκευής;"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στη μουσική και στα αρχεία ήχου αυτής της συσκευής;"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε μουσική και ήχο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στις φωτογραφίες και τα βίντεο αυτής της συσκευής;"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε φωτογραφίες και βίντεο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε περισσότερες φωτογραφίες και βίντεο αυτής της συσκευής;"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε περισσότερες φωτογραφίες και βίντεο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου;"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Αυτή η εφαρμογή θα μπορεί να εγγράφει ήχο μόνο όταν τη χρησιμοποιείτε"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου;"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Αυτή η εφαρμογή ενδέχεται να εγγράφει βίντεο συνεχώς, ακόμη και όταν δεν τη χρησιμοποιείτε. "<annotation id="link">"Έγκριση στις ρυθμίσεις."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Αλλαγή πρόσβασης στο μικρόφωνο για την εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;;"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Αλλαγή της πρόσβασης μικροφώνου για την εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Αυτή η εφαρμογή θέλει να εγγράφει ήχο συνεχώς, ακόμη και όταν δεν τη χρησιμοποιείται. "<annotation id="link">"Έγκριση στις ρυθμίσεις."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να έχει πρόσβαση στη σωματική σας δραστηριότητα;"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στη σωματική δραστηριότητά σας στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η λήψη φωτογραφιών και η εγγραφή βίντεο;"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η λήψη φωτογραφιών και η εγγραφή βίντεο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Αυτή η εφαρμογή θα μπορεί να τραβάει φωτογραφίες και να εγγράφει βίντεο μόνο όταν τη χρησιμοποιείτε"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η λήψη φωτογραφιών και η εγγραφή βίντεο;"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η λήψη φωτογραφιών και η εγγραφή βίντεο στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Αυτή η εφαρμογή ενδέχεται να τραβάει φωτογραφίες και να εγγράφει βίντεο συνεχώς, ακόμη και όταν δεν τη χρησιμοποιείτε. "<annotation id="link">"Έγκριση στις Ρυθμίσεις."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Αλλαγή πρόσβασης στην κάμερα για την εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;;"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Αλλαγή της πρόσβασης κάμερας για την εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Αυτή η εφαρμογή θέλει να τραβάει φωτογραφίες και να εγγράφει βίντεο συνεχώς, ακόμη και όταν δεν τη χρησιμοποιείται. "<annotation id="link">"Έγκριση στις Ρυθμίσεις."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να έχει πρόσβαση στα αρχεία καταγραφής τηλεφωνικών κλήσεών σας;"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στα αρχεία καταγραφής τηλεφ. κλήσεων στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πραγματοποίηση και η διαχείριση τηλεφωνικών κλήσεων;"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πραγματοποίηση και η διαχείριση τηλεφ. κλήσεων στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να έχει πρόσβαση στα δεδομένα αισθητήρα σχετικά με τις ζωτικές ενδείξεις σας;"</string>
- <string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Αυτή η εφαρμογή θέλει πρόσβαση στα δεδομένα αισθητήρα για τις ζωτικές σας ενδείξεις, ακόμη και όταν δεν τη χρησιμοποιείτε. Για να κάνετε αυτήν την αλλαγή, "<annotation id="link">"μεταβείτε στις ρυθμίσεις."</annotation></string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στα δεδομένα αισθητήρων ζωτικών λειτουργιών σας στο &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
+ <string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Αυτή η εφαρμογή θέλει πρόσβαση στα δεδομένα αισθητήρα για τις ζωτικές σας ενδείξεις, ακόμη και όταν δεν τη χρησιμοποιείτε. Για να κάνετε αυτή την αλλαγή, "<annotation id="link">"μεταβείτε στις ρυθμίσεις."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε δεδομένα αισθητήρα σχετικά με τις ζωτικές ενδείξεις σας;"</string>
- <string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Για να επιτρέψετε σε αυτήν την εφαρμογή να έχει πρόσβαση σε δεδομένα αισθητήρων σώματος οποιαδήποτε στιγμή, ακόμα και όταν δεν χρησιμοποιείτε την εφαρμογή, "<annotation id="link">"μεταβείτε στις ρυθμίσεις."</annotation></string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση στα δεδομένα αισθητήρων ζωτικών λειτουργιών σας στο &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
+ <string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Για να επιτρέψετε σε αυτή την εφαρμογή να έχει πρόσβαση σε δεδομένα αισθητήρων σώματος οποιαδήποτε στιγμή, ακόμα και όταν δεν χρησιμοποιείτε την εφαρμογή, "<annotation id="link">"μεταβείτε στις ρυθμίσεις."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Να συνεχίσει να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβαση σε δεδομένα αισθητήρων σώματος ενώ χρησιμοποιείται;"</string>
- <string name="permgrouprequest_notifications" msgid="6396739062335106181">"Επιτρέπετε στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να σας στέλνει ειδοποιήσεις;"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Να συνεχ. να επιτρ. σε &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η πρόσβ. σε δεδομ. αισθ. σώμ. σε &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; κατά τη χρήση της εφαρ.;"</string>
+ <string name="permgrouprequest_notifications" msgid="6396739062335106181">"Να επιτρέπεται στο &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να σας στέλνει ειδοποιήσεις;"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η αποστολή ειδοποιήσεων στη συσκευή &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;;"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Ελεγχόμενες άδειες"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> έχει πρόσβαση στην τοποθεσία"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Ο οργανισμός σας επιτρέπει στην εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> να έχει πρόσβαση στην τοποθεσία σας"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Άλλες άδειες"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Άδεια που χρησιμοποιείται από το σύστημα"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Άδειες που χρησιμοποιούνται από εφαρμογές του συστήματος."</string>
@@ -542,8 +579,8 @@
<string name="permissions_removed_qs" msgid="8957319130625294572">"Η άδεια καταργήθηκε"</string>
<string name="camera_usage_qs" msgid="4394233566086665994">"Προβολή πρόσφατης χρήσης κάμερας"</string>
<string name="microphone_usage_qs" msgid="8527666682168170417">"Προβολή πρόσφατης χρήσης μικροφώνου"</string>
- <string name="remove_camera_qs" msgid="3649996161066883350">"Κατάργηση άδειας για αυτήν την εφαρμογή"</string>
- <string name="remove_microphone_qs" msgid="1276551965129953198">"Κατάργηση άδειας για αυτήν την εφαρμογή"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Κατάργηση άδειας για αυτή την εφαρμογή"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Κατάργηση άδειας για αυτή την εφαρμογή"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Διαχείριση υπηρεσίας"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Διαχείριση αδειών"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Χρησιμοποιείται από την τηλεφωνική κλήση"</string>
@@ -583,7 +620,7 @@
<string name="mic_toggle_title" msgid="2649991093496110162">"Πρόσβαση μικροφώνου"</string>
<string name="perm_toggle_description" msgid="7801326363741451379">"Για εφαρμογές και υπηρεσίες"</string>
<string name="mic_toggle_description" msgid="9163104307990677157">"Για εφαρμογές και υπηρεσίες. Εάν είναι απενεργοποιημένη αυτή η ρύθμιση, τα δεδομένα μικροφώνου ενδέχεται να κοινοποιούνται όταν καλείτε έναν αριθμό έκτακτης ανάγκης."</string>
- <string name="location_settings_subtitle" msgid="2328360561197430695">"Εμφάνιση εφαρμογών και υπηρεσιών που έχουν πρόσβαση σε αυτήν την τοποθεσία"</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Εμφάνιση εφαρμογών και υπηρεσιών που έχουν πρόσβαση σε αυτή την τοποθεσία"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Εμφάνιση πρόσβασης στο πρόχειρο"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Να εμφανίζεται ένα μήνυμα όταν οι εφαρμογές αποκτούν πρόσβαση σε κείμενο, εικόνες ή άλλο περιεχόμενο που έχετε αντιγράψει"</string>
<string name="show_password_title" msgid="2877269286984684659">"Εμφάνιση κωδικών πρόσβασης"</string>
@@ -591,8 +628,9 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Αυτή η εφαρμογή έχει δηλώσει ότι ενδέχεται να κοινοποιήσει δεδομένα τοποθεσίας σε τρίτα μέρη."</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Κοινοποίηση δεδομένων και τοποθεσία"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Προέλευση πληροφοριών κοινοποίησης δεδομένων"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Ο προγραμματιστής παρείχε πληροφορίες στον κατασκευαστή της συσκευής για το πώς η εφαρμογή μοιράζεται δεδομένα. Ο προγραμματιστής μπορεί να ενημερώσει αυτές τις πληροφορίες με την πάροδο του χρόνου."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Ο προγραμματιστής έχει καταχωρίσει πληροφορίες στο "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" σχετικά με το πώς αυτή η εφαρμογή κοινοποιεί δεδομένα. Ο προγραμματιστής μπορεί να ενημερώσει αυτές τις πληροφορίες με την πάροδο του χρόνου."</string>
- <string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Η εφαρμ. μπορεί να κοινοποιεί δεδομ. τοποθεσ. για:"</string>
+ <string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Η εφαρμογή μπορεί να κοινοποιεί δεδομένα τοποθεσίας για:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Η κοινοποίηση δεδομένων διαφέρει"</string>
<string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Οι πρακτικές απορρήτου μπορεί να διαφέρουν ανάλογα με την έκδοση και τη χρήση της εφαρμογής, καθώς και με την περιοχή και την ηλικία σας. "<annotation id="link">"Περισσότερα σχετικά με την κοινοποίηση δεδομένων"</annotation></string>
<string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Οι πρακτικές διαχείρισης δεδομένων μπορεί να διαφέρουν ανάλογα με την έκδοση και τη χρήση της εφαρμογής, καθώς και με την περιοχή και την ηλικία σας."</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Ασφάλεια δεδομένων"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Τα δεδομένα τοποθεσίας ενδέχεται να κοινοποιούνται"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Αυτή η εφαρμογή έχει δηλώσει ότι ενδέχεται να κοινοποιήσει τα δεδομένα τοποθεσίας σας σε τρίτα μέρη"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Δεν είναι δυνατό το άνοιγμα αυτού του συνδέσμου"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Ενημερώσεις στην κοινοποίηση δεδ. για τοποθεσία"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Ελέγξτε εφαρμογές που άλλαξαν τον τρόπο με τον οποίο ενδέχεται να κοινοποιούν τα δεδομένα τοποθεσίας"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Αυτές οι εφαρμογές έχουν αλλάξει τον τρόπο με τον οποίο μπορούν να κοινοποιούν τα δεδομένα τοποθεσία σας. Ενδέχεται να μην τα έχουν κοινοποιήσει στο παρελθόν ή να τα κοινοποιούν τώρα για σκοπούς διαφήμισης ή μάρκετινγκ."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Ενημερώσεις κοινοποίησης δεδομένων"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Ορισμένες εφαρμογές άλλαξαν τον τρόπο με τον οποίο ενδέχεται να κοινοποιούν τα δεδομένα τοποθεσίας σας"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Ρυθμίσεις"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Πρόσβαση στις <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Πρόσβαση χθες, στις <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Πρόσβαση στις <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-en-rAU/strings.xml b/PermissionController/res/values-en-rAU/strings.xml
index 513db22f7..6eb869786 100644
--- a/PermissionController/res/values-en-rAU/strings.xml
+++ b/PermissionController/res/values-en-rAU/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"More info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Allow all"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Always allow all"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Allow limited access"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Select photos and videos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Select more"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Don\'t select more"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"App permissions"</string>
<string name="unused_apps" msgid="2058057455175955094">"Unused apps"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edit selected photos for this app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"No unused apps"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Zero unused apps"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Recent permission decisions"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"All permissions"</string>
<string name="other_permissions" msgid="2901186127193849594">"Other app capabilities"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Permission request"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Install/Uninstall actions not supported on Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Choose what to allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; has been updated. Choose what access to allow this app."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancel"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Remove permissions if app isn’t used"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Remove permissions and free up space"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pause app activity if unused"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Manage app if unused"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Remove permissions, delete temporary files and stop notifications"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Remove permissions, delete temporary files, stop notifications and archive the app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"To protect your data, permissions for this app will be removed if the app is unused for a few months."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"To protect your data, if the app is unused for a few months, the following permissions will be removed: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"To protect your data, permissions have been removed from apps that you haven’t used in a few months."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Notes app"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps that allow you to take notes on your device"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notes"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Current default"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Don\'t ask again"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Set as default"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Show assistant trigger detection"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Show icon in status bar when microphone is used to activate voice assistant"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and media on your device?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and media on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your contacts?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your contacts on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s location?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt; location?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"The app will only have access to the location while you\'re using the app"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s location?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"This app may want to access your location all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Change location access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Change location access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"This app wants to access your location all the time, even when you’re not using the app. "<annotation id="link">"Allow in Settings."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices? "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Change <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>’s location access from approximate to precise?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Change <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>’s location access on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; from approximate to precise?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s approximate location?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;’s approximate location?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precise"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Approximate"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your calendar?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your calendar on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send and view SMS messages?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send and view SMS messages on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos, media and files on your device?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos, media and files on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access &lt;b&gt;photos, videos, music and audio&lt;/b&gt; on this device?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access &lt;b&gt;photos, videos, music, audio and other files&lt;/b&gt; on this device?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access music and audio on this device?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access music and audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on this device?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on this device?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access more photos and videos on this device?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access more photos and videos on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"The app will only be able to record audio while you’re using the app"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"This app may want to record audio all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Change microphone access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Change microphone access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"This app wants to record audio all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your physical activity?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your physical activity on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"The app will only be able to take pictures and record video while you’re using the app"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"This app may want to take pictures and record video all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Change camera access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Change camera access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"This app wants to take pictures and record video all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your phone call logs?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your phone call logs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to make and manage phone calls?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to make and manage phone calls on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access sensor data about your vital signs?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access sensor data about your vital signs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"This app wants to access sensor data about your vital signs all the time, even when you’re not using the app. To make this change, "<annotation id="link">"go to Settings."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access the sensor data about your vital signs?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access the sensor data about your vital signs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"To let this app access body sensor data all the time, even when you’re not using the app, "<annotation id="link">"go to settings."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Keep allowing &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access body sensor data while the app is in use?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Keep allowing &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access body sensor data on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; while app is in use?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send you notifications?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send you notifications on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Controlled permissions"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> has location access"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Your organisation allows <xliff:g id="APP_NAME">%1$s</xliff:g> to access your location"</string>
@@ -520,7 +559,7 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"For apps and services"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Microphone data may still be shared when you call an emergency number."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Change"</string>
- <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Security &amp; privacy"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Security and privacy"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"Scan device"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Dismiss"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Dismiss this alert?"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"This app stated that it may share location data with third parties"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Data sharing and location"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Where data sharing info comes from"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"The developer provided info to this device\'s manufacturer about how this app shares data. The developer may update this info over time."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"The developer provided info to "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" about how this app shares data. The developer may update this info over time."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"This app may share location data for:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Data sharing varies"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Data safety"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Location data may be shared"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"This app stated that it may share your location data with third parties"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Can’t open this link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Data sharing updates for location"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Review apps that changed the way that they may share your location data"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"These apps have changed the way that they may share your location data. They may not have shared it before or may now share it for advertising or marketing purposes."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Data sharing updates"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Some apps changed the way that they may share your location data"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Settings"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Accessed <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Accessed yesterday <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Accessed <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-en-rCA/strings.xml b/PermissionController/res/values-en-rCA/strings.xml
index e3a42643f..b85bbaacb 100644
--- a/PermissionController/res/values-en-rCA/strings.xml
+++ b/PermissionController/res/values-en-rCA/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"More info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Allow all"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Always allow all"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Allow limited access"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Select photos and videos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Select more"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Don’t select more"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"App permissions"</string>
<string name="unused_apps" msgid="2058057455175955094">"Unused apps"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edit selected photos for this app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"No unused apps"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 unused apps"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Recent permission decisions"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"All permissions"</string>
<string name="other_permissions" msgid="2901186127193849594">"Other app capabilities"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Permission request"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Install/Uninstall actions not supported on Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Choose what to allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; has been updated. Choose what to allow this app to access."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancel"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Remove permissions if app isn’t used"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Remove permissions and free up space"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pause app activity if unused"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Manage app if unused"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Remove permissions, delete temporary files, and stop notifications"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Remove permissions, delete temporary files, stop notifications, and archive the app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"To protect your data, permissions for this app will be removed if the app is unused for a few months."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"To protect your data, if the app is unused for a few months, the following permissions will be removed: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"To protect your data, permissions have been removed from apps that you haven’t used in a few months."</string>
@@ -401,6 +403,11 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Notes app"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps that allow you to take notes on your device"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notes"</string>
+ <string name="role_wallet_label" msgid="3719419175656204207">"Default wallet app"</string>
+ <string name="role_wallet_short_label" msgid="6521288403762457452">"Wallet app"</string>
+ <string name="role_wallet_description" msgid="3726535836165949838">"Wallet apps can store your credit and loyalty cards, car keys and other things to help with various forms of transactions."</string>
+ <string name="role_wallet_request_title" msgid="4770217108262737093">"Set <xliff:g id="APP_NAME">%1$s</xliff:g> as your default wallet app?"</string>
+ <string name="role_wallet_request_description" msgid="6305487425777483053">"No permissions needed"</string>
<string name="request_role_current_default" msgid="738722892438247184">"Current default"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Don’t ask again"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Set as default"</string>
@@ -419,7 +426,7 @@
<string name="ongoing_usage_dialog_separator" msgid="1715181526581520068">", "</string>
<string name="ongoing_usage_dialog_last_separator" msgid="4170995004748832163">" and "</string>
<string name="default_app_search_keyword" msgid="8330125736889689743">"default apps"</string>
- <string name="permgroup_list_microphone_and_camera" msgid="962768198001487969">"Microphone &amp; Camera"</string>
+ <string name="permgroup_list_microphone_and_camera" msgid="962768198001487969">"Microphone and camera"</string>
<string name="settings_button" msgid="4414988414732479636">"Settings"</string>
<string name="default_apps" msgid="5119201969348748639">"Default apps"</string>
<string name="no_default_apps" msgid="2593466527182950231">"No default apps"</string>
@@ -455,48 +462,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Show assistant trigger detection"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Show icon in status bar when microphone is used to activate voice assistant"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and media on your device?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and media on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your contacts?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your contacts on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s location?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt; location?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"The app will only have access to the location while you\'re using the app"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s location?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"This app may want to access your location all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Change location access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Change location access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"This app wants to access your location all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to, and determine the relative position of nearby devices?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to, and determine the relative position of nearby devices on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to, and determine the relative position of nearby devices? "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Change <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>’s location access from approximate to precise?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Change <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>’s location access on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; from approximate to precise?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s approximate location?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;’s approximate location?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precise"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Approximate"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your calendar?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your calendar on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send and view SMS messages?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send and view SMS messages on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos, media, and files on your device?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos, media, and files on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access &lt;b&gt;photos, videos, music, and audio&lt;/b&gt; on this device?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access &lt;b&gt;photos, videos, music, audio, and other files&lt;/b&gt; on this device?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access music and audio on this device?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access music and audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on this device?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access more photos and videos on this device?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access more photos and videos on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"The app will only be able to record audio while you’re using the app"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"This app may want to record audio all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Change microphone access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Change microphone access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"This app wants to record audio all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your physical activity?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your physical activity on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"The app will only be able to take pictures and record video while you’re using the app"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"This app may want to take pictures and record video all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Change camera access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Change camera access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"This app wants to take pictures and record video all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your phone call logs?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your phone call logs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to make and manage phone calls?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to make and manage phone calls on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access sensor data about your vital signs?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access sensor data about your vital signs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"This app wants to access sensor data about your vital signs all the time, even when you’re not using the app. To make this change, "<annotation id="link">"go to settings."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access the sensor data about your vital signs?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access the sensor data about your vital signs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"To let this app access body sensor data all the time, even when you’re not using the app, "<annotation id="link">"go to settings."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Keep allowing &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access body sensor data while app is in use?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Keep allowing &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access body sensor data on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; while app is in use?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send you notifications?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send you notifications on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Controlled permissions"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> has location access"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Your organization allows <xliff:g id="APP_NAME">%1$s</xliff:g> to access your location"</string>
@@ -589,6 +623,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"This app stated it may share location data with third parties"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Data sharing and location"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Where data sharing info comes from"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"The developer provided info to this device\'s manufacturer about how this app shares data. The developer may update this info over time."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"The developer provided info to "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" about how this app shares data. The developer may update this info over time."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"This app may share location data for:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Data sharing varies"</string>
@@ -606,8 +641,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Data safety"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Location data may be shared"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"This app stated it may share your location data with third parties"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Can’t open this link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Data sharing updates for location"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Review apps that changed the way they may share your location data"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"These apps have changed the way they may share your location data. They may not have shared it before, or may now share it for advertising or marketing purposes."</string>
@@ -620,4 +653,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Data sharing updates"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Some apps changed the way they may share your location data"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Settings"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Accessed <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Accessed yesterday <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Accessed <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-en-rGB/strings.xml b/PermissionController/res/values-en-rGB/strings.xml
index bb0c0f203..8882cd83d 100644
--- a/PermissionController/res/values-en-rGB/strings.xml
+++ b/PermissionController/res/values-en-rGB/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"More info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Allow all"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Always allow all"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Allow limited access"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Select photos and videos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Select more"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Don\'t select more"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"App permissions"</string>
<string name="unused_apps" msgid="2058057455175955094">"Unused apps"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edit selected photos for this app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"No unused apps"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Zero unused apps"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Recent permission decisions"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"All permissions"</string>
<string name="other_permissions" msgid="2901186127193849594">"Other app capabilities"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Permission request"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Install/Uninstall actions not supported on Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Choose what to allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; has been updated. Choose what access to allow this app."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancel"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Remove permissions if app isn’t used"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Remove permissions and free up space"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pause app activity if unused"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Manage app if unused"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Remove permissions, delete temporary files and stop notifications"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Remove permissions, delete temporary files, stop notifications and archive the app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"To protect your data, permissions for this app will be removed if the app is unused for a few months."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"To protect your data, if the app is unused for a few months, the following permissions will be removed: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"To protect your data, permissions have been removed from apps that you haven’t used in a few months."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Notes app"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps that allow you to take notes on your device"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notes"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Current default"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Don\'t ask again"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Set as default"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Show assistant trigger detection"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Show icon in status bar when microphone is used to activate voice assistant"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and media on your device?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and media on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your contacts?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your contacts on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s location?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt; location?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"The app will only have access to the location while you’re using the app"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s location?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"This app may want to access your location all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Change location access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Change location access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"This app wants to access your location all the time, even when you’re not using the app. "<annotation id="link">"Allow in Settings."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices? "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Change <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>’s location access from approximate to precise?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Change <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>’s location access on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; from approximate to precise?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s approximate location?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;’s approximate location?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precise"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Approximate"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your calendar?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your calendar on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send and view SMS messages?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send and view SMS messages on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos, media and files on your device?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos, media and files on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access &lt;b&gt;photos, videos, music and audio&lt;/b&gt; on this device?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access &lt;b&gt;photos, videos, music, audio and other files&lt;/b&gt; on this device?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access music and audio on this device?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access music and audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on this device?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on this device?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access more photos and videos on this device?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access more photos and videos on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"The app will only be able to record audio while you’re using the app"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"This app may want to record audio all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Change microphone access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Change microphone access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"This app wants to record audio all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your physical activity?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your physical activity on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"The app will only be able to take pictures and record video while you’re using the app"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"This app may want to take pictures and record video all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Change camera access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Change camera access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"This app wants to take pictures and record video all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your phone call logs?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your phone call logs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to make and manage phone calls?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to make and manage phone calls on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access sensor data about your vital signs?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access sensor data about your vital signs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"This app wants to access sensor data about your vital signs all the time, even when you’re not using the app. To make this change, "<annotation id="link">"go to Settings."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access the sensor data about your vital signs?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access the sensor data about your vital signs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"To let this app access body sensor data all the time, even when you’re not using the app, "<annotation id="link">"go to settings."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Keep allowing &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access body sensor data while the app is in use?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Keep allowing &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access body sensor data on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; while app is in use?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send you notifications?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send you notifications on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Controlled permissions"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> has location access"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Your organisation allows <xliff:g id="APP_NAME">%1$s</xliff:g> to access your location"</string>
@@ -520,7 +559,7 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"For apps and services"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Microphone data may still be shared when you call an emergency number."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Change"</string>
- <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Security &amp; privacy"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Security and privacy"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"Scan device"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Dismiss"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Dismiss this alert?"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"This app stated that it may share location data with third parties"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Data sharing and location"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Where data sharing info comes from"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"The developer provided info to this device\'s manufacturer about how this app shares data. The developer may update this info over time."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"The developer provided info to "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" about how this app shares data. The developer may update this info over time."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"This app may share location data for:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Data sharing varies"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Data safety"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Location data may be shared"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"This app stated that it may share your location data with third parties"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Can’t open this link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Data sharing updates for location"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Review apps that changed the way that they may share your location data"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"These apps have changed the way that they may share your location data. They may not have shared it before or may now share it for advertising or marketing purposes."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Data sharing updates"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Some apps changed the way that they may share your location data"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Settings"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Accessed <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Accessed yesterday <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Accessed <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-en-rIN/strings.xml b/PermissionController/res/values-en-rIN/strings.xml
index bb0c0f203..8882cd83d 100644
--- a/PermissionController/res/values-en-rIN/strings.xml
+++ b/PermissionController/res/values-en-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"More info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Allow all"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Always allow all"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Allow limited access"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Select photos and videos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Select more"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Don\'t select more"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"App permissions"</string>
<string name="unused_apps" msgid="2058057455175955094">"Unused apps"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edit selected photos for this app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"No unused apps"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Zero unused apps"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Recent permission decisions"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"All permissions"</string>
<string name="other_permissions" msgid="2901186127193849594">"Other app capabilities"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Permission request"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Install/Uninstall actions not supported on Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Choose what to allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; has been updated. Choose what access to allow this app."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancel"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Remove permissions if app isn’t used"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Remove permissions and free up space"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pause app activity if unused"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Manage app if unused"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Remove permissions, delete temporary files and stop notifications"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Remove permissions, delete temporary files, stop notifications and archive the app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"To protect your data, permissions for this app will be removed if the app is unused for a few months."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"To protect your data, if the app is unused for a few months, the following permissions will be removed: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"To protect your data, permissions have been removed from apps that you haven’t used in a few months."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Notes app"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps that allow you to take notes on your device"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notes"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Current default"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Don\'t ask again"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Set as default"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Show assistant trigger detection"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Show icon in status bar when microphone is used to activate voice assistant"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and media on your device?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and media on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your contacts?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your contacts on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s location?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt; location?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"The app will only have access to the location while you’re using the app"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s location?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s location?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"This app may want to access your location all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Change location access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Change location access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"This app wants to access your location all the time, even when you’re not using the app. "<annotation id="link">"Allow in Settings."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to find, connect to and determine the relative position of nearby devices? "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Change <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>’s location access from approximate to precise?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Change <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>’s location access on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; from approximate to precise?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access this device’s approximate location?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;’s approximate location?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precise"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Approximate"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your calendar?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your calendar on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send and view SMS messages?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send and view SMS messages on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos, media and files on your device?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos, media and files on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access &lt;b&gt;photos, videos, music and audio&lt;/b&gt; on this device?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access &lt;b&gt;photos, videos, music, audio and other files&lt;/b&gt; on this device?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access music and audio on this device?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access music and audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on this device?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on this device?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access photos and videos on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access more photos and videos on this device?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access more photos and videos on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"The app will only be able to record audio while you’re using the app"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to record audio on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"This app may want to record audio all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Change microphone access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Change microphone access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"This app wants to record audio all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your physical activity?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your physical activity on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"The app will only be able to take pictures and record video while you’re using the app"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to take pictures and record video on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"This app may want to take pictures and record video all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Change camera access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Change camera access for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"This app wants to take pictures and record video all the time, even when you’re not using the app. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your phone call logs?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access your phone call logs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to make and manage phone calls?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to make and manage phone calls on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access sensor data about your vital signs?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access sensor data about your vital signs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"This app wants to access sensor data about your vital signs all the time, even when you’re not using the app. To make this change, "<annotation id="link">"go to Settings."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access the sensor data about your vital signs?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access the sensor data about your vital signs on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"To let this app access body sensor data all the time, even when you’re not using the app, "<annotation id="link">"go to settings."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Keep allowing &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access body sensor data while the app is in use?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Keep allowing &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to access body sensor data on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; while app is in use?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send you notifications?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Allow &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; to send you notifications on your &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Controlled permissions"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> has location access"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Your organisation allows <xliff:g id="APP_NAME">%1$s</xliff:g> to access your location"</string>
@@ -520,7 +559,7 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"For apps and services"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Microphone data may still be shared when you call an emergency number."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Change"</string>
- <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Security &amp; privacy"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Security and privacy"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"Scan device"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Dismiss"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Dismiss this alert?"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"This app stated that it may share location data with third parties"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Data sharing and location"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Where data sharing info comes from"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"The developer provided info to this device\'s manufacturer about how this app shares data. The developer may update this info over time."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"The developer provided info to "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" about how this app shares data. The developer may update this info over time."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"This app may share location data for:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Data sharing varies"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Data safety"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Location data may be shared"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"This app stated that it may share your location data with third parties"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Can’t open this link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Data sharing updates for location"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Review apps that changed the way that they may share your location data"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"These apps have changed the way that they may share your location data. They may not have shared it before or may now share it for advertising or marketing purposes."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Data sharing updates"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Some apps changed the way that they may share your location data"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Settings"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Accessed <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Accessed yesterday <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Accessed <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-en-rXC/strings.xml b/PermissionController/res/values-en-rXC/strings.xml
index bf63f7ab4..9a9841f39 100644
--- a/PermissionController/res/values-en-rXC/strings.xml
+++ b/PermissionController/res/values-en-rXC/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎More info‎‏‎‎‏‎"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‎Allow all‎‏‎‎‏‎"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‎Always allow all‎‏‎‎‏‎"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎Allow limited access‎‏‎‎‏‎"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎Select photos and videos‎‏‎‎‏‎"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎Select more‎‏‎‎‏‎"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎Don’t select more‎‏‎‎‏‎"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎Apps‎‏‎‎‏‎"</string>
<string name="app_permissions" msgid="3369917736607944781">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎‏‎App permissions‎‏‎‎‏‎"</string>
<string name="unused_apps" msgid="2058057455175955094">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‏‏‎‎Unused apps‎‏‎‎‏‎"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎Edit selected photos for this app‎‏‎‎‏‎"</string>
<string name="no_unused_apps" msgid="12809387670415295">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎No unused apps‎‏‎‎‏‎"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‎‎‎0 unused apps‎‏‎‎‏‎"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‎‎Recent permission decisions‎‏‎‎‏‎"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎All permissions‎‏‎‎‏‎"</string>
<string name="other_permissions" msgid="2901186127193849594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎Other app capabilities‎‏‎‎‏‎"</string>
<string name="permission_request_title" msgid="8790310151025020126">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎Permission request‎‏‎‎‏‎"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‏‎‎‏‎Android Wear‎‏‎‎‏‎"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎Install/Uninstall actions not supported on Wear.‎‏‎‎‏‎"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎Choose what to allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access‎‏‎‎‏‎"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‏‏‏‎‎‎‏‎&lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; has been updated. Choose what to allow this app to access.‎‏‎‎‏‎"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎Cancel‎‏‎‎‏‎"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎Remove permissions if app isn’t used‎‏‎‎‏‎"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎Remove permissions and free up space‎‏‎‎‏‎"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‎Pause app activity if unused‎‏‎‎‏‎"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎Manage app if unused‎‏‎‎‏‎"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎Remove permissions, delete temporary files, and stop notifications‎‏‎‎‏‎"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎Remove permissions, delete temporary files, stop notifications, and archive the app‎‏‎‎‏‎"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‏‎To protect your data, permissions for this app will be removed if the app is unused for a few months.‎‏‎‎‏‎"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‎To protect your data, if the app is unused for a few months, the following permissions will be removed: ‎‏‎‎‏‏‎<xliff:g id="PERMS">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‎To protect your data, permissions have been removed from apps that you haven’t used in a few months.‎‏‎‎‏‎"</string>
@@ -401,6 +403,11 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎Notes app‎‏‎‎‏‎"</string>
<string name="role_notes_description" msgid="8496852798616883551">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎Apps that allow you to take notes on your device‎‏‎‎‏‎"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‎notes‎‏‎‎‏‎"</string>
+ <string name="role_wallet_label" msgid="3719419175656204207">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎Default wallet app‎‏‎‎‏‎"</string>
+ <string name="role_wallet_short_label" msgid="6521288403762457452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎Wallet app‎‏‎‎‏‎"</string>
+ <string name="role_wallet_description" msgid="3726535836165949838">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎Wallet apps can store your credit and loyalty cards, car keys and other things to help with various forms of transactions.‎‏‎‎‏‎"</string>
+ <string name="role_wallet_request_title" msgid="4770217108262737093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎Set ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ as your default wallet app?‎‏‎‎‏‎"</string>
+ <string name="role_wallet_request_description" msgid="6305487425777483053">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎No permissions needed‎‏‎‎‏‎"</string>
<string name="request_role_current_default" msgid="738722892438247184">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎Current default‎‏‎‎‏‎"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‎Don’t ask again‎‏‎‎‏‎"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎Set as default‎‏‎‎‏‎"</string>
@@ -455,48 +462,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎Show assistant trigger detection‎‏‎‎‏‎"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎Show icon in status bar when microphone is used to activate voice assistant‎‏‎‎‏‎"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access photos and media on your device?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access photos and media on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your contacts?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your contacts on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access this device’s location?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎’s&lt;/b&gt; location?‎‏‎‎‏‎"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‏‎‎The app will only have access to the location while you’re using the app‎‏‎‎‏‎"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access this device’s location?‎‏‎‎‏‎"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎’s location?‎‏‎‎‏‎"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎This app may want to access your location all the time, even when you’re not using the app. ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎Allow in settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎Change location access for &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎Change location access for &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎This app wants to access your location all the time, even when you’re not using the app. ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎Allow in settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to find, connect to, and determine the relative position of nearby devices?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to find, connect to, and determine the relative position of nearby devices on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to find, connect to, and determine the relative position of nearby devices? ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎Allow in settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‎Change ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>‎‏‎‎‏‏‏‎’s location access from approximate to precise?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎Change ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>‎‏‎‎‏‏‏‎’s location access on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; from approximate to precise?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access this device’s approximate location?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;’s approximate location?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎Precise‎‏‎‎‏‎"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎Approximate‎‏‎‎‏‎"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your calendar?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your calendar on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to send and view SMS messages?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‏‎‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to send and view SMS messages on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access photos, media, and files on your device?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‏‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access photos, media, and files on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‎‎‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access &lt;b&gt;photos, videos, music, and audio&lt;/b&gt; on this device?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access &lt;b&gt;photos, videos, music, audio, and other files&lt;/b&gt; on this device?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access music and audio on this device?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access music and audio on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access photos and videos on this device?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access photos and videos on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access more photos and videos on this device?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access more photos and videos on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to record audio?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‎‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to record audio on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎The app will only be able to record audio while you’re using the app‎‏‎‎‏‎"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to record audio?‎‏‎‎‏‎"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‎‎‎‏‎‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to record audio on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎This app may want to record audio all the time, even when you’re not using the app. ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎Allow in settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎Change microphone access for &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎Change microphone access for &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎This app wants to record audio all the time, even when you’re not using the app. ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎Allow in settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your physical activity?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your physical activity on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎‏‏‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to take pictures and record video?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‏‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to take pictures and record video on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎The app will only be able to take pictures and record video while you’re using the app‎‏‎‎‏‎"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to take pictures and record video?‎‏‎‎‏‎"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to take pictures and record video on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎This app may want to take pictures and record video all the time, even when you’re not using the app. ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎Allow in settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‎Change camera access for &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎Change camera access for &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‎‏‎This app wants to take pictures and record video all the time, even when you’re not using the app. ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎Allow in settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your phone call logs?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access your phone call logs on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to make and manage phone calls?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to make and manage phone calls on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access sensor data about your vital signs?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access sensor data about your vital signs on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‎‎‏‏‎This app wants to access sensor data about your vital signs all the time, even when you’re not using the app. To make this change, ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎go to settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access the sensor data about your vital signs?‎‏‎‎‏‎"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access the sensor data about your vital signs on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‎To let this app access body sensor data all the time, even when you’re not using the app, ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎go to settings.‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎Keep allowing &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access body sensor data while app is in use?‎‏‎‎‏‎"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎Keep allowing &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to access body sensor data on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; while app is in use?‎‏‎‎‏‎"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to send you notifications?‎‏‎‎‏‎"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎Allow &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; to send you notifications on your &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt;?‎‏‎‎‏‎"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎Controlled permissions‎‏‎‎‏‎"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has location access‎‏‎‎‏‎"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‎‎Your organization allows ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access your location‎‏‎‎‏‎"</string>
@@ -589,6 +623,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‎‎This app stated it may share location data with third parties‎‏‎‎‏‎"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎Data sharing and location‎‏‎‎‏‎"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎Where data sharing info comes from‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎The developer provided info to this device\'s manufacturer about how this app shares data. The developer may update this info over time.‎‏‎‎‏‎"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‎The developer provided info to ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<annotation id="install_source" example="App Store">"‎‏‎‎‏‏‏‎%1$s‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎ about how this app shares data. The developer may update this info over time.‎‏‎‎‏‎"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎This app may share location data for:‎‏‎‎‏‎"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎Data sharing varies‎‏‎‎‏‎"</string>
@@ -606,8 +641,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎Data safety‎‏‎‎‏‎"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎Location data may be shared‎‏‎‎‏‎"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‎‎‎This app stated it may share your location data with third parties‎‏‎‎‏‎"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‎Can’t open this link‎‏‎‎‏‎"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‏‎Data sharing updates for location‎‏‎‎‏‎"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎Review apps that changed the way they may share your location data‎‏‎‎‏‎"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‎These apps have changed the way they may share your location data. They may not have shared it before, or may now share it for advertising or marketing purposes.‎‏‎‎‏‎"</string>
@@ -620,4 +653,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‏‎Data sharing updates‎‏‎‎‏‎"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎Some apps changed the way they may share your location data‎‏‎‎‏‎"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎Settings‎‏‎‎‏‎"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‏‎Accessed ‎‏‎‎‏‏‎<xliff:g id="TIME_DATE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‎Accessed yesterday ‎‏‎‎‏‏‎<xliff:g id="TIME_DATE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‎‎‎Accessed ‎‏‎‎‏‏‎<xliff:g id="TIME_DATE_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎<xliff:g id="TIME_DATE_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
</resources>
diff --git a/PermissionController/res/values-es-rUS-v33/strings.xml b/PermissionController/res/values-es-rUS-v33/strings.xml
index 5aeea4db3..0205fca80 100644
--- a/PermissionController/res/values-es-rUS-v33/strings.xml
+++ b/PermissionController/res/values-es-rUS-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Más alertas"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertas descartadas"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Expande y ve una alerta más}many{Expande y ve # de alertas más}other{Expande y ve # alertas más}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerta: <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Se completó la acción"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Revisa los parámetros de configuración que pueden proteger aún más tu dispositivo"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Configuración rápida de parámetros de seguridad y privacidad"</string>
diff --git a/PermissionController/res/values-es-rUS/strings.xml b/PermissionController/res/values-es-rUS/strings.xml
index fa0201af9..1590717e5 100644
--- a/PermissionController/res/values-es-rUS/strings.xml
+++ b/PermissionController/res/values-es-rUS/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Más información"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Permitir todo"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Permitir todo siempre"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Permite el acceso limitado"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Seleccionar fotos y videos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Seleccionar más"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"No seleccionar más"</string>
@@ -41,7 +42,7 @@
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Ignorar"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="permission_warning_template" msgid="2247087781222679458">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; realice la siguiente acción: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pueda <xliff:g id="ACTION">%2$s</xliff:g> siempre?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; siempre pueda realizar la siguiente acción: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Solo cuando se usa la app"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Siempre"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"No permitir y no volver a preguntar"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"Permisos de la app"</string>
<string name="unused_apps" msgid="2058057455175955094">"Apps que no usas"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Editar las fotos seleccionadas para esta app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"No hay ninguna app sin usar"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 apps en desuso"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Acciones recientes de permisos"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Todos los permisos"</string>
<string name="other_permissions" msgid="2901186127193849594">"Otras funciones de la app"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Solicitud de permiso"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear no admite las acciones de instalación y desinstalación"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Selecciona los permisos de acceso para &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Se actualizó &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;. Selecciona los permisos de acceso para esta app."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancelar"</string>
@@ -130,8 +130,8 @@
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Ver otros permisos"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
<string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> y <xliff:g id="NUM">%3$s</xliff:g> más"</string>
- <string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"Cronograma de cuándo las apps usaron tu <xliff:g id="PERMGROUP">%1$s</xliff:g> durante las últimas 24 horas"</string>
- <string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Cronograma de cuándo las apps usaron tu <xliff:g id="PERMGROUP">%1$s</xliff:g> durante los últimos 7 días"</string>
+ <string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"Cronología de cuándo las apps usaron tu <xliff:g id="PERMGROUP">%1$s</xliff:g> durante las últimas 24 horas"</string>
+ <string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Cronología de cuándo las apps usaron tu <xliff:g id="PERMGROUP">%1$s</xliff:g> durante los últimos 7 días"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Cuándo esta app usó tu permiso de <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Más información"</string>
<string name="learn_more_content_description" msgid="8673699744544502539">"Más información sobre <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Quitar los permisos si la app no se usa"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Quitar permisos y liberar espacio"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pausar actividad en la app si no se usa"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Administrar la app si no se usa"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Quitar permisos, borrar archivos temporales y detener notificaciones"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Quita permisos, borra archivos temporales, detiene notificaciones y archiva la app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Para proteger tus datos, se quitarán los permisos de esta app si no la usas durante varios meses."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Para proteger tus datos, si no usas la app durante varios meses, se quitarán los siguientes permisos: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Para proteger tus datos, se quitaron los permisos de las apps que están en desuso hace varios meses."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"App de notas"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps que te permiten tomar notas en tu dispositivo"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notas"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"App predeterminada actualmente"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"No volver a preguntar"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Hacer predeterminada"</string>
@@ -424,7 +436,7 @@
<string name="default_apps" msgid="5119201969348748639">"Apps predeterminadas"</string>
<string name="no_default_apps" msgid="2593466527182950231">"Sin apps predeterminadas"</string>
<string name="default_apps_more" msgid="4078194675848858093">"Más apps predeterminadas"</string>
- <string name="default_apps_manage_domain_urls" msgid="6775566451561036069">"Vínculos de apertura"</string>
+ <string name="default_apps_manage_domain_urls" msgid="6775566451561036069">"Abrir vínculos"</string>
<string name="default_apps_for_work" msgid="4970308943596201811">"Predeterminadas de trabajo"</string>
<string name="default_app_none" msgid="9084592086808194457">"Ninguna"</string>
<string name="default_app_system_default" msgid="6218386768175513760">"(Predeterminada de sistema)"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Mostrar detección de activación de asistente"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mostrar ícono en la barra de estado cuando se use el micrófono para activar la función \"Asistente de voz\""</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"¿Quieres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a las fotos y el contenido multimedia del dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a fotos y contenido multimedia en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a tus contactos?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los contactos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"¿Quieres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación de tu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"La app solo tendrá acceso a la ubicación cuando esté en uso"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"¿Quieres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación de este dispositivo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación de tu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&amp;gt?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Es posible que esta app quiera acceder a tu ubicación todo el tiempo, incluso cuando no la uses. "<annotation id="link">"Permite el acceso en Configuración."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"¿Quieres cambiar el acceso a la ubicación de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"¿Cambiar el acceso a la ubicación de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Esta app quiere acceder a tu ubicación todo el tiempo, incluso cuando no la uses. "<annotation id="link">"Permite el acceso en Configuración."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encuentre dispositivos cercanos, se conecte a ellos y determine su ubicación relativa?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; busque disp. cercanos, se conecte y fije su posición relativa en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encuentre dispositivos cercanos, se conecte a ellos y determine su ubicación relativa? "<annotation id="link">"Hazlo en Configuración."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"¿Quieres cambiar el acceso a la ubicación de <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> de aproximada a precisa?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"¿Cambiar el acceso a la ubicación de <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; de Aproximada a Precisa?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"¿Deseas permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación aproximada de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación aproximada de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precisa"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aproximada"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a tu calendario?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda al calendario en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe y vea SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe y vea SMS en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"¿Quieres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a las fotos, el contenido multimedia y los archivos de tu dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a fotos, contenido multimedia y archivos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a &lt;b&gt;fotos, videos, música y audio&lt;/b&gt; del dispositivo?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a &lt;b&gt;fotos, videos, música, audio y otros archivos&lt;/b&gt; del dispositivo?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la música y los archivos de audio de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la música y al audio en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a las fotos y los videos de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a fotos y videos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"¿Quieres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a más fotos y videos del dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a más fotos y videos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grabe audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grabe audio en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"La app solo podrá grabar audio cuando esté en uso"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grabe audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grabe audio en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Es posible que esta app quiera grabar audio todo el tiempo, incluso cuando no la estés usando. "<annotation id="link">"Permite el acceso en Configuración."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"¿Cambiar el acceso al micrófono de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"¿Cambiar el acceso al micrófono de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Esta app quiere grabar audio todo el tiempo, incluso cuando no la uses. "<annotation id="link">"Permite el acceso en Configuración."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"¿Quieres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a tu actividad física?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la actividad física en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tome fotos y grabe videos?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tome fotos y grabe videos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"La app solo podrá tomar fotos y grabar videos cuando esté en uso"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tome fotos y grabe videos?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tome fotos y grabe videos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Es posible que esta app quiera tomar fotos y grabar videos todo el tiempo, incluso cuando no la estés usando. "<annotation id="link">"Permite el acceso en Configuración."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"¿Cambiar el acceso a la cámara de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"¿Cambiar el acceso a la cámara de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Esta app quiere tomar fotos y grabar videos todo el tiempo, incluso cuando no la uses. "<annotation id="link">"Permite el acceso en Configuración."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda al registro de las llamadas telefónicas?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los registros de llamadas en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; haga y administre las llamadas telefónicas?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; haga y administre llamadas telefónicas en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los datos de sensores de tus signos vitales?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a datos de sensores de tus signos vitales en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Esta app quiere acceder a los datos de sensores de tus signos vitales todo el tiempo, incluso cuando no la usas. Para realizar este cambio, "<annotation id="link">"ve a configuración."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"¿Quieres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los datos de los sensores de tus signos vitales?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a datos de sensores de tus signos vitales en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Para permitir que esta app acceda a datos del sensor corporal todo el tiempo, incluso cuando no la uses, "<annotation id="link">"ve a la configuración."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"¿Quieres seguir permitiendo que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a datos del sensor corporal mientras está en uso?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"¿Seguir permitiendo que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a datos del sensor corporal de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mientras se usa?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"¿Quieres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; te envíe notificaciones?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; te envíe notificaciones en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Permisos controlados"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> tiene acceso a la ubicación"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Tu organización permite que <xliff:g id="APP_NAME">%1$s</xliff:g> acceda a tu ubicación"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Otros permisos"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permiso que usa el sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permisos que usan solo las aplicaciones del sistema."</string>
@@ -515,7 +552,7 @@
<string name="privdash_label_24h" msgid="1512532123865375319">"Últimas\n24 horas"</string>
<string name="privdash_label_7d" msgid="5645301995348656931">"Últimos\n7 días"</string>
<string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"<xliff:g id="APP_NAME">%1$s</xliff:g> está protegida por Android. Tus datos se procesan en este dispositivo, por eso no se muestra el uso de permisos de esta app en la barra de estado ni en el panel de privacidad."</string>
- <string name="exempt_info_label" msgid="6286190981253476699">"protege <xliff:g id="APP_NAME">%1$s</xliff:g> está protegida por Android. Tus datos se procesan en este dispositivo, por eso no se muestra el uso de permisos de esta app en la barra de estado ni en el panel de privacidad."</string>
+ <string name="exempt_info_label" msgid="6286190981253476699">"<xliff:g id="APP_NAME">%1$s</xliff:g> está protegida por Android. Tus datos se procesan en este dispositivo, por eso no se muestra el uso de permisos de esta app en el panel de privacidad."</string>
<string name="blocked_camera_title" msgid="1128510551791284384">"La cámara del dispositivo está bloqueada"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"El micrófono del dispositivo está bloqueado"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"La ubicación del dispositivo está desactivada"</string>
@@ -585,12 +622,13 @@
<string name="mic_toggle_description" msgid="9163104307990677157">"Para apps y servicios. Aunque se desactive este parámetro de configuración, es posible que se sigan compartiendo los datos del micrófono cuando llames a un número de emergencia."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Consulta las apps y los servicios que tienen acceso a la ubicación"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Mostrar acceso a portapapeles"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Mostrar un mensaje cuando las apps accedan a textos, imágenes y otro contenido que hayas copiado"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Muestra un mensaje cuando las apps accedan a texto, imágenes y otro contenido que hayas copiado"</string>
<string name="show_password_title" msgid="2877269286984684659">"Mostrar contraseñas"</string>
<string name="show_password_summary" msgid="1110166488865981610">"Mostrar caracteres brevemente mientras escribes"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Esta app indicó que podría compartir datos de ubicación con terceros"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Uso compartido de datos y ubicación"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"De dónde proviene la información de uso compartido de datos"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"El desarrollador brindó información al fabricante del dispositivo sobre el uso compartido de datos de esta app. El desarrollador podría actualizar esta información con el tiempo."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"El desarrollador brindó información a "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" sobre el uso compartido de datos de esta app. El desarrollador podría actualizar esta información con el tiempo."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Esta app puede compartir datos de ubicación para:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"El uso compartido de datos varía"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Seguridad de los datos"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Es posible que se compartan los datos de ubicación"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Esta app indicó que podría compartir tus datos de ubicación con terceros"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"No se puede abrir este vínculo"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Actualizaciones del uso compartido de los datos de ubicación"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Revisa las apps que cambiaron la forma en que comparten tus datos de ubicación"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Estas apps cambiaron la forma en que podrían compartir tus datos de ubicación. Es posible que no los hayan compartido antes o que ahora los compartan con fines publicitarios o de marketing."</string>
@@ -618,8 +654,11 @@
<string name="shares_location_with_third_parties" msgid="2278051743742057767">"Tus datos de ubicación ahora se comparten con terceros"</string>
<string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Tus datos de ubicación ahora se comparten con terceros para publicidad o marketing"</string>
<string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Se actualizó en el último día}=1{Se actualizó en el último día}many{Se actualizó en los últimos # de días}other{Se actualizó en los últimos # días}}"</string>
- <string name="no_updates_at_this_time" msgid="9031085635689982935">"No hay novedades por el momento"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"No hay actualizaciones por el momento"</string>
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Actualizaciones del uso compartido de datos"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Algunas apps cambiaron la forma en que podrían compartir tus datos de ubicación"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Configuración"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Último acceso: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Último acceso: ayer a la(s) <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Último acceso: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> a la(s) <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-es-v33/strings.xml b/PermissionController/res/values-es-v33/strings.xml
index 4f50aaa25..69b1ce6f5 100644
--- a/PermissionController/res/values-es-v33/strings.xml
+++ b/PermissionController/res/values-es-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Más alertas"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertas ignoradas"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Ampliar para ver una alerta más}many{Ampliar para ver # alertas más}other{Ampliar para ver # alertas más}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerta. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Acción completada"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Comprueba los ajustes que pueden proteger más tu dispositivo"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Ajustes rápidos de seguridad y privacidad"</string>
diff --git a/PermissionController/res/values-es/strings.xml b/PermissionController/res/values-es/strings.xml
index 951e5b10b..b52c0712e 100644
--- a/PermissionController/res/values-es/strings.xml
+++ b/PermissionController/res/values-es/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Más información"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Permitir todos"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Permitir todos siempre"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Permitir acceso limitado"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Seleccionar fotos y vídeos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Seleccionar más"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"No seleccionar más"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"No permitir de todas formas"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Cerrar"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"¿Permitir a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"¿Quieres permitir siempre a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"¿Permitir a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lo siguiente? <xliff:g id="ACTION">%2$s</xliff:g>"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"¿Permitir siempre a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lo siguiente? <xliff:g id="ACTION">%2$s</xliff:g>"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Solo mientras se usa la aplicación"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Siempre"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"No permitir y no volver a preguntar"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplicaciones"</string>
<string name="app_permissions" msgid="3369917736607944781">"Permisos de aplicaciones"</string>
<string name="unused_apps" msgid="2058057455175955094">"Aplicaciones no usadas"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Cambia las fotos seleccionadas para esta aplicación"</string>
<string name="no_unused_apps" msgid="12809387670415295">"No hay aplicaciones no usadas"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 aplicaciones no usadas"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Decisiones recientes de permisos"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Todos los permisos"</string>
<string name="other_permissions" msgid="2901186127193849594">"Otras funciones de la aplicación"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Solicitud de permiso"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Las acciones de instalar y desinstalar no pueden realizarse en Wear"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Elige los permisos de acceso que quieres conceder a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se ha actualizado. Elige los permisos de acceso que quieres conceder a esta aplicación."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancelar"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Quitar permisos si la aplicación no se usa"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Quitar permisos y liberar espacio"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pausar actividad de la aplicación si no se usa"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gestionar la aplicación si no se usa"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Quita permisos, elimina archivos temporales y detiene las notificaciones"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Quita permisos, elimina archivos temporales, detiene las notificaciones y archiva la aplicación"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Para proteger tus datos, se quitarán los permisos de esta aplicación si no la usas durante unos meses."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Para proteger tus datos, si la aplicación no se ha utilizado durante unos meses, se quitarán los siguientes permisos: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Para proteger tus datos, se han quitado los permisos de las aplicaciones que llevas unos meses sin usar."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Se abrió por última vez el <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Si permites la gestión de todos los archivos, esta aplicación podrá consultar, modificar y eliminar cualquier archivo que haya en el almacenamiento común de este dispositivo o en los dispositivos de almacenamiento conectados. Es posible que acceda a archivos sin preguntarte."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"¿Permitir que esta aplicación pueda consultar, modificar y eliminar archivos de este dispositivo o de los dispositivos de almacenamiento conectados? Quizá acceda a archivos sin solicitarlo explícitamente."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Las aplicaciones con este permiso pueden <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Las aplicaciones con este permiso pueden hacer lo siguiente: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Las aplicaciones con este permiso pueden acceder a tu actividad física, como paseos a pie o en bici, trayectos en coche, número de pasos y más"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Las aplicaciones con este permiso pueden acceder a tu calendario"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Las aplicaciones con este permiso pueden leer y editar el registro de llamadas del teléfono"</string>
@@ -246,12 +248,12 @@
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"No ha accedido nunca"</string>
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"Denegado / Último acceso: Nunca"</string>
<string name="allowed_header" msgid="7769277978004790414">"Permitido"</string>
- <string name="allowed_always_header" msgid="6455903312589013545">"Permitido siempre"</string>
+ <string name="allowed_always_header" msgid="6455903312589013545">"Permitidas siempre"</string>
<string name="allowed_foreground_header" msgid="6845655788447833353">"Permitidas solo mientras se usan"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"Pueden acceder solo al contenido multimedia"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"Pueden gestionar todos los archivos"</string>
<string name="ask_header" msgid="2633816846459944376">"Preguntar siempre"</string>
- <string name="denied_header" msgid="903209608358177654">"No permitido"</string>
+ <string name="denied_header" msgid="903209608358177654">"No permitidas"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Ver más aplicaciones que pueden acceder a todos los archivos"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 día}many{# días}other{# días}}"</string>
<string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
@@ -347,7 +349,7 @@
<string name="accessibility_service_dialog_title_multiple" msgid="5527879210683548175">"<xliff:g id="NUM_SERVICES">%s</xliff:g> aplicaciones de accesibilidad tienen acceso completo a tu dispositivo"</string>
<string name="accessibility_service_dialog_bottom_text_single" msgid="1128666197822205958">"<xliff:g id="SERVICE_NAME">%s</xliff:g> puede ver tu pantalla, lo que haces y lo que introduces; realizar acciones; y controlar la pantalla."</string>
<string name="accessibility_service_dialog_bottom_text_multiple" msgid="7009848932395519852">"Estas aplicaciones pueden ver tu pantalla, lo que haces y lo que introduces; realizar acciones; y controlar la pantalla."</string>
- <string name="role_assistant_label" msgid="4727586018198208128">"Asistente digital predeterminado"</string>
+ <string name="role_assistant_label" msgid="4727586018198208128">"Asistente predeterminado"</string>
<string name="role_assistant_short_label" msgid="3369003713187703399">"Asistente digital"</string>
<string name="role_assistant_description" msgid="6622458130459922952">"Las aplicaciones de asistencia te ayudan según la información que aparezca en la pantalla. Algunas aplicaciones admiten tanto el menú de aplicaciones como los servicios de entrada de voz para ofrecerte asistencia integrada."</string>
<string name="role_browser_label" msgid="2877796144554070207">"Aplicación de navegador predeterminada"</string>
@@ -397,10 +399,20 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tu teléfono, SMS, contactos y calendario."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y reproducir tus aplicaciones en el dispositivo conectado."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Este servicio comparte las fotos, el contenido multimedia y las notificaciones de tu teléfono con otros dispositivos."</string>
- <string name="role_notes_label" msgid="7451627001058089536">"App de notas predeterminada"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Aplicación de notas predeterminada"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplicación de notas"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplicaciones que te permiten tomar notas en tu dispositivo"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notas"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Predeterminada"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"No volver a preguntar"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Establecer como predeterminado"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Mostrar la detección de activación del asistente"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mostrar icono en la barra de estado cuando se utilice el micrófono para activar el asistente de voz"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a las fotos y archivos multimedia del dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a fotos y vídeos de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a tus contactos?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los contactos de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación de tu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"La aplicación solo podrá acceder a la ubicación cuando la estés usando"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación de este dispositivo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación de tu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Es posible que esta aplicación quiera acceder a tu ubicación siempre, aunque no la estés usando. Puedes darle permiso en "<annotation id="link">"Ajustes"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"¿Quieres cambiar el acceso a la ubicación de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"¿Cambiar el acceso a la ubicación de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Esta aplicación quiere acceder a tu ubicación siempre, incluso aunque no la estés usando. Puedes darle permiso en "<annotation id="link">"Ajustes"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; busque, se conecte y determine la posición relativa de dispositivos cercanos?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; busque, se conecte y fije la posición relativa de disp. cercanos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; busque, se conecte y determine la posición relativa de dispositivos cercanos? "<annotation id="link">"Permítelo en los ajustes"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"¿Cambiar el acceso a la ubicación de <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> de aproximada a precisa?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"¿Cambiar el acceso a la ubicación de <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; de Aproximada a Precisa?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación aproximada de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la ubicación aproximada de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precisa"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aproximada"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a tu calendario?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda al calendario de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe y lea mensajes SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe y lea mensajes SMS en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a las fotos, al contenido multimedia y a los archivos de tu dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a fotos, contenido multimedia y archivos de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a &lt;b&gt;fotos, vídeos, música y audio&lt;/b&gt; de este dispositivo?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a &lt;b&gt;fotos, vídeos, música, audio y otros archivos&lt;/b&gt; del dispositivo?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a música y audio de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la música y audio de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a fotos y vídeos de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a fotos y vídeos de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a más fotos y vídeos de este dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a más fotos y vídeos de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grabe audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grabe vídeos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"La aplicación solo podrá grabar audio mientras la estés usando."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grabe audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grabe vídeos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Es posible que esta aplicación deba grabar audio en todo momento, aunque no se esté usando. Puedes darle este permiso en "<annotation id="link">"Ajustes."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"¿Quieres cambiar el acceso de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; al micrófono?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"¿Cambiar el acceso al micrófono de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Esta aplicación debe grabar audio en todo momento, aunque no la estés usando. "<annotation id="link">"Puedes darle este permiso en Ajustes."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a tu actividad física?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a la actividad física de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; haga fotos y grabe vídeos?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; haga fotos y grabe vídeos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"La aplicación solo podrá hacer fotografías y grabar vídeos mientras la estés usando."</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; haga fotos y grabe vídeos?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; haga fotos y grabe vídeos en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Es posible que esta aplicación deba hacer fotografías y grabar vídeos en todo momento, aunque no se esté usando. "<annotation id="link">"Puedes darle este permiso en Ajustes."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"¿Quieres cambiar el acceso de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; a la cámara?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"¿Cambiar el acceso a la cámara de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Esta aplicación debe hacer fotografías y grabar vídeos en todo momento, aunque no la estés usando. "<annotation id="link">"Puedes darle este permiso en Ajustes."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los registros de llamadas del teléfono?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los registros de llamadas de teléfono de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; haga y gestione llamadas?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; haga y gestione llamadas en tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los datos del sensor sobre tus constantes vitales?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los datos de sensores sobre constantes vitales de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Esta aplicación quiere acceder a los datos de sensores de tus constantes vitales todo el tiempo, incluso cuando no la uses. Para hacer este cambio, "<annotation id="link">"ve a los ajustes"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los datos de sensores de tus constantes vitales?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los datos de sensores sobre constantes vitales de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Para permitir que esta aplicación acceda a datos de sensores corporales todo el tiempo, incluso cuando no la uses, "<annotation id="link">"ve a los ajustes"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"¿Seguir permitiendo que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los datos de los sensores corporales mientras se usa?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a los datos del sensor corporal de tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mientras se usa?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; te envíe notificaciones?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe notificaciones a tu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Permisos controlados"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> tiene acceso a la ubicación"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Tu organización permite que <xliff:g id="APP_NAME">%1$s</xliff:g> acceda a tu ubicación"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Otros permisos"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permiso usado por el sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permisos usados solo por las aplicaciones del sistema."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Esta aplicación ha indicado que puede compartir datos de ubicación con terceros"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Datos compartidos y ubicación"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"De dónde procede la información sobre cómo se comparten los datos"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"El desarrollador ha proporcionado información al fabricante de este dispositivo sobre cómo comparte datos esta aplicación. Es posible que el desarrollador actualice esta información con el tiempo."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"El desarrollador ha proporcionado información a "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" sobre cómo comparte datos esta aplicación. Es posible que el desarrollador actualice esta información con el tiempo."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Esta app puede compartir datos de ubicación para:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"La forma de compartir datos varía"</string>
@@ -599,7 +637,7 @@
<string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Tus datos de ubicación"</string>
<string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Cambia el acceso de esta aplicación en la "<annotation id="link">"configuración de privacidad"</annotation></string>
<string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funcionalidad de la aplicación"</string>
- <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analítica"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Estadísticas"</string>
<string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Comunicaciones del desarrollador"</string>
<string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Publicidad o marketing"</string>
<string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prevención de fraudes, seguridad y cumplimiento"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Seguridad de los datos"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Tus datos de ubicación pueden compartirse"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Esta aplicación ha indicado que es posible que comparta tus datos de ubicación con terceros"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"No se puede abrir este enlace"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Cambios en los datos compartidos de ubicación"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Consulta las aplicaciones que han cambiado cómo comparten tus datos de ubicación"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Estas aplicaciones han cambiado cómo pueden compartir tus datos de ubicación. Puede que no los hayan compartido antes, o que ahora lo hagan con fines publicitarios o de marketing."</string>
@@ -618,8 +654,11 @@
<string name="shares_location_with_third_parties" msgid="2278051743742057767">"Tus datos de ubicación ahora se comparten con terceros"</string>
<string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Tus datos de ubicación ahora se comparten con terceros para fines de publicidad o marketing"</string>
<string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Se ha actualizado en el último día}=1{Se ha actualizado en el último día}many{Se ha actualizado en los últimos # días}other{Se ha actualizado en los últimos # días}}"</string>
- <string name="no_updates_at_this_time" msgid="9031085635689982935">"No hay novedades por el momento"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"No hay cambios por el momento"</string>
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Cambios en cómo se comparten los datos"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Algunas aplicaciones han cambiado cómo pueden compartir tus datos de ubicación"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Ajustes"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Último acceso: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Último acceso: ayer, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Último acceso: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-et-v34/strings.xml b/PermissionController/res/values-et-v34/strings.xml
index 91567dd9e..4476aecdd 100644
--- a/PermissionController/res/values-et-v34/strings.xml
+++ b/PermissionController/res/values-et-v34/strings.xml
@@ -22,6 +22,6 @@
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
<string name="health_connect_summary" msgid="815473513776882296">"Saate hallata rakenduse juurdepääsu terviseandmetele"</string>
<string name="location_settings" msgid="8863940440881290182">"Juurdepääs asukohale"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Rakenduste ja teenuste jaoks. Isegi kui see seade on välja lülitatud, võidakse mikrofoni andmeid siiski jagada hädaabinumbrile helistades"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Rakenduste ja teenuste jaoks. Isegi kui see seade on välja lülitatud, võidakse mikrofoni andmeid siiski jagada hädaabinumbrile helistades."</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Rakenduste ja teenuste jaoks"</string>
</resources>
diff --git a/PermissionController/res/values-et/strings.xml b/PermissionController/res/values-et/strings.xml
index d6c2e7f26..748d966e2 100644
--- a/PermissionController/res/values-et/strings.xml
+++ b/PermissionController/res/values-et/strings.xml
@@ -32,16 +32,17 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Säilita valik „Rakenduse kasutamise ajal”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Säilita ainult sel korral"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Lisateave"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Luba kõik"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Anna juurdepääs kõigile"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Luba alati kõik"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Luba piiratud juurdepääs"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Valige fotod ja videod"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Valige rohkem"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ära vali rohkem"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ära luba ikkagi"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Loobu"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Kas lubada rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul toiming <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Kas lubada rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul alati toiming <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Kas lubada rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul luba <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Kas lubada rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul alati luba <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Ainult rakenduse kasutamisel"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Alati"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Ära luba ja ära enam küsi"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Rakendused"</string>
<string name="app_permissions" msgid="3369917736607944781">"Rakenduse load"</string>
<string name="unused_apps" msgid="2058057455175955094">"Kasutamata rakendused"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Selle rakenduse jaoks valitud fotode muutmine"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Kasutamata rakendusi pole"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 kasutamata rakendust"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Hiljutised lubade otsused"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Luba alati"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Luba rakenduse kasutamise ajal"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Luba ainult rakenduse kasutamise ajal"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Ära luba"</string>
<string name="loading" msgid="4789365003890741082">"Laadimine …"</string>
<string name="all_permissions" msgid="6911125611996872522">"Kõik load"</string>
<string name="other_permissions" msgid="2901186127193849594">"Rakenduse muud funktsioonid"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Loa taotlus"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear ei toeta installimist/desinstallimist."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Valige, millele lubate rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurde pääseda"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Rakendust &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; värskendati. Valige, millele lubate sellel rakendusel juurde pääseda."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Tühista"</string>
@@ -187,7 +187,7 @@
<string name="app_permission_button_allow_all_files" msgid="1792232272599018825">"Luba kõikide failide haldamine"</string>
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Luba juurdepääs ainult meediale"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Luba alati"</string>
- <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Luba rakenduse kasutamise ajal"</string>
+ <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Luba ainult rakenduse kasutamise ajal"</string>
<string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Luba alati kõik"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Küsi iga kord"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Ära luba"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Eemalda load, kui rakendust ei kasutata"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Eemalda load ja vabasta ruumi"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Tegevusetuna rakenduse tegevuste peatamine"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Kasutamata rakenduse haldamine"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Eemaldatakse load, kustutatakse ajutised failid ja peatatakse märguanded"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Lubade eemaldamine, ajutiste failide kustutamine, märguannete peatamine ja rakenduse arhiivimine"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Teie andmete kaitsmiseks eemaldatakse selle rakenduse load, kui seda mõne kuu jooksul ei kasutata."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Teie andmete kaitsmiseks eemaldatakse selle rakenduse järgmised load, kui rakendust mõne kuu jooksul ei kasutata: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Teie andmete kaitsmiseks eemaldati load rakendustelt, mida te ei ole mõne kuu jooksul kasutanud."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Märkmerakendus"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Rakendused, mis võimaldavad teie seadmes märkmeid teha"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"märkmed"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Praegune vaikeseade"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ära enam küsi"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Määra vaikeseadeks"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Assistendi käivitamise tuvastamise kuvamine"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Ikooni kuvamine olekuribal, kui häälassistendi aktiveerimiseks kasutatakse mikrofoni"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs seadmes olevatele fotodele ja meediale?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs fotodele ja meediumisisule?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs teie kontaktidele?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs teie kontaktidele?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs selle seadme asukohale?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs teie seadme &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt; asukohale?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Rakendusel on juurdepääs asukohale vaid sel ajal, kui rakendust kasutate"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs selle seadme asukohale?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs selle seadme &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt; asukohale?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"See rakendus võib soovida pidevat juurdepääsu teie asukohale (ka siis, kui te rakendust ei kasuta). "<annotation id="link">"Lubage see seadetes"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Kas muuta rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul juurdepääsu asukohale?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Kas muuta rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääsu asukohale?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"See rakendus soovib pidevat juurdepääsu teie asukohale (ka siis, kui te rakendust ei kasuta). "<annotation id="link">"Lubage see seadetes"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; leida lähedalasuvaid seadmeid, nendega ühendada ja nende suhteline asukoht määrata?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; otsida ja määratleda teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; läheduses olevate seadmete suhtelist asukohta ja sellega ühendada?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; leida lähedalasuvaid seadmeid, nendega ühendada ja nende suhteline asukoht määrata? "<annotation id="link">"Lubage menüüs Seaded."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Kas muuta rakenduse <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> asukohale juurdepääsemise tase ligikaudsest täpseks?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Kas muuta rakenduse <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> juurdepääs asukohateabele teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ligikaudsest täpseks?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs selle seadme ligikaudsele asukohale?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs teie seadme &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ligikaudsele asukohale?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Täpne"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Ligikaudne"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs teie kalendrile?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs teie kalendrile?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; saata ja vaadata SMS-sõnumeid?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; saata ja vaadata teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; SMS-sõnumeid?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs seadmes olevatele fotodele, meediale ja failidele?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs fotodele, meediumisisule ja failidele?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Kas anda rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&amp;gt seadmes juurdep. &lt;b&gt;fotodele, videotele, muusikale ja helidele&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Anda rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdep. &lt;b&gt;foto-, video-, muusika-, heli- ja muudele failidele&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Kas anda rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; selles seadmes juurdepääs muusikale ja helifailidele?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; selles seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs muusikale ja helifailidele?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Kas anda rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; selles seadmes juurdepääs fotodele ja videotele?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs fotodele ja videotele?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Kas anda rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; selles seadmes juurdepääs rohkematele fotodele ja videotele?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs enamatele fotodele ja videotele?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; salvestada heli?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; salvestada teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; heli?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Rakendus saab heli salvestada vaid siis, kui rakendust kasutate"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; heli salvestada?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; salvestada teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; heli?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"See rakendus võib soovida heli salvestada mis tahes ajal (ka siis, kui te rakendust ei kasuta). "<annotation id="link">"Lubage see seadetes."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Kas muuta rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul juurdepääsu mikrofonile?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Kas muuta rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääsu mikrofonile?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"See rakendus soovib heli salvestada mis tahes ajal (ka siis, kui te rakendust ei kasuta). "<annotation id="link">"Lubage see seadetes."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Kas anda rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs teie füüsilisele tegevusele?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs teie füüsilise tegevuse andmetele?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; jäädvustada pilte ja salvestada videoid?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teha teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; pilte ja salvestada videot?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Rakendus saab pildistada ja videoid salvestada vaid siis, kui rakendust kasutate"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pildistada ja videoid salvestada?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teha teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; pilte ja salvestada videot?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"See rakendus võib soovida pildistada ja videoid salvestada mis tahes ajal (ka siis, kui te rakendust ei kasuta). "<annotation id="link">"Lubage see seadetes."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Kas muuta rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul juurdepääsu kaamerale?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Kas muuta rakenduse &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhul teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääsu kaamerale?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"See rakendus soovib pildistada ja videoid salvestada mis tahes ajal (ka siis, kui te rakendust ei kasuta). "<annotation id="link">"Lubage see seadetes."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääseda juurde teie telefoni kõnelogidele?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs teie telefoni kõnelogidele?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teha ja hallata telefonikõnesid?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teha ja hallata teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; telefonikõnesid?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs anduri andmetele teie eluliste näitajate kohta?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs anduri andmetele teie eluliste näitajate kohta?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"See rakendus soovib pidevat juurdepääsu teie elulistele näitajatele (ka siis, kui te rakendust ei kasuta). Selle muudatuse tegemiseks "<annotation id="link">"avage seaded."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; juurdepääs anduri andmetele teie eluliste näitajate kohta?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Kas lubada rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääs anduri andmetele teie eluliste näitajate kohta?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Selleks et anda rakendusele pidev juurdepääs kehaanduri andmetele (ka siis, kui rakendust ei kasutata), "<annotation id="link">"avage seaded."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Kas lubada jätkuvalt rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääseda juurde kehaanduri andmetele, kui rakendust kasutatakse?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Kas lubada jätkuvalt rakendusele &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; juurdepääsu kehaanduri andmetele, kui rakendust kasutatakse?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; teile märguandeid saata?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Kas lubada rakendusel &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; saata teie seadmes &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; teile märguandeid?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Hallatud load"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> pääseb juurde asukohale"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Teie organisatsioon lubab rakendusel <xliff:g id="APP_NAME">%1$s</xliff:g> pääseda juurde teie asukohale."</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"See rakendus andis teada, et võib asukohaandmeid jagada kolmandate osapooltega"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Andmete jagamine ja asukoht"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Andmete jagamise teabe päritolu"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Arendaja on esitanud selle seadme tootjale teavet selle kohta, kuidas see rakendus andmeid jagab. Arendaja võib seda teavet aja jooksul muuta."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Arendaja on esitanud rakenduste poele "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" teavet selle kohta, kuidas see rakendus andmeid jagab. Arendaja võib seda teavet aja jooksul muuta."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Rakendus võib asukohaandmeid jagada järgmiseks."</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Andmete jagamine võib olla erinev"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Andmete ohutus"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Asukohaandmeid võidakse jagada"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"See rakendus andis teada, et võib jagada teie asukohaandmeid kolmandate osapooltega."</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Seda linki ei saa avada"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Andmete jagamise värskendused asukoha kohta"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Vaadake üle rakendused, mis on muutnud teie asukohaandmete jagamise viisi"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Need rakendused on muutnud teie asukohaandmete jagamise viisi. Võib-olla ei jaganud nad neid varem või hakkasid neid nüüd jagama reklaami- või turunduseesmärgil."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Andmete jagamise värskendused"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Mõni rakendus on muutnud teie asukohaandmete jagamise viisi"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Seaded"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Juurde pääsetud <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Juurde pääsetud eile <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Juurde pääsetud <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-eu-v33/strings.xml b/PermissionController/res/values-eu-v33/strings.xml
index c9f8903f6..424feaf4a 100644
--- a/PermissionController/res/values-eu-v33/strings.xml
+++ b/PermissionController/res/values-eu-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Alerta gehiago"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Baztertutako alertak"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Zabaldu eta ikusi beste alerta bat}other{Zabaldu eta ikusi # alerta gehiago}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerta. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Osatu da ekintza"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Egiaztatu gailuaren segurtasuna hobe dezaketen ezarpenak"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Segurtasunari eta pribatutasunari buruzko ezarpen bizkorrak"</string>
diff --git a/PermissionController/res/values-eu/strings.xml b/PermissionController/res/values-eu/strings.xml
index 5f8f8991e..139857812 100644
--- a/PermissionController/res/values-eu/strings.xml
+++ b/PermissionController/res/values-eu/strings.xml
@@ -34,13 +34,14 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Datu gehiago"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Eman guztirako baimena"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Eman guztirako baimena beti"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Eman sarbide mugatua"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Hautatu argazkiak eta bideoak"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Hautatu beste batzuk"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ez hautatu gehiago"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ez eman baimenik halere"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Baztertu"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioak <xliff:g id="ACTION">%2$s</xliff:g> ahal izatea baimendu nahi duzu?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari \"<xliff:g id="ACTION">%2$s</xliff:g>\" baimena eman nahi diozu?"</string>
<string name="permission_add_background_warning_template" msgid="1812914855915092273">"Beti eman nahi diozu \"<xliff:g id="ACTION">%2$s</xliff:g>\" baimena &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Aplikazioa erabiltzean soilik"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Beti"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikazioak"</string>
<string name="app_permissions" msgid="3369917736607944781">"Aplikazio-baimenak"</string>
<string name="unused_apps" msgid="2058057455175955094">"Erabiltzen ez diren aplikazioak"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Editatu aplikazio honetarako hautatutako argazkiak"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Ez dago erabiltzen ez duzun aplikaziorik"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Erabiltzen ez diren 0 aplikazio"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Azkenaldian baimenen inguruan hartutako erabakiak"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Eman baimena beti"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Aplikazioa erabiltzean soilik"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Baimendu aplikazioa erabiltzean soilik"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Ez eman baimenik"</string>
<string name="loading" msgid="4789365003890741082">"Kargatzen…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Baimen guztiak"</string>
<string name="other_permissions" msgid="2901186127193849594">"Aplikazioaren beste gaitasun batzuk"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Baimen-eskaera"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Instalatzeko eta desinstalatzeko ekintzak ezin dira gauzatu Wear gailuetan."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Aukeratu zer atzi dezakeen &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioak"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Eguneratu egin da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;. Aukeratu aplikazioak zer atzi dezakeen."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Utzi"</string>
@@ -126,7 +126,7 @@
<string name="app_name_unknown" msgid="1319665005754048952">"Ezezaguna"</string>
<string name="permission_usage_title" msgid="1568233336351734538">"Pribatutasun-panela"</string>
<string name="auto_permission_usage_summary" msgid="7335667266743337075">"Ikusi zein aplikaziok erabili berri dituzten baimenak"</string>
- <string name="permission_group_usage_title" msgid="2595013198075285173">"<xliff:g id="PERMGROUP">%1$s</xliff:g> atzitzeko baimenaren erabilera"</string>
+ <string name="permission_group_usage_title" msgid="2595013198075285173">"<xliff:g id="PERMGROUP">%1$s</xliff:g> erabiltzeko baimenaren erabilera"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Ikusi beste baimen batzuk"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
<string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> eta beste <xliff:g id="NUM">%3$s</xliff:g>"</string>
@@ -163,7 +163,7 @@
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Azken minutuan baimenei eman zaien erabilera"</string>
<string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Ez da erabili azken # egunean}other{Ez da erabili azken # egunetan}}"</string>
<string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Ez da erabili azken # orduan}other{Ez da erabili azken # orduetan}}"</string>
- <string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Aplikazio batek erabili du}other{# aplikaziok erabili dute}}"</string>
+ <string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 aplikaziok erabili du}other{# aplikaziok erabili dute}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Ikusi guztiak panelean"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Iragazteko irizpidea: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_usage_remove_filter" msgid="2926157607436428207">"Kendu iragazkia"</string>
@@ -187,7 +187,7 @@
<string name="app_permission_button_allow_all_files" msgid="1792232272599018825">"Eman fitxategi guztiak kudeatzeko baimena"</string>
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Eman multimedia-fitxategiak soilik erabiltzeko baimena"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Eman baimena beti"</string>
- <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Aplikazioa erabiltzean soilik"</string>
+ <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Baimendu aplikazioa erabiltzean soilik"</string>
<string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Eman beti baliabide guztiak erabiltzeko baimena"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Galdetu beti"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Ez eman baimenik"</string>
@@ -196,7 +196,7 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"Erabili kokapen zehatza"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Kokapen zehatza desaktibatuta dagoenean, aplikazioek gutxi gorabeherako kokapena atzi dezakete"</string>
<string name="app_permission_title" msgid="2090897901051370711">"\"<xliff:g id="PERM">%1$s</xliff:g>\" baimena"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"Aplikazio honek <xliff:g id="PERM">%1$s</xliff:g> erabiltzeko duen baimena"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"Aplikazio honek \"<xliff:g id="PERM">%1$s</xliff:g>\" erabiltzeko duen baimena"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Ikusi <xliff:g id="APP">%1$s</xliff:g> aplikazioaren baimen guztiak"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Ikusi baimen hau duten aplikazio guztiak"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Erakutsi laguntzaileak mikrofonoa erabiltzeko duen baimena"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Kendu baimenak aplikazioa erabiltzen ez bada"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Kendu baimenak eta egin tokia"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pausatu aplikazioko jarduerak, erabiltzen ez bada"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Kudeatu aplikazioa erabiltzen ez bada"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Kendu baimenak, ezabatu aldi baterako fitxategiak eta geldiarazi jakinarazpenak"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Kendu baimenak, ezabatu aldi baterako fitxategiak, geldiarazi jakinarazpenak eta artxibatu aplikazioa"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Zure datuak babeste aldera, aplikazio honen baimenak kendu egingo dira aplikazioa ez baduzu erabiltzen zenbait hilabetez."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Zure datuak babeste aldera, kendu egingo dira honako baimen hauek zenbait hilabetez aplikazioa erabiltzen ez baduzu: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Zure datuak babeste aldera, kendu egin dira zenbait hilabetez erabili ez dituzun aplikazioen baimenak."</string>
@@ -232,7 +234,7 @@
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Telefonoko deien erregistroa irakur dezakete baimen hau duten aplikazioek, baita bertan idatzi ere"</string>
<string name="permission_description_summary_camera" msgid="108004375101882069">"Argazkiak atera eta bideoak graba ditzakete baimen hau duten aplikazioek"</string>
<string name="permission_description_summary_contacts" msgid="2337798886460408996">"Zure kontaktuak atzi ditzakete baimen hau duten aplikazioek"</string>
- <string name="permission_description_summary_location" msgid="2817531799933480694">"Gailu honen kokapena atzi dezakete baimen hau duten aplikazioek"</string>
+ <string name="permission_description_summary_location" msgid="2817531799933480694">"Gailu honen kokapena erabil dezakete baimen hau duten aplikazioek"</string>
<string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"Inguruko gailuak aurkitu, haietara konektatu, eta haien arteko distantzia erlatiboa zehatz dezakete baimen hau duten aplikazioek"</string>
<string name="permission_description_summary_microphone" msgid="630834800308329907">"Audioa graba dezakete baimen hau duten aplikazioek"</string>
<string name="permission_description_summary_phone" msgid="4515277217435233619">"Telefono-deiak egin eta kudea ditzakete baimen hau duten aplikazioek"</string>
@@ -251,7 +253,7 @@
<string name="allowed_storage_scoped" msgid="5383645873719086975">"Multimedia-fitx. soilik erabiltzeko baimena dutenak"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"Fitxategi guztiak kudeatzeko baimena dutenak"</string>
<string name="ask_header" msgid="2633816846459944376">"Galdetu beti"</string>
- <string name="denied_header" msgid="903209608358177654">"Baimendu gabe"</string>
+ <string name="denied_header" msgid="903209608358177654">"Baimendu gabekoak"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Ikusi fitxategi guztiak atzi ditzaketen aplikazio gehiago"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 egun}other{# egun}}"</string>
<string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ordu}other{# ordu}}"</string>
@@ -381,7 +383,7 @@
<string name="role_home_search_keywords" msgid="3830755001192666285">"abiarazlea"</string>
<string name="role_call_redirection_label" msgid="5785304207206147590">"Deiak desbideratzeko aplikazio lehenetsia"</string>
<string name="role_call_redirection_short_label" msgid="7568143419571217757">"Deiak birbideratzeko aplikazioa"</string>
- <string name="role_call_redirection_description" msgid="6091669882014664420">"Egiten dituzun deiak beste telefono-zenbaki batera desbideratzeko aukera ematen dizuten aplikazioak"</string>
+ <string name="role_call_redirection_description" msgid="6091669882014664420">"Irteerako deiak beste telefono-zenbaki batera desbideratzeko aukera ematen dizuten aplikazioak"</string>
<string name="role_call_redirection_request_title" msgid="2816244455003562925">"<xliff:g id="APP_NAME">%1$s</xliff:g> ezarri nahi duzu deiak birbideratzeko aplikazio lehenetsi gisa?"</string>
<string name="role_call_redirection_request_description" msgid="3118895714178527164">"Ez du behar baimenik"</string>
<string name="role_call_screening_label" msgid="883935222060878724">"Deitzailearen id. eta spam-aplikazio lehenetsia"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Oharren aplikazioa"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Gailuan oharrak idazteko aukera ematen dizuten aplikazioak"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"oharrak"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Aplikazio lehenetsia"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ez galdetu berriro"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Ezarri lehenetsi gisa"</string>
@@ -443,7 +455,7 @@
<string name="incident_report_notification_text" msgid="3376480583513587923">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak arazketa-informazioa kargatu nahi du."</string>
<string name="incident_report_dialog_title" msgid="669104389325204095">"Arazketa-datuak partekatu nahi dituzu?"</string>
<string name="incident_report_dialog_intro" msgid="5897733669850951832">"Arazo bat hauteman du sistemak."</string>
- <string name="incident_report_dialog_text" msgid="5675553296891757523">"<xliff:g id="DATE">%2$s</xliff:g> (<xliff:g id="TIME">%3$s</xliff:g>) datan sortutako akatsen txostena kargatzeko baimena eskatzen ari da <xliff:g id="APP_NAME_0">%1$s</xliff:g>. Akatsen txostenek zure gailuari buruzkoa den edo aplikazioek erregistratu duten informazio pertsonala dute; adibidez, erabiltzaile-izenak, kokapenari buruzko datuak, gailuaren identifikatzaileak eta sareari buruzko informazioa. Informazio hori izateko fidagarriak iruditzen zaizkizun pertsona eta aplikazioekin soilik partekatu beharko zenituzke akatsen txostenak. <xliff:g id="APP_NAME_1">%4$s</xliff:g> aplikazioari akatsen txostena kargatzeko baimena eman nahi diozu?"</string>
+ <string name="incident_report_dialog_text" msgid="5675553296891757523">"<xliff:g id="DATE">%2$s</xliff:g> (<xliff:g id="TIME">%3$s</xliff:g>) datan sortutako akatsen txostena kargatzeko baimena eskatzen ari da <xliff:g id="APP_NAME_0">%1$s</xliff:g>. Akatsen txostenek zure gailuari buruzkoa den edo aplikazioek erregistratu duten informazio pertsonala dute; adibidez, erabiltzaile-izenak, kokapenari buruzko datuak, gailu-identifikatzaileak eta sareari buruzko informazioa. Informazio hori izateko fidagarriak iruditzen zaizkizun pertsona eta aplikazioekin soilik partekatu beharko zenituzke akatsen txostenak. <xliff:g id="APP_NAME_1">%4$s</xliff:g> aplikazioari akatsen txostena kargatzeko baimena eman nahi diozu?"</string>
<string name="incident_report_error_dialog_text" msgid="4189647113387092272">"Errore bat gertatu da <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren akatsen txostena prozesatzean; beraz, ezin izan dira partekatu arazketa-datu xehatuak. Barkatu eragozpenak."</string>
<string name="incident_report_dialog_allow_label" msgid="2970242967721155239">"Eman baimena"</string>
<string name="incident_report_dialog_deny_label" msgid="3535314290677579383">"Ukatu"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Erakutsi laguntzailea abiarazteko hautematea"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mikrofonoa erabiltzen denean ahozko laguntza aktibatzeko, erakutsi dagokion ikonoa egoera-barran"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Gailuko argazkiak eta multimedia-edukia erabiltzeko baimena eman nahi diozu &lt;b&amp;gt<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko argazkiak eta multimedia-edukia erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Kontaktuak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko kontaktuak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Gailuaren kokapena erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt; gailuaren kokapena erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Hura erabiltzen ari zarenean soilik atzituko du aplikazioak kokapena"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Gailuaren kokapena erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren kokapena erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Baliteke aplikazioak beti atzitu behar izatea zure kokapena, baita aplikazioa erabiltzen ari ez zarenean ere. "<annotation id="link">"Eman baimen hori Ezarpenak atalean"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Kokapenerako sarbidea aldatu nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuaren kokapena erabiltzeko baimena aldatu nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Aplikazioak beti atzitu nahi du zure kokapena, baita aplikazioa erabiltzen ari ez zarenean ere. "<annotation id="link">"Eman baimen hori Ezarpenak atalean"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Inguruko gailuak aurkitu, haietara konektatu eta haien arteko distantzia erlatiboa zehazteko baimena eman &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuan inguruko gailuak aurkitu, haietara konektatu eta haien distantzia erlatiboa zehazteko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Inguruko gailuak aurkitzeko, haietara konektatzeko eta haien arteko distantzia erlatiboa zehazteko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&amp;gt aplikazioari? "<annotation id="link">"Eman baimena ezarpenetan."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> aplikazioak gutxi gorabeherako kokapena atzi dezake. Kokapen zehatza erabiltzeko baimena eman nahi diozu?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> aplikazioak &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuaren gutxi gorabeherako kokapena erabil dezake. Kokapen zehatza erabiltzeko baimena eman nahi diozu?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Gailuaren gutxi gorabeherako kokapena erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuaren gutxi gorabeherako kokapena erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Zehatza"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Gutxi gorabeherakoa"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Egutegia erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko egutegia erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"SMS mezuak bidaltzeko eta ikusteko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuan SMSak bidaltzeko eta ikusteko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Gailuko argazkiak, multimedia-edukia eta fitxategiak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko argazkiak, multimedia-edukia eta fitxategiak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Gailuko &lt;b&gt;argazkiak, bideoak, musika eta audioa&lt;/b&gt; erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Gailuko &lt;b&gt;argazkiak, bideoak, musika, audioa eta bestelako fitxategiak&lt;/b&gt; erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Gailuko musika eta audioa erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko musika eta audioa erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Gailuko argazkiak eta bideoak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko argazki eta bideoak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Gailuko argazki eta bideo gehiago erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko argazki eta bideo gehiago erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Audioa grabatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuan audioa grabatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikazioak hura erabiltzean soilik grabatuko du audioa"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Audioa grabatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuan audioa grabatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Baliteke aplikazioak edonoiz grabatzea audioa, baita aplikazioa erabiltzen ari ez zarenean ere. "<annotation id="link">"Eman baimena ezarpenetan."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Mikrofonorako sarbidea aldatu nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko mikrofonoa erabiltzeko baimena aldatu nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Aplikazioak edonoiz grabatu nahi du audioa, baita aplikazioa erabiltzen ari ez zarenean ere. "<annotation id="link">"Eman baimena ezarpenetan."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Zure jarduera fisikoa erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko jarduera fisikoak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Argazkiak ateratzeko eta bideoak grabatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuan argazkiak atera eta bideoak grabatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikazioak hura erabiltzean soilik aterako ditu argazkiak, eta grabatuko bideoak"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Argazkiak atera eta bideoak grabatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuan argazkiak atera eta bideoak grabatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Baliteke aplikazioak edonoiz ateratzea argazkiak eta grabatzea bideoak, baita aplikazioa erabiltzen ari ez zarenean ere. "<annotation id="link">"Eman baimena ezarpenetan."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Kamerarako sarbidea aldatu nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko kamera erabiltzeko baimena aldatu nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Aplikazioak edonoiz atera nahi ditu argazkiak eta grabatu bideoak, baita aplikazioa erabiltzen ari ez zarenean ere. "<annotation id="link">"Eman baimena ezarpenetan."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Telefonoko deien erregistroa erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko deien erregistroa erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Telefono-deiak egiteko eta kudeatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuan telefono-deiak egiteko eta kudeatzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Bizi-konstanteei buruzko sentsorearen datuak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko bizi-konstanteei buruzko sentsoreen datuak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Aplikazioak bizi-konstanteei buruzko sentsoreen datuak atzitu nahi ditu, baita aplikazioa erabiltzen ari ez zarenean ere. Aldaketa hori egiteko, "<annotation id="link">"joan ezarpenetara."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Bizi-konstanteei buruzko sentsoreen datuak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko bizi-konstanteei buruzko sentsoreen datuak erabiltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Aplikazioari gorputz-sentsoreen datuak beti erabiltzeko baimena emateko (baita aplikazioa erabiltzen ari ez zarenean ere), "<annotation id="link">"joan ezarpenetara."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erabili bitartean gorputz-sentsoreen datuak erabiltzeko baimena eman nahi diozu aplikazio horri?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; erabili bitartean &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailuko gorputz-sentsoreen datuak erabiltzeko baimena eman nahi diozu aplikazioari?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Jakinarazpenak bidaltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; gailura jakinarazpenak bidaltzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontrolatutako baimenak"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak kokapena erabil dezake"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Erakundeak kokapena erabiltzeko baimena eman dio <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioari"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Beste baimen batzuk"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Sistemak erabilitako baimenak"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Sistema-aplikazioek soilik erabilitako baimenak."</string>
@@ -589,12 +626,13 @@
<string name="show_password_title" msgid="2877269286984684659">"Erakutsi pasahitzak"</string>
<string name="show_password_summary" msgid="1110166488865981610">"Idatzi ahala, erakutsi karaktereak laburki"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Agian hirugarrenekin kokapen-datuak partekatuko dituela adierazi du aplikazioaren garatzaileak"</string>
- <string name="permission_rationale_location_title" msgid="2404797182678793506">"Datuak partekatzeko moduak eta kokapena"</string>
- <string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Nondik dator datuak partekatzeko moduei buruzko informazioa?"</string>
+ <string name="permission_rationale_location_title" msgid="2404797182678793506">"Datuak partekatzeko aukera eta kokapena"</string>
+ <string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Nondik dator datuak partekatzeko aukerari buruzko informazioa?"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Aplikazioak datuak partekatzeko dituen moduei buruzko informazioa eman dio gailuaren fabrikatzaileari garatzaileak. Baliteke garatzaileak informazio hori eguneratzea denboran zehar."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Aplikazioak datuak partekatzeko dituen moduei buruzko informazioa eman du "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" dendan garatzaileak. Baliteke garatzaileak informazio hori eguneratzea denboran zehar."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Baliteke hauetarako partekatzea kokapen-datuak:"</string>
- <string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datuak partekatzeko moduak aldatu egiten dira"</string>
- <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Litekeena da datuen inguruko jardunbideak aplikazioaren bertsioaren, erabileraren, lurraldearen eta adinaren araberakoak izatea. "<annotation id="link">"Datuak partekatzeko moduei buruzko informazio gehiago"</annotation></string>
+ <string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datuak partekatzeko aukerak aldatu egiten dira"</string>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Litekeena da datuen inguruko jardunbideak aplikazioaren bertsioaren, erabileraren, lurraldearen eta adinaren araberakoak izatea. "<annotation id="link">"Datuak partekatzeko aukerari buruzko informazio gehiago"</annotation></string>
<string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Litekeena da datuen inguruko jardunbideak aplikazioaren bertsioaren, erabileraren, lurraldearen eta adinaren araberakoak izatea."</string>
<string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Kokapen-datuak"</string>
<string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Aldatu aplikazioaren sarbidea "<annotation id="link">"pribatutasun-ezarpenetan"</annotation></string>
@@ -608,18 +646,19 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Datuen babesa"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Baliteke kokapen-datuak partekatzea"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Agian hirugarrenekin kokapen-datuak partekatuko dituela adierazi du aplikazioaren garatzaileak"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Ezin da ireki esteka"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
- <string name="data_sharing_updates_title" msgid="7996933386875213859">"Kokapen-datuak partekatzeko jardunbideen inguruko berritasunak"</string>
+ <string name="data_sharing_updates_title" msgid="7996933386875213859">"Kokapen-datuak partekatzeko aukeraren berritasunak"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Berrikusi kokapen-datuak partekatzeko modua aldatu duten aplikazioak"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Kokapen-datuak partekatzeko modua aldatu dute aplikazio hauek. Agian ez zuten daturik partekatzen lehen, edo baliteke orain publizitate- edo marketin-helburuetarako partekatzea."</string>
- <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Datuak partekatzeko jardunbideei buruzko informazioa eman dute aplikazio-denda batean aplikazio hauen garatzaileek. Baliteke denboran zehar informazio hori eguneratzea.\n\nLitekeena da datuak partekatzeko jardunbideak aplikazioaren bertsioaren, erabileraren, lurraldearen eta adinaren araberakoak izatea."</string>
- <string name="learn_about_data_sharing" msgid="4200480587079488045">"Datuak partekatzeko jardunbideei buruzko informazio gehiago"</string>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Datuak partekatzeko aukerari buruzko informazioa eman dute aplikazio-denda batean aplikazio hauen garatzaileek. Baliteke denboran zehar informazio hori eguneratzea.\n\nLitekeena da datuak partekatzeko aukera aplikazioaren bertsioaren, erabileraren, lurraldearen eta adinaren araberakoa izatea."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Datuak partekatzeko aukerari buruzko informazio gehiago"</string>
<string name="shares_location_with_third_parties" msgid="2278051743742057767">"Orain, kokapen-datuak hirugarrenekin partekatzen dira"</string>
<string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Orain, kokapen-datuak hirugarrenekin partekatzen dira publizitate- edo marketin-helburuetarako"</string>
<string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Atzo jaso ziren berritasunak}=1{Atzo jaso ziren berritasunak}other{Azken # egunetan jaso dira berritasunak}}"</string>
<string name="no_updates_at_this_time" msgid="9031085635689982935">"Une honetan, ez dago berritasunik"</string>
- <string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Datuak partekatzeko moduen inguruko berritasunak"</string>
+ <string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Datuak partekatzeko aukeraren berritasunak"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Kokapen-datuak partekatzeko modua aldatu dute aplikazio batzuek"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Ezarpenak"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Atzitze-data: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Atzo atzitu zen (<xliff:g id="TIME_DATE">%1$s</xliff:g>)"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Atzitze-data: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> (<xliff:g id="TIME_DATE_1">%2$s</xliff:g>)"</string>
</resources>
diff --git a/PermissionController/res/values-fa-v33/strings.xml b/PermissionController/res/values-fa-v33/strings.xml
index b46c08f50..6c7abf7c5 100644
--- a/PermissionController/res/values-fa-v33/strings.xml
+++ b/PermissionController/res/values-fa-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"هشدارهای بیشتر"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"هشدارهای ردشده"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{گسترده کردن و دیدن یک هشدار دیگر}one{گسترده کردن و دیدن # هشدار دیگر}other{گسترده کردن و دیدن # هشدار دیگر}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"هشدار. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"کنش کامل شد"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"بررسی کردن تنظیماتی که می‌تواند امنیت بیشتری به دستگاهتان اضافه کند"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"تنظیمات فوری امنیت و حریم خصوصی"</string>
diff --git a/PermissionController/res/values-fa/strings.xml b/PermissionController/res/values-fa/strings.xml
index 7be621a55..531b928ee 100644
--- a/PermissionController/res/values-fa/strings.xml
+++ b/PermissionController/res/values-fa/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="6098036489833144040">"کنترل‌کننده اجازه"</string>
<string name="ok" msgid="1936281769725676272">"تأیید"</string>
- <string name="permission_search_keyword" msgid="1214451577494730543">"مجوزها"</string>
+ <string name="permission_search_keyword" msgid="1214451577494730543">"اجازه‌ها"</string>
<string name="cancel" msgid="8943320028373963831">"لغو"</string>
<string name="back" msgid="6249950659061523680">"برگشت"</string>
<string name="available" msgid="6007778121920339498">"دردسترس"</string>
@@ -32,16 +32,17 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"تغییر ندادن اجازه «هنگامی که از برنامه استفاده می‌شود»"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"«فقط این بار» نگه داشته شود"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"اطلاعات بیشتر"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"همه مجازاند"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"مجاز بودن همه"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"همه موارد همیشه مجازاند"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"مجاز کردن دسترسی محدود"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"انتخاب عکس و ویدیو"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"انتخاب موارد بیشتر"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"موارد بیشتری انتخاب نشود"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"دیگر چیزی انتخاب نشود"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"درهرصورت اجازه نیست"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"رد کردن"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> مجوز از <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> مجوز"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه <xliff:g id="ACTION">%2$s</xliff:g> را می‌دهید؟"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"‏همیشه به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; برای <xliff:g id="ACTION">%2$s</xliff:g> اجازه داده شود؟"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; این اجازه داده شود؟ <xliff:g id="ACTION">%2$s</xliff:g>"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"‏همیشه به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; این اجازه داده شود؟ <xliff:g id="ACTION">%2$s</xliff:g>"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"فقط هنگام استفاده از برنامه"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"همیشه"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"اجازه نیست و دیگر پرسیده نشود"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"برنامه‌ها"</string>
<string name="app_permissions" msgid="3369917736607944781">"اجازه‌های برنامه"</string>
<string name="unused_apps" msgid="2058057455175955094">"برنامه‌های استفاده‌نشده"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ویرایش عکس‌های انتخاب‌شده برای این برنامه"</string>
<string name="no_unused_apps" msgid="12809387670415295">"برنامه استفاده‌نشده‌ای موجود نیست"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"برنامه استفاده‌نشده‌ای وجود ندارد"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"تصمیم‌های اخیر درباره اجازه‌ها"</string>
@@ -111,11 +113,9 @@
<string name="permission_access_only_foreground" msgid="7801170728159326195">"فقط هنگام استفاده از برنامه مجاز است"</string>
<string name="permission_access_never" msgid="4647014230217936900">"اجازه ندادن"</string>
<string name="loading" msgid="4789365003890741082">"درحال بارگیری…"</string>
- <string name="all_permissions" msgid="6911125611996872522">"همه مجوزها"</string>
+ <string name="all_permissions" msgid="6911125611996872522">"همه اجازه‌ها"</string>
<string name="other_permissions" msgid="2901186127193849594">"سایر قابلیت‌های برنامه"</string>
- <string name="permission_request_title" msgid="8790310151025020126">"درخواست مجوز"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"‏کنش‌های نصب/حذف نصب در Wear پشتیبانی نمی‌شود."</string>
+ <string name="permission_request_title" msgid="8790310151025020126">"درخواست اجازه"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"‏انتخاب کنید &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه دارد به چه چیزی دسترسی پیدا کند"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; به‌روزرسانی شده است. انتخاب کنید این برنامه اجازه دارد به چه چیزی دسترسی پیدا کند."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"لغو"</string>
@@ -143,7 +143,7 @@
<string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ساعت}one{# ساعت}other{# ساعت}}"</string>
<string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# دقیقه}one{# دقیقه}other{# دقیقه}}"</string>
<string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# ثانیه}one{# ثانیه}other{# ثانیه}}"</string>
- <string name="permission_usage_any_permission" msgid="6358023078298106997">"همه مجوزها"</string>
+ <string name="permission_usage_any_permission" msgid="6358023078298106997">"همه اجازه‌ها"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"هر زمانی"</string>
<string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{# روز گذشته}one{# روز گذشته}other{# روز گذشته}}"</string>
<string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# ساعت گذشته}one{# ساعت گذشته}other{# ساعت گذشته}}"</string>
@@ -158,9 +158,9 @@
<string name="permission_usage_bar_chart_title_any_time" msgid="2845251288192246754">"پراستفاده‌ترین مجوز در هرزمانی"</string>
<string name="permission_usage_bar_chart_title_last_7_days" msgid="5796577162176938349">"پراستفاده‌ترین مجوز در ۷ روز گذشته"</string>
<string name="permission_usage_bar_chart_title_last_day" msgid="7950805735777472871">"پراستفاده‌ترین مجوز در ۲۴ ساعت گذشته"</string>
- <string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"پراستفاده‌ترین مجوزها در ۱ ساعت گذشته"</string>
+ <string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"پراستفاده‌ترین اجازه‌ها در ۱ ساعت گذشته"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"پراستفاده‌ترین مجوزها در ۱۵ دقیقه گذشته"</string>
- <string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"پراستفاده‌ترین مجوزها در ۱ دقیقه گذشته"</string>
+ <string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"پراستفاده‌ترین اجازه‌ها در ۱ دقیقه گذشته"</string>
<string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{در # روز گذشته استفاده نشده است}one{در # روز گذشته استفاده نشده است}other{در # روز گذشته استفاده نشده است}}"</string>
<string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{در # ساعت گذشته استفاده نشده است}one{در # ساعت گذشته استفاده نشده است}other{در # ساعت گذشته استفاده نشده است}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{یک برنامه از آن استفاده کرده است}one{# برنامه از آن استفاده کرده است}other{# برنامه از آن استفاده کرده است}}"</string>
@@ -168,9 +168,9 @@
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"فیلترشده براساس: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_usage_remove_filter" msgid="2926157607436428207">"حذف فیلتر"</string>
<string name="filter_by_title" msgid="7300368602759958031">"فیلتر کردن براساس"</string>
- <string name="filter_by_permissions" msgid="7613462963111282568">"فیلتر کردن براساس مجوزها"</string>
+ <string name="filter_by_permissions" msgid="7613462963111282568">"فیلتر کردن براساس اجازه‌ها"</string>
<string name="filter_by_time" msgid="6667864816999691642">"فیلتر براساس زمان"</string>
- <string name="sort_spinner_most_permissions" msgid="1704349738096822836">"بیشترین مجوزها"</string>
+ <string name="sort_spinner_most_permissions" msgid="1704349738096822836">"بیشترین اجازه‌ها"</string>
<string name="sort_spinner_most_accesses" msgid="5283913004357220161">"بیشترین تعداد دسترسی"</string>
<string name="sort_spinner_recent" msgid="7513845273076525203">"اخیر"</string>
<string name="sort_by_app" msgid="4055799843051138087">"به‌ترتیب استفاده برنامه"</string>
@@ -203,8 +203,10 @@
<string name="unused_apps_category_title" msgid="2988455616845243901">"تنظیمات برنامه‌های استفاده‌نشده"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"اگر از برنامه استفاده نمی‌شود، اجازه‌ها برداشته شوند"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"برداشتن اجازه‌ها و آزاد کردن فضا"</string>
- <string name="unused_apps_label_v2" msgid="7058776770056517980">"مکث فعالیت برنامه درصورت عدم‌استفاده"</string>
+ <string name="unused_apps_label_v2" msgid="7058776770056517980">"مکث فعالیت‌ها در برنامه درصورت عدم‌استفاده"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"مدیریت برنامه درصورت عدم استفاده"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"اجازه‌ها برداشته می‌شود، فایل‌های موقت حذف می‌شود، و اعلان‌ها متوقف می‌شوند"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"برداشتن اجازه‌ها، حذف فایل‌های موقت، توقف اعلان‌ها، و بایگانی کردن برنامه"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"برای محافظت از داده‌هایتان، اگر طی چند ماه گذشته از این برنامه استفاده نشده باشد، اجازه‌های آن برداشته خواهد شد."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"برای محافظت از داده‌هایتان، اگر طی چند ماه گذشته از این برنامه استفاده نشده باشد، اجازه‌های زیر برداشته خواهد شد: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"برای محافظت از داده‌هایتان، اجازه‌ها از برنامه‌هایی که طی چند ماه گذشته استفاده نشده‌اند برداشته شده است."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"آخرین باری که باز شده: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"اگر مدیریت همه فایل‌ها را مجاز کنید، این برنامه می‌تواند به همه فایل‌های موجود در فضای ذخیره‌سازی استاندارد این دستگاه یا دستگاه‌های ذخیره‌سازی متصل دسترسی داشته باشد، آن‌ها را تغییر دهد، و حذف کند. این برنامه ممکن است بدون سؤال کردن از شما به فایل‌ها دسترسی پیدا کند."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"به این برنامه اجازه داده شود به فایل‌های موجود در این دستگاه یا دستگاه‌های ذخیره‌سازی متصل دسترسی داشته باشد، آن‌ها را تغییر دهد، و حذف کند؟ این برنامه ممکن است بدون سؤال کردن از شما به فایل‌ها دسترسی پیدا کند."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"برنامه‌هایی که این مجوز را داشته باشند مجاز هستند به: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"برنامه‌هایی که این اجازه را داشته باشند برای این هم مجازند: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"برنامه‌های دارای این اجازه می‌توانند به فعالیت فیزیکی‌تان مانند پیاده‌روی، دوچرخه‌سواری، رانندگی، قدم‌شماری، و غیره دسترسی داشته باشند"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"برنامه‌های دارای این اجازه می‌توانند به تقویمتان دسترسی داشته باشند"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"برنامه‌هایی که این مجوز را داشته باشند می‌توانند گزارش تماس تلقنی را بخوانند و بنویسند"</string>
@@ -246,12 +248,12 @@
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"هرگز دسترسی نداشته است"</string>
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"غیرمجاز / هرگز دسترسی نداشته است"</string>
<string name="allowed_header" msgid="7769277978004790414">"مجاز است"</string>
- <string name="allowed_always_header" msgid="6455903312589013545">"همیشه مجاز است"</string>
- <string name="allowed_foreground_header" msgid="6845655788447833353">"مجاز فقط هنگام استفاده از برنامه"</string>
+ <string name="allowed_always_header" msgid="6455903312589013545">"همیشه مجاز بودن"</string>
+ <string name="allowed_foreground_header" msgid="6845655788447833353">"مجاز فقط هنگام استفاده"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"مجاز فقط برای دسترسی به رسانه‌ها"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"مجاز برای مدیریت همه فایل‌ها"</string>
<string name="ask_header" msgid="2633816846459944376">"هربار پرسیده شود"</string>
- <string name="denied_header" msgid="903209608358177654">"اجازه ندادن"</string>
+ <string name="denied_header" msgid="903209608358177654">"مجاز نبودن"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"دیدن برنامه‌های دیگری که به همه فایل‌ها دسترسی دارند"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{یک روز}one{# روز}other{# روز}}"</string>
<string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ساعت}one{# ساعت}other{# ساعت}}"</string>
@@ -314,7 +316,7 @@
<string name="permission_subtitle_only_in_foreground" msgid="9068389431267377564">"تنها هنگام استفاده از برنامه"</string>
<string name="permission_subtitle_media_only" msgid="8917869683764720717">"رسانه"</string>
<string name="permission_subtitle_all_files" msgid="4982613338298067862">"همه فایل‌ها"</string>
- <string name="permission_subtitle_background" msgid="8916750995309083180">"همیشه مجاز است"</string>
+ <string name="permission_subtitle_background" msgid="8916750995309083180">"همیشه مجاز بودن"</string>
<string name="app_perms_24h_access" msgid="99069906850627181">"آخرین زمان دسترسی: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_perms_24h_access_yest" msgid="5411926024794555022">"آخرین زمان دسترسی دیروز ساعت <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_perms_7d_access" msgid="4945055548894683751">"آخرین دسترسی: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> ساعت <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
@@ -401,12 +403,22 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"برنامه یادداشت‌ها"</string>
<string name="role_notes_description" msgid="8496852798616883551">"برنامه‌هایی که به شما اجازه می‌دهند در دستگاهتان یادداشت‌برداری کنید"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"یادداشت"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"برنامه پیش‌فرض کنونی"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"دوباره سؤال نشود"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"تنظیم برای پیش‌فرض"</string>
<string name="phone_call_uses_microphone" msgid="233569591461187177">"‏در &lt;b&gt;تماس تلفنی&lt;/b&gt; از میکروفون استفاده می‌شود"</string>
- <string name="phone_call_uses_microphone_and_camera" msgid="6291898755681748189">"‏در &lt;b&gt;تماس ویدیویی&lt;/b&gt; از دوربین و میکروفون استفاده می‌شود"</string>
- <string name="phone_call_uses_camera" msgid="2048417022147857418">"‏در &lt;b&gt;تماس ویدیویی&lt;/b&gt; از دوربین استفاده می‌شود"</string>
+ <string name="phone_call_uses_microphone_and_camera" msgid="6291898755681748189">"‏در &lt;b&gt;تماس تصویری&lt;/b&gt; از دوربین و میکروفون استفاده می‌شود"</string>
+ <string name="phone_call_uses_camera" msgid="2048417022147857418">"‏در &lt;b&gt;تماس تصویری&lt;/b&gt; از دوربین استفاده می‌شود"</string>
<string name="system_uses_microphone" msgid="576672130318877143">"سرویس سیستم به میکروفون دسترسی دارد"</string>
<string name="system_uses_microphone_and_camera" msgid="5124478304275138804">"سرویس سیستم به دوربین و میکروفون دسترسی دارد"</string>
<string name="system_uses_camera" msgid="1911223105234441470">"سرویس سیستم به دوربین دسترسی دارد"</string>
@@ -450,58 +462,83 @@
<string name="adjust_user_sensitive_title" msgid="4196724451314280527">"تنظیمات پیشرفته"</string>
<string name="menu_adjust_user_sensitive" msgid="6497923610654425780">"تنظیمات پیشرفته"</string>
<string name="adjust_user_sensitive_globally_title" msgid="8649190949066029174">"نمایش استفادهٔ برنامه سیستم"</string>
- <string name="adjust_user_sensitive_globally_summary" msgid="129467818433773912">"نمایش استفاده برنامه سیستم از مجوزها در نوار وضعیت، داشبورد، و جاهای دیگر"</string>
+ <string name="adjust_user_sensitive_globally_summary" msgid="129467818433773912">"نمایش استفاده برنامه سیستم از اجازه‌ها در نوار وضعیت، داشبورد، و جاهای دیگر"</string>
<string name="adjust_user_sensitive_per_app_header" msgid="4543506440989005648">"برجسته کردن استفاده برای موارد زیر"</string>
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"نمایش دستیار تشخیص راه‌انداز"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"نمایش نماد مربوطه در نوار وضعیت وقتی از میکروفون برای فعال کردن دستیار صوتی استفاده می‌شود"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; اجازه داده شود به عکس‌ها و رسانه‌های موجود در دستگاهتان دسترسی پیدا کند؟"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به عکس‌ها و رسانه‌های &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به مخاطبینتان در &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"‏به &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>’s&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"‏به &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> دسترسی داشته باشد؟"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"این برنامه ممکن است بخواهد مرتب به مکانتان دسترسی داشته باشد، حتی زمانی‌که از برنامه استفاده نمی‌کنید. "<annotation id="link">"در تنظیمات به آن اجازه دهید."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"‏دسترسی به مکان برای &lt;b&amp;gt؛<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&amp;gt تغییر کند؟"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"‏دسترسی &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; به مکان در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; تغییر کند؟"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"این برنامه می‌خواهد مرتب به مکانتان دسترسی داشته باشد، حتی زمانی‌که از برنامه استفاده نمی‌کنید. "<annotation id="link">"در تنظیمات به آن اجازه دهید."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود دستگاه‌های اطراف را پیدا کند، به آن‌ها متصل شود، و موقعیت نسبی آن‌ها را مشخص کند؟"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; دستگاه‌های اطراف را پیدا کند، به آن‌ها متصل شود، و موقعیت نسبی آن‌ها را تعیین کند؟"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود دستگاه‌های اطراف را پیدا کند، به آن‌ها متصل شود، و موقعیت نسبی آن‌ها را مشخص کند؟ "<annotation id="link">"در تنظیمات اجازه دهید."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"دسترسی <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> به مکان از حالت تقریبی به دقیق تغییر کند؟"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"‏دسترسی <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> به مکان &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; از تقریبی به دقیق تغییر کند؟"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"‏به &lt;b&amp;gt؛<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&amp;gt؛ اجازه داده شود به مکان تقریبی این دستگاه دسترسی پیدا کند؟"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به مکان تقریبی &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به تقویمتان در &lt;b&gt;<xliff:g id="DEVICE">%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;» اجازه داده شود پیامک ارسال و مشاهده کند؟"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به عکس‌ها، رسانه‌ها، و فایل‌های &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه می‌دهید به &lt;b&gt;عکس‌ها، ویدیوها، موسیقی، و فایل‌های صوتی&lt;/b&gt; این دستگاه دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه می‌دهید به &lt;b&gt;عکس‌ها، ویدیوها، موسیقی، صوت، و فایل‌های دیگر&lt;/b&gt; این دستگاه دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه می‌دهید به فایل‌های موسیقی و صوتی در این دستگاه دسترسی داشته باشد؟"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; به فایل‌های موسیقی و صوتی دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه می‌دهید به عکس‌ها و ویدیوهای این دستگاه دسترسی داشته باشد؟"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به عکس‌ها و ویدیوهای &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه می‌دهید به عکس‌ها و ویدیوهای بیشتری در این دستگاه دسترسی داشته باشد؟"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به عکس‌ها و ویدیوهای بیشتری در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"‏به &lt;/b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود صدا ضبط کند؟"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; صدا ضبط کند؟"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"این برنامه فقط وقتی از آن استفاده می‌کنید، می‌تواند صدا ضبط کند"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"‏به &lt;/b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود صدا ضبط کند؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; صدا ضبط کند؟"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"این برنامه ممکن است بخواهد مرتب صدا ضبط کند، حتی زمانی‌که از برنامه استفاده نمی‌کنید. "<annotation id="link">"در تنظیمات به آن اجازه دهید."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"‏دسترسی به میکروفون برای &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; تغییر کند؟"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"‏دسترسی &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; به میکروفون در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; تغییر کند؟"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"این برنامه می‌خواهد مرتب صدا ضبط کند، حتی زمانی‌که از برنامه استفاده نمی‌کنید. "<annotation id="link">"در تنظیمات به آن اجازه دهید."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه می‌دهید به فعالیت فیزیکی‌تان دسترسی پیدا کند؟"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به فعالیت فیزیکی‌تان در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود عکس بگیرد و ویدیو ضبط کند؟"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; t اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; عکس بگیرد و ویدیو ضبط کند؟"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"این برنامه فقط وقتی از آن استفاده می‌کنید، می‌تواند عکس و فیلم بگیرد"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود عکس بگیرد و ویدیو ضبط کند؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; t اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; عکس بگیرد و ویدیو ضبط کند؟"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"این برنامه ممکن است بخواهد مرتب عکس و فیلم بگیرد، حتی زمانی‌که از برنامه استفاده نمی‌کنید. "<annotation id="link">"در تنظیمات به آن اجازه دهید."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"‏دسترسی به دوربین برای &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; تغییر کند؟"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"‏دسترسی &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; به دوربین در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; تغییر کند؟"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"این برنامه می‌خواهد مرتب عکس و فیلم بگیرد، حتی زمانی‌که از برنامه استفاده نمی‌کنید. "<annotation id="link">"در تنظیمات به آن اجازه دهید."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به گزارش تماس‌های تلفنی شما دسترسی داشته باشد؟"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به گزارش‌های تماس تلفنتان در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; اجازه داده شود تماس‌های تلفنی برقرار کند و آن‌ها را مدیریت کند؟"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; تماس‌های تلفنی برقرار کند و آن‌ها را مدیریت کند؟"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; اجازه داده شود به داده‌های حسگر مربوط به علائم حیاتی شما دسترسی پیدا کند؟"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به داده‌های علائم حیاتی‌تان از حسگر &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; دسترسی داشته باشد؟"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"این برنامه می‌خواهد به داده‌های حسگر از علائم حیاتی شما همیشه دسترسی داشته باشد، حتی زمانی که از برنامه استفاده نمی‌کنید. برای انجام این تغییر، "<annotation id="link">"به تنظیمات بروید."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه می‌دهید به داده‌های علائم حیاتی‌تان از حسگر دسترسی داشته باشد؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود به داده‌های علائم حیاتی‌تان از حسگر &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; دسترسی داشته باشد؟"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"برای اینکه این برنامه بتواند همیشه و حتی زمانی که از برنامه استفاده نمی‌کنید به داده‌های حسگر بدن دسترسی داشته باشد، "<annotation id="link">"به تنظیمات بروید."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; همچنان اجازه داده شود درحین استفاده، به داده‌های حسگر بدن دسترسی داشته باشد؟"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; همچنان اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; به داده‌های حسگر بدن، درحین استفاده از برنامه، دسترسی داشته باشد؟"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود اعلان ارسال کند؟"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"‏به &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اجازه داده شود در &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; اعلان ارسال کند؟"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"مجوزهای کنترل‌شده"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> به مکان دسترسی دارد"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"سازمان شما به <xliff:g id="APP_NAME">%1$s</xliff:g> اجازه داده است به مکانتان دسترسی داشته باشد"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"اجازه‌های دیگر"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"اجازه‌هایی که سیستم استفاده می‌کند"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"اجازه‌هایی که فقط برنامه‌های سیستم استفاده می‌کنند."</string>
@@ -526,12 +563,12 @@
<string name="safety_center_rescan_button" msgid="4517514567809409596">"اسکن کردن دستگاه"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"رد کردن"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"این هشدار رد شود؟"</string>
- <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"هرزمان خواستید تنظیمات امنیت و حریم خصوصی را مرور کنید تا محافظت بیشتری اضافه کنید"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"هرزمان خواستید تنظیمات ایمنی و حریم خصوصی را مرور کنید تا محافظت بیشتری اضافه کنید"</string>
<string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"رد شدن"</string>
<string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"لغو"</string>
<string name="safety_center_entries_category_title" msgid="34356964062813115">"تنظیمات"</string>
<string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"وضعیت حریم خصوصی و امنیت. <xliff:g id="OVERALL_SAFETY_STATUS">%1$s</xliff:g>. <xliff:g id="SUMMARY_OF_DEVICE_STATUS">%2$s</xliff:g>"</string>
- <string name="security_settings" msgid="3808106921175271317">"تنظیمات امنیتی"</string>
+ <string name="security_settings" msgid="3808106921175271317">"تنظیمات ایمنی"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"اجازه‌ها"</string>
<string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"امنیت و حریم خصوصی"</string>
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"بررسی وضعیت"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"این برنامه اعلام کرده است که ممکن است داده‌های مکان را با اشخاص ثالث هم‌رسانی کند"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"هم‌رسانی داده‌ها و مکان"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"اطلاعات هم‌رسانی داده از کجا می‌آید"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"توسعه‌دهنده اطلاعاتی درباره نحوه هم‌رسانی داده‌ها توسط این برنامه به سازنده این دستگاه ارائه کرده است. ممکن است توسعه‌دهنده این اطلاعات را به‌مرور زمان به‌روز کند."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"‏توسعه‌دهنده در "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" اطلاعاتی درباره نحوه هم‌رسانی داده‌ها توسط این برنامه ارائه کرده است. ممکن است توسعه‌دهنده این اطلاعات را به‌مرور زمان به‌روز کند."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"برنامه شاید داده‌های مکان را به این دلایل هم‌رسانی کند:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"روش‌های هم‌رسانی داده متفاوت است"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ایمنی داده"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"داده‌های مکان ممکن است هم‌رسانی شود"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"این برنامه اعلام کرده که ممکن است داده‌های مکانتان را با اشخاص ثالث هم‌رسانی کند"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"این پیوند باز نشد"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"به‌روزرسانی‌های هم‌رسانی داده برای مکان"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"برنامه‌هایی که روش هم‌رسانی داده‌های مکان شما را تغییر داده‌اند مرور کنید"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"این برنامه‌ها روش هم‌رسانی داده‌های مکان شما را تغییر داده‌اند. شاید قبلاً آن را هم‌رسانی نکرده باشند، یا شاید اکنون آن را برای اهداف تبلیغاتی یا بازاریابی هم‌رسانی کنند."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"به‌روزرسانی‌های هم‌رسانی داده"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"برخی‌از برنامه‌ها روش هم‌رسانی داده‌های مکان شما را تغییر داده‌اند"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"تنظیمات"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"تاریخ دسترسی: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"دسترسی در روز گذشته ساعت <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"دسترسی در <xliff:g id="TIME_DATE_0">%1$s</xliff:g> ساعت <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-fi-v33/strings.xml b/PermissionController/res/values-fi-v33/strings.xml
index 32e3cabe8..9b57c6172 100644
--- a/PermissionController/res/values-fi-v33/strings.xml
+++ b/PermissionController/res/values-fi-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Lisää ilmoituksia"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Hylätyt hälytykset"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Laajenna ja katso yksi muu ilmoitus}other{Laajenna ja katso # muuta ilmoitusta}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Hälytys. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Toiminto suoritettu"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Tarkista asetukset, jotka voivat parantaa laitteesi turvallisuutta"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Tietosuojan ja yksityisyyden pika-asetukset"</string>
diff --git a/PermissionController/res/values-fi-v34/strings.xml b/PermissionController/res/values-fi-v34/strings.xml
index bd264d879..b2f95dc19 100644
--- a/PermissionController/res/values-fi-v34/strings.xml
+++ b/PermissionController/res/values-fi-v34/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="security_privacy_brand_name" msgid="7303621734258440812">"Tietoturva ja yksityisyys"</string>
+ <string name="security_privacy_brand_name" msgid="7303621734258440812">"Turvallisuus ja yksityisyys"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Asetukset"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
<string name="health_connect_summary" msgid="815473513776882296">"Päätä sovellusten pääsystä terveysdataan"</string>
diff --git a/PermissionController/res/values-fi/strings.xml b/PermissionController/res/values-fi/strings.xml
index 6bfe39862..5a8cecf59 100644
--- a/PermissionController/res/values-fi/strings.xml
+++ b/PermissionController/res/values-fi/strings.xml
@@ -34,13 +34,14 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Lisätietoja"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Salli kaikki"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Salli aina kaikki"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Salli rajoitettu pääsy"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Valitse kuvia ja videoita"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Valitse lisää"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Älä valitse enempää"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Älä salli silti"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Ohita"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Sallitaanko toiminto <xliff:g id="ACTION">%2$s</xliff:g> sovellukselle &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aina <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="permission_add_background_warning_template" msgid="1812914855915092273">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aina <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Vain sovelluksen käytön aikana"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Aina"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Sovell."</string>
<string name="app_permissions" msgid="3369917736607944781">"Sovellusluvat"</string>
<string name="unused_apps" msgid="2058057455175955094">"Käyttämättömät sovellukset"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Muuta sovelluksen kuvavalintaa"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Ei käyttämättömiä sovelluksia"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 käyttämätöntä sovellusta"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Viimeaikaiset lupapäätökset"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Salli aina"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Salli vain, kun sov. on käyt."</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Salli vain, kun sovellus käytössä"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Älä salli"</string>
<string name="loading" msgid="4789365003890741082">"Ladataan…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Kaikki luvat"</string>
<string name="other_permissions" msgid="2901186127193849594">"Muut sovellusluvat"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Lupapyyntö"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear ei tue asennus- ja poistotoimintoja."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Valitse, mitä käyttöoikeuksia sovellukselle &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; myönnetään."</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on päivitetty. Valitse, mitä käyttöoikeuksia tälle sovellukselle myönnetään."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Peru"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Poista luvat, jos sovellusta ei käytetä"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Poista lupia ja vapauta tilaa"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Keskeytä sovellustoim. jos ei käytössä"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Hallinnoi sovellusta, jos käyttämätön"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Poista käyttämättömät luvat ja väliaikaiset tiedostot ja pysäytä ilmoitukset"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Poista käyttämättömät luvat ja väliaikaiset tiedostot, pysäytä ilmoitukset ja arkistoi sovellus"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Datasi suojaamiseksi tämän sovelluksen luvat poistetaan, jos sovellusta ei käytetä muutamaan kuukauteen."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Jos sovellusta ei käytetä muutamaan kuukauteen, seuraavat luvat poistetaan datasi suojaamiseksi: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Datasi suojaamiseksi luvat on poistettu sovelluksilta, joita et ole käyttänyt muutamaan kuukauteen."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Muistiinpanosovellus"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Sovellukset, joilla voit ottaa muistiinpanoja laitteellasi"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"muistiinpanot"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Nykyinen oletus"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Älä kysy uudelleen"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Aseta oletukseksi"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Näytä avustajan käynnistyskomennon havaitseminen"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Näytä tilarivillä kuvake, kun ääniapuri aktivoidaan mikrofonin avulla."</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; käyttää laitteellasi olevia kuvia ja mediaa?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyviin kuviin ja mediaan?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; yhteystietojesi käyttöoikeuden?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyviin yhteystietoihin?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn tämän laitteen sijaintiin?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteen (&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt;) sijaintiin?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Sovellus saa sijainnin käyttöoikeuden vain silloin, kun käytät sovellusta"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn tämän laitteen sijaintiin?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteen (&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) sijaintiin?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Sovellus voi haluta nähdä sijaintisi aina, myös silloin kun et käytä sitä. "<annotation id="link">"Myönnä lupa asetuksista"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Muutetaanko sijainnin käyttöoikeutta (&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;)?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Muutetaanko sijainnin pääsyoikeuksia (&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;) laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Sovellus haluaa nähdä sijaintisi aina, myös silloin kun et käytä sitä. "<annotation id="link">"Myönnä lupa asetuksista"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; löytää lähellä olevia laitteita, yhdistää niihin ja määrittää niiden suhteellisen sijainnin?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; löytää laitteita lähellä (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;), yhdistää ja määrittää suhteellisen sijainnin?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; löytää lähellä olevia laitteita, yhdistää niihin ja määrittää niiden suhteellisen sijainnin? "<annotation id="link">"Myönnä lupa asetuksista."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Muutetaanko sijainnin käyttöoikeus (<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>) likimääräisestä tarkaksi?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Muutetaanko sijainnin pääsyoikeudet (<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>) laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) likimääräisistä tarkoiksi?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn tämän laitteen karkeaan sijaintiin?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteen (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) likimääräiseen sijaintiin?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Tarkka"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Likimääräinen"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn kalenteriisi?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteen (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) kalenteriin?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lähettää ja lukea tekstiviestejä?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lähettää ja lukea tekstiviestejä laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; käyttää laitteellasi olevia kuvia, mediaa ja tiedostoja?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyviin kuviin, mediaan ja tiedostoihin?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteen &lt;b&gt;kuviin, videoihin, musiikkiin ja audioon&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn &lt;b&gt;kuviin, videoihin, musiikkiin, audioon ja muihin tiedostoihin&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn tällä laitteella oleviin musiikki- ja audiotiedostoihin?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyvään musiikkiin ja audioon?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteella oleviin kuviin ja mediaan?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyviin kuviin ja videoihin?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn useampiin laitteella oleviin kuviin ja mediaan?"</string>
- <string name="permgrouprequest_microphone" msgid="2825208549114811299">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nauhoittaa audiota?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn useampiin laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyviin kuviin ja videoihin?"</string>
+ <string name="permgrouprequest_microphone" msgid="2825208549114811299">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tallentaa audiota?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tallentaa audiota laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Sovellus voi tallentaa audiota vain silloin, kun käytät sitä"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tallentaa audiota?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tallentaa audiota laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Sovellus voi haluta tallentaa audiota aina, myös silloin kun et käytä sitä. "<annotation id="link">"Myönnä lupa asetuksista"</annotation>"."</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Muutetaanko mikrofonin käyttöoikeutta (&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;)?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Muutetaanko mikrofonin pääsyoikeuksia (&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;) laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Sovellus haluaa tallentaa audiota aina, myös silloin kun et käytä sitä. "<annotation id="link">"Myönnä lupa asetuksista"</annotation>"."</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nähdä liikkumistietosi?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyviin fyysisen aktiivisuuden tietoihin?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ottaa kuvia ja nauhoittaa videoita?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ottaa kuvia ja kuvata videoita laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Sovellus voi ottaa kuvia ja videoita vain silloin, kun käytät sitä"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ottaa kuvia ja videoita?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ottaa kuvia ja kuvata videoita laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Sovellus voi haluta ottaa kuvia ja videoita aina, myös silloin kun et käytä sitä. "<annotation id="link">"Myönnä lupa asetuksista"</annotation>"."</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Muutetaanko kameran käyttöoikeutta (&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;)?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Muutetaanko kameran pääsyoikeuksia (&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;) laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Sovellus haluaa ottaa kuvia ja videoita aina, myös silloin kun et käytä sitä. "<annotation id="link">"Myönnä lupa asetuksista"</annotation>"."</string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; puhelulokien käyttöoikeuden?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyviin puhelulokeihin?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; soittaa ja hallinnoida puheluita?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Saako <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> soittaa ja hallinnoida puheluita laitteella (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?)?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; käyttää anturitietoja elintoiminnoistasi?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Voiko &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; saada pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyvään elintoimintojen anturidataan?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Sovellus haluaa pääsyn elintoimintojasi koskevaan anturidataan aina, myös silloin, kun et käytä sovellusta. Voit myöntää luvan "<annotation id="link">"asetuksista"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; käyttää anturidataa elintoiminnoistasi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pääsyn laitteelta (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) löytyvään elintoimintojen anturidataan?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Jos haluat myöntää sovellukselle pääsyn kehoanturidataan aina, myös silloin, kun et käytä sovellusta, "<annotation id="link">"siirry asetuksiin."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Haluatko edelleen sallia pääsyn kehoanturidataan, kun &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on käytössä?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Haluatko edelleen sallia pääsyn laitteen (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) kehoanturidataan, kun &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; on käytössä?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lähettää sinulle ilmoituksia?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Saako &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lähettää ilmoituksia laitteelle (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Automaattisesti myönnetyt käyttöoikeudet"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Sovelluksella (<xliff:g id="APP_NAME">%1$s</xliff:g>) on pääsy sijaintiin"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Organisaatiosi sallii sovelluksen (<xliff:g id="APP_NAME">%1$s</xliff:g>) pääsyn sijaintiin"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Muut luvat"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Järjestelmän käyttämät luvat"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Vain järjestelmäsovellusten käyttämät luvat"</string>
@@ -522,7 +559,7 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Sovellusten ja palvelujen osalta"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofonidataa saatetaan silti jakaa, kun soitat hätänumeroon."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Muuta"</string>
- <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Tietoturva ja yksityisyys"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Turvallisuus ja yksityisyys"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"Tarkista laite"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Ohita"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Ohitetaanko tämä hälytys?"</string>
@@ -533,7 +570,7 @@
<string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Tietoturvan ja yksityisyyden tila. <xliff:g id="OVERALL_SAFETY_STATUS">%1$s</xliff:g>. <xliff:g id="SUMMARY_OF_DEVICE_STATUS">%2$s</xliff:g>"</string>
<string name="security_settings" msgid="3808106921175271317">"Turvallisuusasetukset"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"Luvat"</string>
- <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Tietoturva ja yksityisyys"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Turvallisuus ja yksityisyys"</string>
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Tarkista tila"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Yksityisyysasetukset"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Lisää asetuksia"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Sovellus on ilmoittanut, että se saattaa jakaa sijaintitietoja kolmansille osapuolille"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Datan jakaminen ja sijainti"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Mistä datan jakotiedot tulevat"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Kehittäjä on antanut laitteen valmistajalle tietoja tavoista, joilla sovellus jakaa dataa. Kehittäjä voi päivittää tietoja ajan mittaan."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883"><annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" sisältää kehittäjän lisäämiä tietoja tavoista, joilla sovellus jakaa dataa. Kehittäjä voi päivittää tietoja ajan mittaan."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Sijaintitietoja voidaan jakaa näihin tarkoituksiin"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datan jakaminen vaihtelee"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Dataturvallisuus"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Sijaintitietoja voidaan jakaa"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Sovellus on ilmoittanut, että se saattaa jakaa sijaintitietoja kolmansille osapuolille"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Linkki ei avaudu"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Sijaintidatan jakamisen päivitykset"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Tarkista sovellukset, jotka ovat muuttaneet tapaa, jolla ne voivat jakaa sijaintitietoja"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Nämä sovellukset ovat muuttaneet tapaa, jolla ne voivat jakaa sijaintitietoja. Ne eivät ehkä ole jakaneet niitä aiemmin tai ne saattavat nyt jakaa niitä mainonta- tai markkinointitarkoituksiin."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Datan jaon päivitykset"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Jotkin sovellukset ovat muuttaneet tapaa, jolla ne voivat jakaa sijaintitietoja"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Asetukset"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Avattu <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Avattu eilen klo <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Avattu <xliff:g id="TIME_DATE_0">%1$s</xliff:g> klo <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-fr-rCA-v33/strings.xml b/PermissionController/res/values-fr-rCA-v33/strings.xml
index 722d0c2dc..808e1bcd9 100644
--- a/PermissionController/res/values-fr-rCA-v33/strings.xml
+++ b/PermissionController/res/values-fr-rCA-v33/strings.xml
@@ -19,7 +19,7 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Cette application sera autorisée à vous envoyer des notifications; elle aura accès à votre appareil photo, à vos contacts, à votre microphone, à votre téléphone et à vos messages texte"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Cette application sera autorisée à vous envoyer des notifications; elle aura accès à votre appareil photo, à vos contacts, à vos fichiers, à votre microphone, à votre téléphone et à vos messages texte"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Les applications possédant cette autorisation peuvent accéder à tous les fichiers sur cet appareil"</string>
- <string name="work_policy_title" msgid="832967780713677409">"Les détails de votre politique professionnelle"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Infos sur votre politique de travail"</string>
<string name="work_policy_summary" msgid="3886113358084963931">"Les paramètres sont gérés par votre administrateur informatique"</string>
<string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Développer et afficher la liste"</string>
<string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Réduire la liste et masquer les paramètres"</string>
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Plus d\'alertes"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertes ignorées"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Développez et affichez une autre alerte}one{Développez et affichez # autre alerte}many{Développez et affichez # d\'autres alertes}other{Développez et affichez # autres alertes}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerte. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Action terminée"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Vérifiez les paramètres qui peuvent protéger davantage votre appareil"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Paramètres rapides de sécurité et de confidentialité"</string>
diff --git a/PermissionController/res/values-fr-rCA-v34/strings.xml b/PermissionController/res/values-fr-rCA-v34/strings.xml
index ab03d9ca2..347b04cc8 100644
--- a/PermissionController/res/values-fr-rCA-v34/strings.xml
+++ b/PermissionController/res/values-fr-rCA-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Sécurité et confidentialité"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Commandes"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Connexion santé"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Gérer l\'accès des applications aux données relatives à la santé"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Gérez l\'accès des applications aux données relatives à la santé"</string>
<string name="location_settings" msgid="8863940440881290182">"Accès à la position"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"Pour les applications et les services. Si ce paramètre est désactivé, il est possible que les données du microphone soient partagées lorsque vous appelez un numéro d\'urgence"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Pour les applications et les services"</string>
diff --git a/PermissionController/res/values-fr-rCA/strings.xml b/PermissionController/res/values-fr-rCA/strings.xml
index 0c2615b83..61704f86b 100644
--- a/PermissionController/res/values-fr-rCA/strings.xml
+++ b/PermissionController/res/values-fr-rCA/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"En savoir plus"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Tout autoriser"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Toujours tout autoriser"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Autoriser un accès limité"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Sélectionner des photos et des vidéos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Sélectionner d\'autres photos"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ne pas sélectionner plus de données"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ne pas en sélectionner d\'autres"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ne pas autoriser quand même"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Fermer"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> sur <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Applications"</string>
<string name="app_permissions" msgid="3369917736607944781">"Autorisations des applications"</string>
<string name="unused_apps" msgid="2058057455175955094">"Applications non utilisées"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Modifiez une sélection de photos pour cette application"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Aucune application inutilisée"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Aucune application inutilisée"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Décisions d\'autorisation récentes"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Toutes les autorisations"</string>
<string name="other_permissions" msgid="2901186127193849594">"Autres autorisations de l\'application"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Demande d\'autorisation"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Les actions d\'installation et de désinstallation ne sont pas prises en charge par Android Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Définissez les autorisations d\'accès de l\'application « <xliff:g id="APP_NAME">%1$s</xliff:g> »"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"L\'application « <xliff:g id="APP_NAME">%1$s</xliff:g> » a été mise à jour. Définissez ses autorisations d\'accès."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Annuler"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Retirer les autorisations si l\'application est inutilisée"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Retirer autorisations et libérer espace"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Suspendre l\'activité appli si inutilisée"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gérer l\'application si inutilisée"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Retirer les autorisations, supprimer les fichiers temporaires et arrêter les notifications"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Retirer les autorisations, supprimer les fichiers temporaires, arrêter les notifications et archiver l\'application"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Afin de protéger vos données, les autorisations pour cette application seront retirées si elle n\'est pas utilisée pendant quelques mois."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Afin de protéger vos données, si l\'application n\'est pas utilisée pendant quelques mois, les autorisations suivantes seront supprimées : <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Afin de protéger vos données, les autorisations ont été supprimées pour les applications que vous n\'avez pas utilisées depuis quelques mois."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Dernière ouverture : <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Si vous autorisez la gestion de tous les fichiers, cette application pourra accéder à tous les fichiers enregistrés dans l\'espace de stockage partagé sur cet appareil ou sur des appareils de stockage connectés, les modifier et les supprimer. L\'application pourra accéder à des fichiers sans vous demander la permission."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Autoriser cette application à accéder aux fichiers qui se trouvent sur cet appareil ou sur des appareils de stockage connectés et à les modifier et les supprimer. Cette application pourra accéder à des fichiers sans vous demander la permission."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Les applications qui possèdent l\'autorisation peuvent <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Les applications ayant cette autorisation peuvent <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Les applications qui possèdent cette autorisation peuvent accéder aux données relatives à vos activités physiques, comme la marche, le vélo, la conduite, le nombre de pas effectués et plus encore"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Les applications qui possèdent cette autorisation peuvent accéder à votre agenda"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Les applications qui possèdent cette autorisation peuvent lire et écrire des journaux d\'appels téléphoniques"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Application de prise de notes"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Applications qui vous permettent de prendre des notes sur votre appareil"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"remarques"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Application par défaut actuelle"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ne plus me demander"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Définir par défaut"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Afficher la détection des déclencheurs de l\'assistant"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Afficher l\'icône dans la barre d\'état lorsque le microphone est utilisé pour activer l\'assistant vocal"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à accéder aux photos et aux médias de votre appareil?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder au contenu multimédia et aux photos sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à vos contacts?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à vos contacts sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position de cet appareil?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à la position de votre « <xliff:g id="DEVICE_NAME">%2$s</xliff:g> »?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"L\'application aura uniquement accès à la position lorsque vous l\'utilisez"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position de cet appareil?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à la position de votre « <xliff:g id="DEVICE_NAME">%2$s</xliff:g> »?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Cette appli pourrait demander à accéder à votre position en tout temps, même si vous ne l\'utilisez pas. Accordez cette autorisation dans les "<annotation id="link">"paramètres"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Modifier l\'accès à la position pour « <xliff:g id="APP_NAME">%1$s</xliff:g> »?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Modifier l\'accès à la position pour « <xliff:g id="APP_NAME">%1$s</xliff:g> » sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Cette application veut accéder à votre position en tout temps, même lorsque vous ne l\'utilisez pas. Accordez cette autorisation dans les "<annotation id="link">"paramètres"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à trouver les appareils à proximité, à s\'y connecter et à déterminer leur position relative?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à détecter les appareils à prox., à s\'y connecter et à déterminer leur position relative sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à trouver les appareils à proximité, à s\'y connecter et à déterminer leur position relative? "<annotation id="link">"Accordez l\'autorisation dans les paramètres."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Modifier l\'accès à la position de l\'application <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> d\'approximative à exacte?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Modifier l\'accès à la position de « <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> » sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> » d\'approximative à précise?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position approximative de cet appareil?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à la position approximative de votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exacte"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Approximative"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à votre agenda?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à votre agenda sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à envoyer et à afficher des messages texte?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à envoyer et à afficher des messages texte sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos, au contenu multimédia et aux fichiers de votre appareil?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder au contenu multimédia, aux photos et aux fichiers sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder &lt;b&gt;aux photos, aux vidéos, et aux fichiers musicaux et audio&lt;/b&gt; sur cet appareil?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder &lt;b&gt;aux photos, aux vidéos, et aux fichiers musicaux, audio et autres&lt;/b&gt; sur cet appareil?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux fichiers musicaux et audio sur cet appareil?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux fichiers musicaux et audio sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos et aux vidéos sur cet appareil?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux photos et vidéos sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à plus de photos et de vidéos sur cet appareil?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à plus de photos et de vidéos sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à enregistrer l\'audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à enregistrer de l\'audio sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"L\'application pourra uniquement enregistrer de l\'audio lorsque vous l\'utilisez"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à enregistrer de l\'audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à enregistrer de l\'audio sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Cette application pourrait demander à enregistrer de l\'audio en tout temps, même lorsque vous ne l\'utilisez pas. "<annotation id="link">"Autorisez dans les paramètres."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Modifier l\'accès au microphone pour « <xliff:g id="APP_NAME">%1$s</xliff:g> »?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Modifier l\'accès au microphone pour « <xliff:g id="APP_NAME">%1$s</xliff:g> » sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Cette application veut enregistrer de l\'audio en tout temps, même si vous ne l\'utilisez pas. "<annotation id="link">"Autorisez dans les paramètres."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à vos activités physiques?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à votre activité physique sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à prendre des photos et à enregistrer des vidéos?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à prendre des photos et à enregistrer des vidéos sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"L\'application pourra uniquement prendre des photos et enregistrer des vidéos lorsque vous l\'utilisez"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à prendre des photos et à enregistrer des vidéos?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à prendre des photos et à enregistrer des vidéos sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Cette appli pourrait demander à prendre des photos et des vidéos en tout temps, même lorsque vous ne l\'utilisez pas. "<annotation id="link">"Autorisez dans les paramètres."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Modifier l\'accès à l\'appareil photo pour « <xliff:g id="APP_NAME">%1$s</xliff:g> »?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Modifier l\'accès à l\'appareil photo pour « <xliff:g id="APP_NAME">%1$s</xliff:g> » sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Cette application veut prendre des photos et enregistrer des vidéos en tout temps, même lorsque vous ne l\'utilisez pas. "<annotation id="link">"Autorisez dans les paramètres."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à vos journaux d\'appels?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à vos journaux d\'appels téléphoniques sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à faire et à gérer des appels téléphoniques?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à passer et à gérer des appels téléphoniques sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux données des capteurs pour vos signes vitaux?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux données des capteurs relatives à vos signes vitaux sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Cette application souhaite pouvoir accéder en tout temps aux données des capteurs relatives à vos signes vitaux, même lorsque vous ne l\'utilisez pas. Pour effectuer ce changement, "<annotation id="link">"accédez aux paramètres"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux données des capteurs relatives à vos signes vitaux?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux données des capteurs relatives à vos signes vitaux sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Pour permettre à cette application d\'accéder aux données des capteurs corporels en tout temps, même lorsque vous n\'utilisez pas l\'application, "<annotation id="link">"accédez aux paramètres"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Voulez-vous continuer à autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux données des capteurs corporels pendant l\'utilisation de l\'appli?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Continuer à autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder aux données des capteurs corporels sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> » pendant l\'utilisation de l\'appli?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à vous envoyer des notifications?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à vous envoyer des notifications sur votre « <xliff:g id="DEVICE">%2$s</xliff:g> »?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Autorisations contrôlées"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> dispose d\'un accès à la position"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Votre organisation permet à <xliff:g id="APP_NAME">%1$s</xliff:g> d\'accéder à votre position"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Autres autorisations"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Autorisations utilisées par le système"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Autorisations utilisées par les applications système."</string>
@@ -537,7 +574,7 @@
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Vérification de l\'état"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Paramètres de confidentialité"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Plus de paramètres"</string>
- <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Accès à l\'appareil photo"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Accès à la caméra"</string>
<string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Accès au microphone"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"L\'autorisation a été retirée"</string>
<string name="camera_usage_qs" msgid="4394233566086665994">"Consulter les utilisations récentes de l\'appareil photo"</string>
@@ -579,18 +616,19 @@
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Accès modifié"</string>
<string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Voir les utilisations récentes de la position"</string>
<string name="privacy_controls_title" msgid="7605929972256835199">"Paramètres de confidentialité"</string>
- <string name="camera_toggle_title" msgid="1251201397431837666">"Accès à l\'appareil photo"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Accès à la caméra"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Accès au microphone"</string>
<string name="perm_toggle_description" msgid="7801326363741451379">"Pour les applications et les services"</string>
<string name="mic_toggle_description" msgid="9163104307990677157">"Pour les applications et les services. Si ce paramètre est désactivé, il est possible que les données du microphone soient partagées lorsque vous appelez un numéro d\'urgence."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Voir les applications et les services qui ont accès à votre emplacement"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Afficher l\'accès au presse-papiers"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Afficher un message lorsque les applications accèdent à du texte, à des images ou à d\'autres contenus que vous avez copiés"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Un message s\'affiche lorsque les applications accèdent à du texte, à des images ou à d\'autres contenus que vous avez copiés"</string>
<string name="show_password_title" msgid="2877269286984684659">"Afficher les mots de passe"</string>
- <string name="show_password_summary" msgid="1110166488865981610">"Afficher les caractères brièvement pendant la saisie"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Les caractères s\'affichent brièvement pendant la saisie"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Cette application indique qu\'elle peut partager des données de localisation avec des tiers"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Partage des données et localisation"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Provenance des renseignements sur le partage des données"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Le développeur a fourni des renseignements au fabricant de cet appareil sur la façon dont cette application partage les données. Le développeur peut mettre à jour ces renseignements au fil du temps."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Le développeur a fourni des renseignements à "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" sur la façon dont cette application partage les données. Le développeur peut mettre à jour ces renseignements au fil du temps."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"L\'appli peut partager des données de loc. pour :"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Les pratiques de partage de données peuvent varier"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Sécurité des données"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Les données de localisation peuvent être partagées"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Cette application indique qu\'elle peut partager vos données de localisation avec des tiers"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Impossible d\'ouvrir ce lien"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Mises à jour des pratiques de partage des données pour la localisation"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Passez en revue les applications qui ont changé la façon dont elles peuvent partager vos données de localisation"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Ces applications ont modifié la façon dont elles peuvent partager vos données de localisation. Elles peuvent ne pas les avoir partagées auparavant, ou peuvent maintenant les partager à des fins d\'annonces ou de marketing."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Mises à jour des pratiques de partage des données"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Certaines applis ont modifié comment elles peuvent partager vos données de localisation"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Paramètres"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Dernier accès : <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Accès hier (<xliff:g id="TIME_DATE">%1$s</xliff:g>)"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Accès : <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-fr-v33/strings.xml b/PermissionController/res/values-fr-v33/strings.xml
index 1cb802ff5..24bd671a8 100644
--- a/PermissionController/res/values-fr-v33/strings.xml
+++ b/PermissionController/res/values-fr-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Autres alertes"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertes ignorées"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Développer et voir 1 autre alerte}one{Développer et voir # autre alerte}many{Développer et voir # autres alertes}other{Développer et voir # autres alertes}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerte. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Action terminée"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Vérifiez les paramètres qui peuvent renforcer la protection de votre appareil"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Réglages rapides de sécurité et de confidentialité"</string>
diff --git a/PermissionController/res/values-fr-v34/strings.xml b/PermissionController/res/values-fr-v34/strings.xml
index 59da70170..f7f584b75 100644
--- a/PermissionController/res/values-fr-v34/strings.xml
+++ b/PermissionController/res/values-fr-v34/strings.xml
@@ -22,6 +22,6 @@
<string name="health_connect_title" msgid="2132233890867430855">"Santé Connect"</string>
<string name="health_connect_summary" msgid="815473513776882296">"Gérer l\'accès de l\'appli aux données de santé"</string>
<string name="location_settings" msgid="8863940440881290182">"Accès à la position"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Pour les applis et services. Si ce paramètre est désactivé, il est possible que les données du micro soient quand même partagées quand vous appelez un numéro d\'urgence."</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Pour les applis et services. Si ce paramètre est désactivé, il est possible que les données du micro soient quand même partagées quand vous appelez un numéro d\'urgence"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Pour les applis et services"</string>
</resources>
diff --git a/PermissionController/res/values-fr/strings.xml b/PermissionController/res/values-fr/strings.xml
index 8e8215e72..4e06abee4 100644
--- a/PermissionController/res/values-fr/strings.xml
+++ b/PermissionController/res/values-fr/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Plus d\'infos"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Tout autoriser"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Toujours autoriser"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Autoriser un accès limité"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Certaines photos et vidéos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Sélectionner plus"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ne rien sélectionner de plus"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Applications"</string>
<string name="app_permissions" msgid="3369917736607944781">"Autorisations des applications"</string>
<string name="unused_apps" msgid="2058057455175955094">"Applications inutilisées"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Modifier les photos sélectionnées pour cette application"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Aucune appli inutilisée"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 appli inutilisée"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Décisions autorisations récentes"</string>
@@ -81,7 +83,7 @@
<string name="storage_supergroup_warning_allow" msgid="103093462784523190">"Cette appli a été conçue pour une ancienne version d\'Android. Si vous lui accordez cette autorisation, elle aura accès à tout le contenu stocké (y compris, les photos, vidéos, fichiers musicaux et audio, et autres)."</string>
<string name="storage_supergroup_warning_deny" msgid="6420765672683284347">"Cette appli a été conçue pour une ancienne version d\'Android. Si vous lui refusez cette autorisation, elle n\'aura pas accès à l\'ensemble du contenu stocké (y compris, les photos, vidéos, fichiers musicaux et audio, et autres)."</string>
<string name="default_permission_description" msgid="4624464917726285203">"effectuer une action inconnue"</string>
- <string name="app_permissions_group_summary" msgid="8788419008958284002">"<xliff:g id="COUNT_0">%1$d</xliff:g> application(s) autorisée(s) sur <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
+ <string name="app_permissions_group_summary" msgid="8788419008958284002">"<xliff:g id="COUNT_0">%1$d</xliff:g> appli(s) autorisée(s) sur <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
<string name="app_permissions_group_summary2" msgid="4329922444840521150">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g> applications autorisées"</string>
<string name="menu_show_system" msgid="4254021607027872504">"Voir applis système"</string>
<string name="menu_hide_system" msgid="3855390843744028465">"Masquer applis système"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Toutes les autorisations"</string>
<string name="other_permissions" msgid="2901186127193849594">"Autres fonctionnalités de l\'application"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Demande d\'autorisation"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Opérations d\'installation et de désinstallation impossibles sur Android Wear"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Sélectionner les éléments auxquels &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; peut accéder"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"L\'application &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; a été mise à jour. Sélectionnez les éléments auxquels elle peut accéder."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Annuler"</string>
@@ -161,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Autorisations utilisées (dernière heure)"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Autorisations utilisées (15 dernières minutes)"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Autorisations utilisées (dernière minute)"</string>
- <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Non utilisée au cours du dernier jour (#)}one{Non utilisée au cours du dernier jour (#)}many{Non utilisée au cours des # derniers jours}other{Non utilisée au cours des # derniers jours}}"</string>
- <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Non utilisée au cours de la dernière heure (#)}one{Non utilisée au cours de la dernière heure (#)}many{Non utilisée au cours des # dernières heures}other{Non utilisée au cours des # dernières heures}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Pas d\'utilisation sur le dernier jour (#)}one{Pas d\'utilisation sur le dernier jour (#)}many{Pas d\'utilisation sur les # derniers jours}other{Pas d\'utilisation sur les # derniers jours}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Pas d\'utilisation sur la dernière heure (#)}one{Pas d\'utilisation sur la dernière heure (#)}many{Pas d\'utilisation sur les # dernières heures}other{Pas d\'utilisation sur les # dernières heures}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Utilisation par 1 appli}one{Utilisation par # appli}many{Utilisation par # applis}other{Utilisation par # applis}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Tout afficher dans le tableau de bord"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Données filtrées par : <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -187,7 +187,7 @@
<string name="app_permission_button_allow_all_files" msgid="1792232272599018825">"Autoriser la gestion de tous les fichiers"</string>
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Autoriser l\'accès aux fichiers multimédias uniquement"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Toujours autoriser"</string>
- <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Autoriser seulement si l\'appli est en cours d\'utilisation"</string>
+ <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Autoriser seulement si l\'appli est utilisée"</string>
<string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Toujours autoriser"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Toujours demander"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Ne pas autoriser"</string>
@@ -197,14 +197,16 @@
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Si la position exacte est désactivée, les applis ont accès à votre position approximative"</string>
<string name="app_permission_title" msgid="2090897901051370711">"Autorisation d\'accès à \"<xliff:g id="PERM">%1$s</xliff:g>\""</string>
<string name="app_permission_header" msgid="2951363137032603806">"Accès à \"<xliff:g id="PERM">%1$s</xliff:g>\" pour cette appli"</string>
- <string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Afficher toutes les autorisations pour <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Afficher toutes les applications disposant de cette autorisation"</string>
+ <string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Voir toutes les autorisations pour <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Voir toutes les applis ayant cette autorisation"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Afficher l\'utilisation du micro par l\'Assistant"</string>
<string name="unused_apps_category_title" msgid="2988455616845243901">"Paramètres des applis inutilisées"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"Supprimer les autorisations si l\'application n\'est pas utilisée"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Supprimer autorisations et libérer espace"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Suspendre activité appli si inutilisée"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gérer l\'appli si inutilisée"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Retirer les autorisations, supprimer les fichiers temporaires et arrêter les notifications"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Retirer les autorisations, supprimer les fichiers temporaires, arrêter les notifications et archiver l\'appli"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Si cette application n\'est pas utilisée pendant plusieurs mois, ses autorisations seront supprimées afin de protéger vos données."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Pour protéger vos données, si l\'application n\'est pas utilisée pendant plusieurs mois, les autorisations suivantes seront supprimées : <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Afin de protéger vos données, les autorisations ont été supprimées pour les applications que vous n\'avez pas utilisées depuis plusieurs mois."</string>
@@ -232,7 +234,7 @@
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Les applications disposant de cette autorisation peuvent consulter et modifier le journal d\'appels du téléphone"</string>
<string name="permission_description_summary_camera" msgid="108004375101882069">"Les applications disposant de cette autorisation peuvent prendre des photos et enregistrer des vidéos"</string>
<string name="permission_description_summary_contacts" msgid="2337798886460408996">"Les applications disposant de cette autorisation peuvent accéder à vos contacts"</string>
- <string name="permission_description_summary_location" msgid="2817531799933480694">"Les applications disposant de cette autorisation peuvent accéder à la position de cet appareil"</string>
+ <string name="permission_description_summary_location" msgid="2817531799933480694">"Les applications ayant cette autorisation peuvent accéder à la position de cet appareil"</string>
<string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"Les applis ayant cette autorisation peuvent détecter les appareils à proximité, s\'y connecter et déterminer leur position relative"</string>
<string name="permission_description_summary_microphone" msgid="630834800308329907">"Les applications disposant de cette autorisation peuvent enregistrer de l\'audio"</string>
<string name="permission_description_summary_phone" msgid="4515277217435233619">"Les applications disposant de cette autorisation peuvent passer et gérer des appels téléphoniques"</string>
@@ -246,8 +248,8 @@
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"Aucun accès enregistré"</string>
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"Accès refusé/aucune tentative d\'accès"</string>
<string name="allowed_header" msgid="7769277978004790414">"Autorisé"</string>
- <string name="allowed_always_header" msgid="6455903312589013545">"Toujours autorisées"</string>
- <string name="allowed_foreground_header" msgid="6845655788447833353">"Autorisées seulement pendant l\'utilisation"</string>
+ <string name="allowed_always_header" msgid="6455903312589013545">"Toujours autorisé"</string>
+ <string name="allowed_foreground_header" msgid="6845655788447833353">"Autorisé seulement pendant l\'utilisation"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"Autorisées à gérer les fichiers multimédias"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"Autorisées à gérer tous les fichiers"</string>
<string name="ask_header" msgid="2633816846459944376">"Toujours demander"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Appli de notes"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Applis vous permettant de prendre des notes sur votre appareil"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notes"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Appli par défaut actuelle"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ne plus me demander"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Définir par défaut"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Afficher la détection de l\'activation de l\'assistant"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Afficher une icône dans la barre d\'état lorsque le micro est utilisé pour activer l\'assistance vocale"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos et contenus multimédias sur votre appareil ?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos et contenus multimédias sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à vos contacts ?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à vos contacts sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position de cet appareil ?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position de votre &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"L\'application n\'a accès à la position de l\'appareil que lorsqu\'elle est ouverte"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position de cet appareil ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position de votre &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Cette appli peut vouloir accéder à votre position en permanence, même lorsque vous ne l\'utilisez pas. "<annotation id="link">"Autorisez-la à le faire dans les paramètres."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Changer l\'autorisation d\'accès à la position pour &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Modifier l\'accès à la position de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Cette appli souhaite accéder à votre position en permanence, même lorsque vous ne l\'utilisez pas. "<annotation id="link">"Autorisez-la à le faire dans les paramètres."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à détecter les appareils à proximité, s\'y connecter et déterminer leur position relative ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à détecter des appareils à proximité, s\'y connecter et déterminer leur position relative sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à détecter les appareils à proximité, s\'y connecter et déterminer leur position relative ? "<annotation id="link">"Autoriser dans les paramètres"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Donner à <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> l\'accès à la position exacte et non plus approximative ?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Modifier l\'accès à la position de <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; d\'approximative à précise ?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position approximative de cet appareil ?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la position approximative de votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exacte"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Approximative"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à votre agenda ?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à votre agenda sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à envoyer et afficher des SMS ?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à envoyer et afficher des SMS sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos, contenus multimédias et fichiers sur votre appareil ?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos, contenus multimédias et fichiers sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux &lt;b&gt;photos, vidéos, fichiers musicaux/audio&lt;/b&gt; sur l\'appareil ?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux &lt;b&gt;photos, vidéos, fichiers musicaux/audio, etc.&lt;/b&gt; sur l\'appareil ?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la musique et à l\'audio sur cet appareil ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à la musique et à l\'audio sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos et vidéos sur cet appareil ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos et vidéos sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à d\'autres photos et vidéos sur cet appareil ?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à d\'autres photos et vidéos sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à enregistrer de l\'audio ?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à réaliser des enregistrements audio sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Cette application ne pourra réaliser des enregistrements audio que lorsque vous l\'utiliserez"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; de réaliser des enregistrements audio ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à réaliser des enregistrements audio sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Cette application peut souhaiter réaliser des enregistrements audio à tout moment, même quand vous ne l\'utilisez pas. "<annotation id="link">"Autoriser dans les paramètres"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Changer l\'autorisation d\'accès au micro pour &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Modifier l\'accès au microphone de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Cette application souhaite réaliser des enregistrements audio à tout moment, même quand vous ne l\'utilisez pas. "<annotation id="link">"Autoriser dans les paramètres"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à accéder aux données relatives à votre activité physique ?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à votre activité physique sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à prendre des photos et enregistrer des vidéos ?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à prendre des photos et des vidéos sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Cette application ne pourra prendre des photos et enregistrer des vidéos que lorsque vous l\'utiliserez"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à prendre des photos et enregistrer des vidéos ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à prendre des photos et des vidéos sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Cette application peut souhaiter prendre des photos et des vidéos à tout moment, même quand vous ne l\'utilisez pas. "<annotation id="link">"Autoriser dans les paramètres"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Changer l\'autorisation d\'accès à l\'appareil photo pour &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Modifier l\'accès à l\'appareil photo de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Cette application souhaite prendre des photos et des vidéos à tout moment, même quand vous ne l\'utilisez pas. "<annotation id="link">"Autoriser dans les paramètres"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux journaux d\'appels de votre téléphone ?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à vos journaux d\'appels sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à passer et gérer des appels téléphoniques ?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à passer et gérer des appels sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux données des capteurs concernant vos signes vitaux ?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à vos signes vitaux sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Cette application veut accéder en permanence aux données des capteurs liées aux signes vitaux, même quand vous ne l\'utilisez pas. Pour autoriser ce changement, "<annotation id="link">"accédez aux paramètres."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux données des capteurs concernant vos signes vitaux ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à vos signes vitaux sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Pour autoriser cette appli à accéder aux données des capteurs corporels en permanence, même quand vous ne l\'utilisez pas, "<annotation id="link">"accédez aux paramètres"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Continuer à autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à accéder aux données des capteurs corporels seulement en cours d\'utilisation ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Continuer à autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux données des capteurs corporels en cours d\'utilisation sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à vous envoyer des notifications ?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à vous envoyer des notifications sur votre &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Autorisations contrôlées"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> a accès à votre position"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Votre organisation autorise <xliff:g id="APP_NAME">%1$s</xliff:g> à accéder à votre position"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Autres autorisations"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Autorisation utilisée par le système"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Autorisations utilisées uniquement par les applications système."</string>
@@ -537,7 +574,7 @@
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Vérifier l\'état"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Paramètres de confidentialité"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Autres paramètres"</string>
- <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Accès à l\'appareil photo"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Accès à la caméra"</string>
<string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Accès au micro"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Autorisation supprimée"</string>
<string name="camera_usage_qs" msgid="4394233566086665994">"Voir l\'utilisation récente de l\'appareil photo"</string>
@@ -575,11 +612,11 @@
<string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Examiner l\'appli qui a accès à la localisation en arrière-plan"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> peut toujours accéder à votre localisation, même lorsque l\'appli est fermée"</string>
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Examiner l\'appli qui a accès à la localisation en arrière-plan"</string>
- <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Même fermée, cette appli peut toujours accéder à votre localisation.\n\nCertaines applis de sécurité et d\'urgence nécessitent d\'accéder à votre position en arrière-plan pour fonctionner comme prévu."</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Même fermée, cette appli peut toujours accéder à votre localisation.\n\nCertaines applis de sécurité et d\'urgence ont besoin d\'accéder à votre position en arrière-plan pour fonctionner comme prévu."</string>
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Accès modifié"</string>
<string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Voir l\'utilisation récente de la localisation"</string>
<string name="privacy_controls_title" msgid="7605929972256835199">"Paramètres de confidentialité"</string>
- <string name="camera_toggle_title" msgid="1251201397431837666">"Accès à l\'appareil photo"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Accès à la caméra"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Accès au micro"</string>
<string name="perm_toggle_description" msgid="7801326363741451379">"Pour les applis et services"</string>
<string name="mic_toggle_description" msgid="9163104307990677157">"Pour les applis et services. Si ce paramètre est désactivé, il est possible que les données du micro soient quand même partagées quand vous appelez un numéro d\'urgence."</string>
@@ -591,25 +628,24 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Cette appli a indiqué qu\'elle peut partager des données de localisation avec des tiers"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Partage des données et localisation"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Origine des informations sur le partage des données"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Le développeur a fourni des infos au fabricant de cet appareil concernant la manière dont cette appli partage les données. Le développeur peut mettre à jour ces infos au fil du temps."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Le développeur a fourni des infos sur "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" concernant la manière dont cette appli partage les données. Le développeur peut mettre à jour ces infos au fil du temps."</string>
- <string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Appli peut partager données de localisation pour :"</string>
+ <string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"L\'appli peut partager des données de localis. pour :"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Partage des données variable"</string>
<string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"La gestion des données peut varier selon la version de l\'appli, l\'utilisation que vous en faites, votre région et votre âge. "<annotation id="link">"En savoir plus sur le partage des données"</annotation></string>
<string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"La gestion des données peut varier selon la version de l\'appli, l\'utilisation que vous en faites, votre région et votre âge."</string>
<string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Vos données de localisation"</string>
<string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Modifiez l\'accès de cette appli dans les "<annotation id="link">"paramètres de confidentialité"</annotation></string>
- <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Fonctionnement de l\'appli"</string>
- <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Données analytiques"</string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"le fonctionnement de l\'appli ;"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"les données analytiques ;"</string>
<string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Communications du développeur"</string>
- <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Publicité ou marketing"</string>
- <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prévention des fraudes, sécurité et conformité"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"la publicité ou marketing ;"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"la prévention des fraudes, la sécurité et la conformité."</string>
<string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personnalisation"</string>
<string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Gestion du compte"</string>
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Sécurité des données"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Les données de localisation peuvent être partagées"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Cette appli a indiqué qu\'elle peut partager vos données de localisation avec des tiers"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Impossible d\'ouvrir ce lien"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Mises à jour du partage des données pour la localisation"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Consulter les applis qui ont modifié la manière dont elles peuvent partager vos données de localisation"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Ces applis ont modifié la manière dont elles peuvent partager vos données de localisation. Elles ne les partageaient peut-être pas auparavant ou peuvent désormais les partager à des fins de publicité ou de marketing."</string>
@@ -619,7 +655,10 @@
<string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Vos données de localisation sont désormais partagées avec des tiers à des fins de publicité ou de marketing"</string>
<string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Mise à jour au cours du dernier jour}=1{Mise à jour au cours du dernier jour}one{Mise à jour il y a # jour}many{Mise à jour au cours des # derniers jours}other{Mise à jour au cours des # derniers jours}}"</string>
<string name="no_updates_at_this_time" msgid="9031085635689982935">"Aucune mise à jour pour le moment"</string>
- <string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Mises à jour du partage des données"</string>
+ <string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Modifications du partage des données"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Certaines applis ont modifié la façon dont elles peuvent partager vos données de localisation"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Paramètres"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Dernière consultation : <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Dernière consultation : hier, à <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Dernière consultation : <xliff:g id="TIME_DATE_0">%1$s</xliff:g><xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-gl-v33/strings.xml b/PermissionController/res/values-gl-v33/strings.xml
index 780f3faf6..3c8898c4f 100644
--- a/PermissionController/res/values-gl-v33/strings.xml
+++ b/PermissionController/res/values-gl-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Máis alertas"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertas pechadas"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Despregar tarxeta e ver 1 alerta máis}other{Despregar tarxeta e ver # alertas máis}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerta. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Acción completada"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Comproba as opcións de configuración que poden aumentar a protección do dispositivo"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Configuración rápida de seguranza e privacidade"</string>
diff --git a/PermissionController/res/values-gl/strings.xml b/PermissionController/res/values-gl/strings.xml
index e4f42ab90..0d7297898 100644
--- a/PermissionController/res/values-gl/strings.xml
+++ b/PermissionController/res/values-gl/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Máis datos"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Permitir todos"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Permitir todos sempre"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Permitir acceso limitado"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Seleccionar fotos e vídeos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Seleccionar máis"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Non seleccionar máis"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Non permitir aínda así"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Pechar"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Queres permitir á aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Permitir sempre á aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Queres dar permiso á aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; para <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; poida <xliff:g id="ACTION">%2$s</xliff:g> sempre?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Só ao usar a aplicación"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Sempre"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Non permitir e non volver preguntar"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplicacións"</string>
<string name="app_permissions" msgid="3369917736607944781">"Permisos de aplicacións"</string>
<string name="unused_apps" msgid="2058057455175955094">"Aplicacións que non se usan"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Editar as fotos seleccionadas desta aplicación"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Non hai aplicacións sen usar"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 aplicacións que non se usan"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Decisións recentes de permisos"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Todos os permisos"</string>
<string name="other_permissions" msgid="2901186127193849594">"Outras funcionalidades da aplicación"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Solicitude de permiso"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"As accións de instalar e desinstalar non son compatibles con Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Seleccionar os permisos de acceso que queres dar á aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Actualizouse a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;. Selecciona os permisos de acceso que lle queres dar."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancelar"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Quitar permisos se non se usa a aplicación"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Quitar permisos e liberar espazo"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pór en pausa actividade de apps sen uso"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Xestionar aplicación se non se usa"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Quita permisos, elimina ficheiros temporais e detén as notificacións"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Quita permisos, elimina os ficheiros temporais, detén as notificacións e arquiva a aplicación"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Para protexer os teus datos, quitaranse os permisos desta aplicación se pasas varios meses sen utilizala."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Para protexer os teus datos, se a aplicación leva varios meses sen usarse, quitaranse os seguintes permisos: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Para protexer os teus datos, quitáronse os permisos das aplicacións que levas varios meses sen usar."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Abriuse por última vez o <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Se permites a xestión de todos os ficheiros, esta aplicación pode acceder aos ficheiros de almacenamento común, así como modificalos e eliminalos, neste dispositivo ou nos dispositivos de almacenamento conectados. A aplicación pode acceder aos ficheiros sen pedirche permiso."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Queres permite que esta aplicación acceda aos ficheiros, así como que os modifique e elimine, neste dispositivo ou en calquera dispositivo de almacenamento conectado? Esta aplicación pode acceder aos ficheiros sen pediche permiso."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"As aplicacións que teñen este permiso poden facer o seguinte: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"As aplicacións que teñen este permiso poden <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"As aplicacións que teñen este permiso poden acceder á túa actividade física, como as camiñadas, os percorridos en bicicleta, os traxectos en coche, o reconto de pasos e moito máis"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"As aplicacións que teñen este permiso poden acceder ao teu calendario"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"As aplicacións que teñen este permiso poden ler e editar o rexistro de chamadas do teléfono"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplicación de notas"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplicacións que che permiten tomar notas no dispositivo"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notas"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"App predeterminada actual"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Non preguntar de novo"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"App predeterminada"</string>
@@ -444,7 +456,7 @@
<string name="incident_report_dialog_title" msgid="669104389325204095">"Queres compartir os datos de depuración?"</string>
<string name="incident_report_dialog_intro" msgid="5897733669850951832">"O sistema detectou un problema."</string>
<string name="incident_report_dialog_text" msgid="5675553296891757523">"A aplicación <xliff:g id="APP_NAME_0">%1$s</xliff:g> quere subir un informe de erros deste dispositivo, xerado o <xliff:g id="DATE">%2$s</xliff:g> (<xliff:g id="TIME">%3$s</xliff:g>). Os informes de erros inclúen información persoal sobre o dispositivo ou datos rexistrados polas aplicacións, como os nomes de usuario, os datos de localización, os identificadores do dispositivo e a información da rede. Comparte estes informes unicamente con persoas e aplicacións de confianza. Queres permitir que a aplicación <xliff:g id="APP_NAME_1">%4$s</xliff:g> cargue un informe de erros?"</string>
- <string name="incident_report_error_dialog_text" msgid="4189647113387092272">"Houbo un erro ao procesar o informe de erro da aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>, polo cal se denegou o uso compartido dos datos de depuración detallados. Lamentamos a interrupción."</string>
+ <string name="incident_report_error_dialog_text" msgid="4189647113387092272">"Houbo un erro ao procesar o informe de erros da aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>, polo cal se denegou o uso compartido dos datos de depuración detallados. Lamentamos a interrupción."</string>
<string name="incident_report_dialog_allow_label" msgid="2970242967721155239">"Permitir"</string>
<string name="incident_report_dialog_deny_label" msgid="3535314290677579383">"Denegar"</string>
<string name="adjust_user_sensitive_title" msgid="4196724451314280527">"Configuración avanzada"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Mostrar detección do activador do asistente"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mostra unha icona na barra de estado cando se utiliza o micrófono para activar o asistente de voz"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ás fotos, ao contido multimedia e aos ficheiros do teu dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ás fotos e ao contido multimedia no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos teus contactos?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos teus contactos no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á localización deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á localizacion do dispositivo &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"A aplicación só terá acceso á localización mentres a esteas utilizando"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á localización deste dispositivo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á localización do dispositivo &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Esta aplicación pode querer acceder á túa localización todo o tempo, incluso cando non a esteas utilizando. "<annotation id="link">"Permitir en Configuración"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Queres cambiar o acceso da aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; á localización?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Queres cambiar o acceso da aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; á localización no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Esta aplicación quere acceder á túa localización todo o tempo, incluso cando non a esteas utilizando. "<annotation id="link">"Permitir en Configuración"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; atope dispositivos próximos, se conecte a eles e determine a súa posición relativa?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Permites que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; busque, conecte e fixe a posición relativa dos disp. próximos no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; atope dispositivos próximos, se conecte a eles e determine a súa posición relativa? "<annotation id="link">"Permitir na configuración"</annotation>"."</string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Queres que o acceso de <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> á localización cambie de aproximada a precisa?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Queres cambiar o acceso á localización da aplicación <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; de aproximada a exacta?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á localización aproximada deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á localización aproximada do dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precisa"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aproximada"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ao teu calendario?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ao teu calendario no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe e vexa mensaxes SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe e vexa mensaxes SMS no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a fotos, contido multimedia e ficheiros no teu dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ás fotos, ao contido multimedia e aos ficheiros no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ás &lt;b&gt;fotos, vídeos, música e audio&lt;/b&gt; deste dispositivo?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ás &lt;b&gt;fotos, vídeos, música, audio e outros ficheiros&lt;/b&gt; do dispositivo?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á música e aos ficheiros de audio deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á música e aos ficheiros de audio no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ás fotos e aos vídeos deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda ás fotos e aos vídeos no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a máis fotos e vídeos deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a máis fotos e vídeos no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave audio no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Esta aplicación só poderá gravar audio cando a esteas utilizando"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave audio no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Pode que esta aplicación queira gravar audio todo o tempo, incluso cando non a esteas utilizando. "<annotation id="link">"Permitir en Configuración."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Queres cambiar o acceso da aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ao micrófono?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Queres cambiar o acceso da aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ao micrófono no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Esta aplicación quere gravar audio todo o tempo, incluso cando non a esteas utilizando. "<annotation id="link">"Permitir en Configuración."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á túa actividade física?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á tua actividade física no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; realice fotos e grave vídeos?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Esta aplicación só poderá sacar fotos e gravar vídeos cando a esteas utilizando"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; saque fotos e grave vídeos?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Pode que esta aplicación queira sacar fotos e gravar vídeos todo o tempo, incluso cando non a esteas utilizando. "<annotation id="link">"Permitir en Configuración."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Queres cambiar o acceso da aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; á cámara?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Queres cambiar o acceso da aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; á cámara no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Esta aplicación quere sacar fotos e gravar vídeos todo o tempo, incluso cando non a esteas utilizando. "<annotation id="link">"Permitir en Configuración."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos rexistros de chamadas do teléfono?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos rexistros de chamadas telefónicas no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; realice e xestione chamadas telefónicas?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; realice e xestione chamadas no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos datos dos sensores sobre as túas constantes vitais?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos datos dos sensores sobre as constantes vitais no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Esta aplicación require acceso aos datos dos sensores sobre as túas constantes vitais en todo momento, mesmo cando non a usas. Para facer este cambio, "<annotation id="link">"vai á configuración."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos datos dos sensores sobre as túas constantes vitais?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos datos dos sensores sobre as constantes vitais no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Para permitir que esta aplicación acceda aos datos dos sensores corporais en todo momento, aínda que non a esteas utilizando, "<annotation id="link">"vai á configuración"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Permites que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; siga accedendo aos datos dos sensores corporais mentres estea en uso?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Permites que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos datos dos sensores corporais no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mentres estea en uso?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Queres permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; che envíe notificacións?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; che envíe notificacións no dispositivo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Permisos controlados"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ten acceso á localización"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"A túa organización permite que <xliff:g id="APP_NAME">%1$s</xliff:g> acceda á túa localización"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Outros permisos"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permiso que utiliza o sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permisos que só utilizan as aplicacións do sistema."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"A aplicación indicou que é posible que comparta datos de localización con terceiros"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Uso compartido de datos e localización"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"De onde provén a información sobre o uso compartido de datos?"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"A persoa que programou esta aplicación facilitoulle información acerca de como comparte datos ao fabricante deste dispositivo. Esa persoa pode modificar esta información co paso do tempo."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"A persoa que programou esta aplicación facilitoulle información acerca de como comparte datos a "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". É posible que esa persoa modifique esta información co paso do tempo."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"A app pode compartir datos de localización para:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"As prácticas de uso compartido de datos varían"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Seguranza dos datos"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Poden compartirse os datos de localización"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Esta aplicación indicou que pode compartir os teus datos de localización con terceiros"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Non se puido abrir esta ligazón"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Actualizacións do uso compartido de datos de localización"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Revisa as aplicacións que cambiaron a forma en que poden compartir os teus datos de localización"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Estas aplicacións cambiaron a forma en que poden compartir os teus datos de localización. É posible que non os compartisen antes ou que agora os compartan con fins publicitarios ou de márketing."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Actualizacións de uso compartido de datos"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Algunhas aplicacións cambiaron a forma en que poden compartir os teus datos de localización"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Configuración"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Último acceso: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Último acceso: onte, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Último acceso: <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-gu-v33/strings.xml b/PermissionController/res/values-gu-v33/strings.xml
index 06ea8f9b2..d77558fc3 100644
--- a/PermissionController/res/values-gu-v33/strings.xml
+++ b/PermissionController/res/values-gu-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"વધુ અલર્ટ"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"છોડી દીધેલા અલર્ટ"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{મોટું કરો અને વધુ એક અલર્ટ જુઓ}one{મોટું કરો અને વધુ # અલર્ટ જુઓ}other{મોટું કરો અને વધુ # અલર્ટ જુઓ}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"અલર્ટ. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"ક્રિયા પૂર્ણ થઈ"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"તમારા ડિવાઇસમાં સુરક્ષા ઉપાયો ઉમેરી શકે એવા સેટિંગ ચેક કરો"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"સુરક્ષા અને પ્રાઇવસી માટેના ઝડપી સેટિંગ"</string>
diff --git a/PermissionController/res/values-gu/strings.xml b/PermissionController/res/values-gu/strings.xml
index be4fbe77f..8202cc705 100644
--- a/PermissionController/res/values-gu/strings.xml
+++ b/PermissionController/res/values-gu/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"વધુ માહિતી"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"બધાને મંજૂરી આપો"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"હંમેશાં માટે બધાને મંજૂરી આપો"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"મર્યાદિત ઍક્સેસની મંજૂરી આપો"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ફોટા અને વીડિયો પસંદ કરો"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"વધુ ફોટા પસંદ કરો"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"વધુ પસંદ કરશો નહીં"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ઍપ"</string>
<string name="app_permissions" msgid="3369917736607944781">"ઍપની પરવાનગીઓ"</string>
<string name="unused_apps" msgid="2058057455175955094">"ન વપરાયેલી ઍપ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"આ ઍપ માટે પસંદ કરેલા ફોટામાં ફેરફાર કરો"</string>
<string name="no_unused_apps" msgid="12809387670415295">"કોઈ બિનવપરાયેલી ઍપ નથી"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"બિનવપરાયેલી 0 ઍપ"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"પરવાનગી સંબંધિત નિર્ણયો"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"બધી પરવાનગીઓ"</string>
<string name="other_permissions" msgid="2901186127193849594">"અન્ય ઍપ સુવિધાઓ"</string>
<string name="permission_request_title" msgid="8790310151025020126">"પરવાનગીની વિનંતી"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear પર ઇન્સ્ટૉલ/અનઇન્સ્ટૉલ ક્રિયાઓ સમર્થિત નથી."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને શેના ઍક્સેસ માટેની મંજૂરી આપવી તે પસંદ કરો"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; અપડેટ કરવામાં આવી છે. આ ઍપને શેના ઍક્સેસ માટેની મંજૂરી આપવી તે પસંદ કરો."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"રદ કરો"</string>
@@ -130,7 +130,7 @@
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"અન્ય પરવાનગીઓ જુઓ"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
<string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> અને વધુ <xliff:g id="NUM">%3$s</xliff:g>"</string>
- <string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"છેલ્લા 24 કલાકમાં ઍપ દ્વારા તમારા <xliff:g id="PERMGROUP">%1$s</xliff:g>નો ઉપયોગ ક્યારે કરવામાં આવ્યો, તેની સમયરેખા"</string>
+ <string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"છેલ્લા 24 કલાકમાં ઍપ દ્વારા તમારા <xliff:g id="PERMGROUP">%1$s</xliff:g>નો ઉપયોગ ક્યારે કરવામાં આવ્યો, તેની ટાઇમલાઇન"</string>
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"છેલ્લા 7 દિવસમાં ઍપ દ્વારા તમારા <xliff:g id="PERMGROUP">%1$s</xliff:g>નો ઉપયોગ ક્યારે કરવામાં આવ્યો, તેની સમયરેખા"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"જ્યારે આ ઍપ દ્વારા તમારી <xliff:g id="PERMGROUP">%1$s</xliff:g>ની પરવાનગીનો ઉપયોગ કરવામાં આવ્યો"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"વધુ જાણો"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ઍપ ઉપયોગમાં ન હોવા પર પરવાનગીઓ કાઢી નાખો"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"પરવાનગીઓ કાઢી નાખો અને જગ્યા ખાલી કરો"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"જો ઉપયોગ કરતા ન હો, તો ઍપ પ્રવૃત્તિ થોભાવો"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"જો ઍપ વાપરતા ન હો, તો તેને મેનેજ કરો"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"પરવાનગીઓ કાઢી નાખો, હંગામી ફાઇલો ડિલીટ કરો અને નોટિફિકેશન બંધ કરો"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"પરવાનગીઓ કાઢી નાખો, હંગામી ફાઇલો ડિલીટ કરો, નોટિફિકેશન બંધ કરો અને ઍપને આર્કાઇવ કરો"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"તમારા ડેટાની સુરક્ષા કરવા માટે, જો ઍપનો કેટલાક મહિનાથી ઉપયોગ કરવામાં આવ્યો ન હોય, તો આ ઍપની પરવાનગીઓ કાઢી નાખવામાં આવશે."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"તમારા ડેટાની સુરક્ષા કરવા માટે, જો ઍપનો કેટલાક મહિનાથી ઉપયોગ કરવામાં આવ્યો ન હોય, તો નીચેની પરવાનગીઓ કાઢી નાખવામાં આવશે: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"તમારા ડેટાની સુરક્ષા માટે, તમારા દ્વારા કેટલાક મહિનાથી ઉપયોગમાં ન લેવાયેલી ઍપની પરવાનગીઓ કાઢી નાખવામાં આવી છે."</string>
@@ -226,13 +228,13 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"છેલ્લે <xliff:g id="DATE">%s</xliff:g>ના રોજ ખોલી"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"તમે બધી ફાઇલો મેનેજ કરવાની મંજૂરી આપશો, તો આ ઍપ, આ ડિવાઇસના સામાન્ય સ્ટોરેજમાં અથવા કનેક્ટ કરેલા સ્ટોરેજ ડિવાઇસમાં રહેલી કોઈપણ ફાઇલને ઍક્સેસ કરી શકશે, તેમાં ફેરફાર કરી શકશે અથવા તેને ડિલીટ કરી શકશે. ઍપ તમને પૂછ્યા વિના ફાઇલો ઍક્સેસ કરે તેમ બની શકે છે."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"ડિવાઇસમાં અથવા કનેક્ટ કરેલા સ્ટોરેજ ડિવાઇસમાં રહેલી ફાઇલોને ઍક્સેસ કરવાની, તેમાં ફેરફાર કરવાની અથવા તેને ડિલીટ કરવાની મંજૂરી આપીએ? આ ઍપ તમને પૂછ્યા વિના ફાઇલો ઍક્સેસ કરે તેમ બની શકે છે."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"આ પરવાનગી ધરાવતી ઍપ <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"આ પરવાનગી ધરાવતી ઍપ આ કરી શકે છે: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"આ પરવાનગી ધરાવતી ઍપ તમારી શારીરિક પ્રવૃત્તિ જેમ કે ચાલવું, બાઇકિંગ, ડ્રાઇવિંગ, પગલાંની સંખ્યા અને બીજી ઘણી બધી પ્રવૃત્તિ ઍક્સેસ કરી શકે છે"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"આ પરવાનગી ધરાવતી ઍપ તમારા કૅલેન્ડરને ઍક્સેસ કરી શકશે"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"આ પરવાનગી ધરાવતી ઍપ ફોન કૉલ લૉગ વાંચી અને લખી શકે છે"</string>
<string name="permission_description_summary_camera" msgid="108004375101882069">"આ પરવાનગી ધરાવતી ઍપ ફોટા લઈ શકે છે અને વીડિયો રેકોર્ડ કરી શકે છે"</string>
<string name="permission_description_summary_contacts" msgid="2337798886460408996">"આ પરવાનગી ધરાવતી ઍપ તમારા સંપર્કોને ઍક્સેસ કરી શકશે"</string>
- <string name="permission_description_summary_location" msgid="2817531799933480694">"આ પરવાનગી ધરાવતી ઍપ આ ડિવાઇસનું સ્થાન ઍક્સેસ કરી શકે છે"</string>
+ <string name="permission_description_summary_location" msgid="2817531799933480694">"આ પરવાનગી ધરાવતી ઍપ આ ડિવાઇસનું લોકેશન ઍક્સેસ કરી શકે છે"</string>
<string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"આ પરવાનગી ધરાવતી ઍપ નજીકના ડિવાઇસ શોધી શકે છે, તેઓને કનેક્ટ કરી શકે છે તેમજ સંબંધિત અંતર નક્કી કરી શકે છે"</string>
<string name="permission_description_summary_microphone" msgid="630834800308329907">"આ પરવાનગી ધરાવતી ઍપ ઑડિયો રેકોર્ડ કરી શકશે"</string>
<string name="permission_description_summary_phone" msgid="4515277217435233619">"આ પરવાનગી ધરાવતી ઍપ ફોન કૉલ કરી શકશે અને તેને મેનેજ કરી શકશે"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"નોંધ માટેની ઍપ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"ઍપ કે જે તમને તમારા ડિવાઇસ પર નોંધ કરવાની મંજૂરી આપે છે"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"નોંધ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"હાલની ડિફૉલ્ટ"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"ફરીથી પૂછશો નહીં"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ડિફૉલ્ટ તરીકે સેટ"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"આસિસ્ટંટ ટ્રિગરની ઓળખ બતાવો"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"જ્યારે માઇક્રોફોનનો ઉપયોગ કરીને વૉઇસ આસિસ્ટંટ સક્રિય કરવામાં આવે, ત્યારે માઇક્રોફોનનું આઇકન સ્ટેટસ બારમાં બતાવો"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા ડિવાઇસ પર ફોટા અને મીડિયાને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"શું &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"શું &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>નું લોકેશન ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"તમે આ ઍપનો ઉપયોગ કરી રહ્યાં ન હો, તો પણ તે હંમેશાં તમારા સ્થાનને ઍક્સેસ કરી શકે છે. "<annotation id="link">"સેટિંગમાંથી મંજૂરી આપો."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; માટે સ્થાનનો ઍક્સેસ બદલીએ?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"તમારા &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"તમે આ ઍપનો ઉપયોગ કરી રહ્યાં ન હો, તો પણ તે હંમેશાં તમારા સ્થાનને ઍક્સેસ કરવા માગે છે. "<annotation id="link">"સેટિંગમાંથી મંજૂરી આપો."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને નજીકના ડિવાઇસને શોધવાની, તેને કનેક્ટ કરવાની તેમજ સંબંધિત અંતર નક્કી કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર નજીકના ડિવાઇસ શોધવાની, કનેક્ટ કરવાની ને સંબંધિત અંતર નક્કી કરવાની મંજૂરી આપીએ?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને નજીકના ડિવાઇસને શોધવાની, તેને કનેક્ટ કરવાની તેમજ સંબંધિત અંતર નક્કી કરવાની મંજૂરી આપીએ? "<annotation id="link">"સેટિંગમાં મંજૂરી આપો."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>નો સ્થાનનો ઍક્સેસ અંદાજિતમાંથી બદલીને ચોક્કસ કરીએ?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"શું <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>નો તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$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_calendar" msgid="1493150855673603806">"&lt;b&gt;<xliff:g id="APP_NAME">%1$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_device_aware_calendar" msgid="3103987548035171850">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર SMS મેસેજ મોકલવાની અને જોવાની મંજૂરી આપીએ?"</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="872629037299467086">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર ફોટા, મીડિયા અને ફાઇલો ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને આ ડિવાઇસ પરના &lt;/b&gt;ફોટા, વીડિયો, મ્યુઝિક અને ઑડિયો&lt;/b&gt;ના ઍક્સેસની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને આ ડિવાઇસ પર &lt;b&gt;ફોટા, વીડિયો, મ્યુઝિક, ઑડિયો અને અન્ય ફાઇલો&lt;b&gt;ના ઍક્સેસની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને આ ડિવાઇસ પરની મ્યુઝિક અને ઑડિયો ફાઇલો ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર મ્યુઝિક અને ઑડિયો ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને આ ડિવાઇસ પરના ફોટા અને વીડિયો ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર ફોટા અને વીડિયો ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને આ ડિવાઇસ પરના વધુ ફોટા અને વીડિયો ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર વધુ ફોટા અને વીડિયો ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને ઑડિયો રેકૉર્ડ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર ઑડિયો રેકૉર્ડ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"જ્યારે તમે ઍપનો ઉપયોગ કરી રહ્યા હશો, માત્ર ત્યારે જ ઍપ ઑડિયો રેકોર્ડ કરી શકશે"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને ઑડિયો રેકોર્ડ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર ઑડિયો રેકૉર્ડ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"તમે આ ઍપનો ઉપયોગ કરી રહ્યાં ન હો, તો પણ ઍપ હંમેશાં ઑડિયો રેકોર્ડ કરવાનું ઇચ્છી શકે છે. "<annotation id="link">"સેટિંગમાંથી મંજૂરી આપો."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; માટે માઇક્રોફોનનો ઍક્સેસ બદલીએ?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"તમારા &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"તમે આ ઍપનો ઉપયોગ કરી રહ્યાં ન હો, તો પણ ઍપ હંમેશાં ઑડિયો રેકોર્ડ કરવા માગે છે. "<annotation id="link">"સેટિંગમાંથી મંજૂરી આપો."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારી શારીરિક પ્રવૃત્તિને ઍક્સેસ કરવાની મંજૂરી આપવી છે?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર તમારી શારીરિક પ્રવૃત્તિ ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને ફોટા પાડવાની અને વીડિયો રેકોર્ડ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર ફોટા લેવાની અને વીડિયો રેકોર્ડ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"જ્યારે તમે ઍપનો ઉપયોગ કરી રહ્યા હશો, માત્ર ત્યારે જ ઍપ ફોટા લઈ શકશે અને વીડિયો રેકોર્ડ કરી શકશે"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને ફોટા લેવાની અને વીડિયો રેકોર્ડ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર ફોટા લેવાની અને વીડિયો રેકોર્ડ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"તમે આ ઍપનો ઉપયોગ કરી રહ્યાં ન હો, તો પણ ઍપ હંમેશાં ફોટા લેવા અને વીડિયો રેકોર્ડ કરવાનું ઇચ્છી શકે છે. "<annotation id="link">"સેટિંગમાંથી મંજૂરી આપો."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; માટે કૅમેરાનો ઍક્સેસ બદલીએ?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"શું તમારા &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"તમે આ ઍપનો ઉપયોગ કરી રહ્યાં ન હો, તો પણ ઍપ હંમેશાં ફોટા લેવા અને વીડિયો રેકોર્ડ કરવા માગે છે. "<annotation id="link">"સેટિંગમાંથી મંજૂરી આપો."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા ફોનના કૉલ લૉગ ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર તમારા ફોનના કૉલ લૉગ ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને ફોન કૉલ કરવાની અને તેને મેનેજ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર ફોન કૉલ કરવાની અને તેને મેનેજ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા જીવિત હોવાના મહત્ત્વપૂર્ણ સંકેતો વિશેના સેન્સર ડેટાને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર તમારા જીવિત હોવાના મહત્ત્વપૂર્ણ સંકેતો વિશેનો સેન્સરનો ડેટા ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"આ ઍપ તમારા આરોગ્ય વિશે મહત્ત્વપૂર્ણ સંકેતો આપતો સેન્સરનો ડેટા હંમેશાં ઍક્સેસ કરવા માગે છે, તમે ઍપ ન વાપરતા હો ત્યારે પણ. આમાં ફેરફાર કરવા માટે, "<annotation id="link">"સેટિંગ પર જાઓ."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા જીવિત હોવાના મહત્ત્વપૂર્ણ સંકેતો વિશેનો સેન્સરનો ડેટા ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર તમારા જીવિત હોવાના મહત્ત્વપૂર્ણ સંકેતો વિશેનો સેન્સરનો ડેટા ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"જ્યારે તમે ઍપનો ઉપયોગ કરી રહ્યાં ન હો, ત્યારે પણ આ ઍપને બૉડી સેન્સરનો ડેટા ઍક્સેસ કરવાની મંજૂરી આપવા માટે, "<annotation id="link">"સેટિંગ પર જાઓ."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ઍપ ઉપયોગમાં હોય ત્યારે &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને બૉડી સેન્સર ડેટા ઍક્સેસ કરવાની મંજૂરી આપવાનું ચાલુ રાખીએ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"ઍપના ઉપયોગ વખતે, &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર બૉડી સેન્સર ડેટા ઍક્સેસ કરવાની મંજૂરી ચાલુ રાખીએ?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમને નોટિફિકેશન મોકલવાની મંજૂરી આપીએ?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"શું &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ને તમારા ;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; પર નોટિફિકેશન મોકલવાની મંજૂરી આપીએ?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"નિયંત્રિત પરવાનગીઓ"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> પાસે લોકેશન ઍક્સેસ છે"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"તમારી સંસ્થા <xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારું લોકેશન ઍક્સેસ કરવાની મંજૂરી આપે છે"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"અન્ય પરવાનગીઓ"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"સિસ્ટમ દ્વારા ઉપયોગમાં લેવાતી પરવાનગીઓ"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"ફક્ત સિસ્ટમ ઍપ્લિકેશન દ્વારા ઉપયોગમાં લેવાતી પરવાનગીઓ."</string>
@@ -518,7 +555,7 @@
<string name="exempt_info_label" msgid="6286190981253476699">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને Android વડે સુરક્ષિત કરવામાં આવી છે. આ ડિવાઇસમાં તમારા ડેટા પર પ્રક્રિયા કરવામાં આવતી હોવાથી, આ ઍપની પરવાનગીના વપરાશની માહિતી તમારા પ્રાઇવસી ડૅશબોર્ડ પર બતાવવામાં આવતી નથી."</string>
<string name="blocked_camera_title" msgid="1128510551791284384">"ડિવાઇસનો કૅમેરા બ્લૉક કરેલો છે"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"ડિવાઇસનું માઇક્રોફોન બ્લૉક કરેલું છે"</string>
- <string name="blocked_location_title" msgid="2005608279812892383">"ડિવાઇસનું સ્થાન બંધ છે"</string>
+ <string name="blocked_location_title" msgid="2005608279812892383">"ડિવાઇસનું લોકેશન બંધ છે"</string>
<string name="blocked_sensor_summary" msgid="4443707628305027375">"ઍપ અને સેવાઓ માટે"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"જ્યારે તમે ઇમર્જન્સી નંબર પર કૉલ કરો ત્યારે કદાચ માઇક્રોફોનનો ડેટા હજી પણ શેર કરવામાં આવી શકે છે."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"બદલો"</string>
@@ -574,10 +611,10 @@
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"આ ઍપ Androidના નવીનતમ વર્ઝનને સપોર્ટ કરતી નથી. જો આ ઍપ મ્યુઝિક અને ઑડિયો ફાઇલોને ઍક્સેસ કરી શકતી ન હોય, તો તેને ફોટા અને વીડિયોને પણ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે નહીં."</string>
<string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"બૅકગ્રાઉન્ડમાં સ્થાનનો ઍક્સેસ ધરાવતી ઍપનો રિવ્યૂ કરો"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> હંમેશાં તમારા સ્થાનને ઍક્સેસ કરી શકે છે, ઍપ બંધ હોય ત્યારે પણ"</string>
- <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"બૅકગ્રાઉન્ડમાં સ્થાનનો ઍક્સેસ ધરાવતી ઍપનો રિવ્યૂ કરો"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"બૅકગ્રાઉન્ડમાં લોકેશનનો ઍક્સેસ ધરાવતી ઍપનો રિવ્યૂ કરો"</string>
<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="safety_center_view_recent_location_access" msgid="3524391299490678243">"લોકેશનનો તાજેતરનો વપરાશ જુઓ"</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>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"આ ઍપ દ્વારા જણાવવામાં આવ્યું છે કે તે ત્રીજા પક્ષો સાથે લોકેશન ડેટા શેર કરી શકે છે"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ડેટા શેરિંગ અને લોકેશન"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ડેટા શેરિંગ સંબંધિત માહિતી ક્યાંથી આવે છે"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ઍપના ડેવલપરે આ ઍપની ડેટા શેર કરવાની રીત વિશેની માહિતી આ ડિવાઇસના નિર્માતાને પૂરી પાડી છે. સમય જતાં કદાચ ડેવલપર આ માહિતી અપડેટ કરી શકે છે."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ઍપના ડેવલપરે આ ઍપની ડેટા શેર કરવા વિશેની માહિતી "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"ને પૂરી પાડી છે. સમય જતાં કદાચ ડેવલપર આ માહિતી અપડેટ કરી શકે છે."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"આ ઍપ આ માટે લોકેશન ડેટા શેર કરી શકે છે:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ડેટા શેરિંગમાં ફેરફાર થતો રહે છે"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ડેટા સલામતી"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"લોકેશન ડેટા શેર કરવામાં આવી શકે છે"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"આ ઍપ દ્વારા જણાવવામાં આવ્યું છે કે તે ત્રીજા પક્ષો સાથે તમારો લોકેશન ડેટા શેર કરી શકે છે"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"આ લિંક ખોલી શકાતી નથી"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"લોકેશન માટે ડેટા શેરિંગ સંબંધિત અપડેટ"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"તે ઍપનું રિવ્યૂ કરો જેમણે તમારા લોકેશન ડેટાને શેર કરવાની રીત બદલી છે"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"આ ઍપ દ્વારા તમારા લોકેશન ડેટાને શેર કરવાની રીત બદલવામાં આવી હોઈ શકે છે. તેઓએ તેને પહેલાં શેર કર્યો ન હોય એવું બની શકે છે અથવા હવે તેને જાહેરાત અથવા માર્કેટિંગ હેતુઓ માટે શેર કરી શકે છે."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ડેટા શેરિંગ સંબંધિત અપડેટ"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"કેટલીક ઍપ દ્વારા તમારા લોકેશન ડેટાને શેર કરવાની રીત બદલવામાં આવી હોઈ શકે છે"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"સેટિંગ"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"ઍક્સેસ કર્યાનો સમય <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"ઍક્સેસ કર્યાનો સમય ગઈકાલે <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"ઍક્સેસ કર્યાનો સમય <xliff:g id="TIME_DATE_0">%1$s</xliff:g>ના રોજ <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-hi/strings.xml b/PermissionController/res/values-hi/strings.xml
index ced18bd1e..a4a9ab17d 100644
--- a/PermissionController/res/values-hi/strings.xml
+++ b/PermissionController/res/values-hi/strings.xml
@@ -32,11 +32,12 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"\"ऐप्लिकेशन इस्तेमाल करते समय\" अनुमति बनाए रखें"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"“सिर्फ़ इस बार अनुमति दें” को बनाए रखें"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"ज़्यादा जानकारी"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"सभी को अनुमति दें"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"सभी के लिए अनुमति दें"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"हमेशा के लिए सभी को अनुमति दें"</string>
- <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"फ़ोटो और वीडियो चुनें"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"सीमित ऐक्सेस देने की अनुमति दें"</string>
+ <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"चुनिंदा फ़ोटो और वीडियो को अनुमति दें"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"ज़्यादा फ़ोटो चुनें"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ज़्यादा डेटा न चुनें"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ज़्यादा फ़ोटो और वीडियो न चुनें"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"फिर भी अनुमति न दें"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"खारिज करें"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> में से <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ऐप्लिकेशन"</string>
<string name="app_permissions" msgid="3369917736607944781">"ऐप्लिकेशन की अनुमतियां"</string>
<string name="unused_apps" msgid="2058057455175955094">"इस्तेमाल नहीं किए गए ऐप्लिकेशन"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"इस ऐप्लिकेशन के पास किन फ़ोटो का ऐक्सेस होगा, इसमें बदलाव करें"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ऐसा कोई ऐप्लिकेशन नहींं है जिसका इस्तेमाल न किया गया हो"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"इस्तेमाल न किए जाने वाले ऐप"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"हाल ही में दी गई अनुमतियां"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"सभी अनुमतियां"</string>
<string name="other_permissions" msgid="2901186127193849594">"ऐप्लिकेशन को ये अनुमतियां भी दी गई हैं"</string>
<string name="permission_request_title" msgid="8790310151025020126">"अनुमति पाने का अनुरोध"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear पर ऐप्लिकेशन इंस्टॉल या अनइंस्टॉल नहीं किए जा सकते."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"चुनें कि &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को किन चीज़ों को ऐक्सेस करने की अनुमति दी जाए"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपडेट कर दिया गया है. चुनें कि इस ऐप्लिकेशन को किन चीज़ों को ऐक्सेस करने की अनुमति दी जाए."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"रद्द करें"</string>
@@ -196,7 +196,7 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"जगह की सटीक जानकारी का इस्तेमाल करें"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"जगह की सटीक जानकारी देने वाली सुविधा बंद होने पर, ऐप्लिकेशन आपकी अनुमानित जगह की जानकारी को ऐक्सेस कर सकते हैं"</string>
<string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g> की अनुमति"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"इस ऐप्लिकेशन के लिए <xliff:g id="PERM">%1$s</xliff:g> की अनुमति चाहिए"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"इस ऐप्लिकेशन के लिए, <xliff:g id="PERM">%1$s</xliff:g> ऐक्सेस करने की अनुमति चाहिए"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"<xliff:g id="APP">%1$s</xliff:g> को मिली सभी अनुमतियां देखें"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"इस अनुमति वाले सभी ऐप्लिकेशन देखें"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"असिस्टेंट माइक्रोफ़ोन के इस्तेमाल से जुड़ा डेटा दिखाएं"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ऐप्लिकेशन का इस्तेमाल न होने पर अनुमतियां हटाएं"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"अनुमतियां हटाएं और जगह खाली करें"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"इस्तेमाल न होने पर ऐप गतिविधि रोकें"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"इस्तेमाल नहीं हुआ ऐप्लिकेशन मैनेज करें"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ऐप्लिकेशन की अनुमतियां हटाएं, डिवाइस में कुछ समय के लिए रहने वाली फ़ाइलें मिटाएं, और सूचनाएं रोकें"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ऐप्लिकेशन की अनुमतियां हटाएं, डिवाइस में कुछ समय के लिए रहने वाली फ़ाइलें मिटाएं, सूचनाएं रोकें, और ऐप्लिकेशन संग्रहित करें"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"अगर इस ऐप्लिकेशन का इस्तेमाल कुछ महीनों तक नहीं किया गया, तो इसे दी गई अनुमतियां हटा दी जाएंगी. ऐसा आपके डेटा को सुरक्षित रखने के लिए किया जाएगा."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"अगर ऐप्लिकेशन कुछ महीनों से इस्तेमाल नहीं हुआ है, तो आपके डेटा को सुरक्षित रखने के लिए ये अनुमतियां हटा दी जाएंगी: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"जिन ऐप्लिकेशन का इस्तेमाल कुछ महीनों से नहीं हुआ है उन्हें दी गई अनुमतियां हटा दी गई हैं. ऐसा आपके डेटा को सुरक्षित रखने के लिए किया गया है."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"पिछली बार <xliff:g id="DATE">%s</xliff:g> को खोला गया था"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"अगर आप इस ऐप्लिकेशन को सभी फ़ाइलों को मैनेज करने की अनुमति देते हैं, तो यह ऐप्लिकेशन इस डिवाइस या इससे जुड़े दूसरे डिवाइस के स्टोरेज में मौजूद किसी भी फ़ाइल को ऐक्सेस कर सकता है, उनमें बदलाव कर सकता है, और उन्हें मिटा भी सकता है. यह ऐप्लिकेशन आपसे पूछे बिना फ़ाइलें ऐक्सेस कर सकता है."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"क्या आप इस ऐप्लिकेशन को इस डिवाइस या इससे जुड़े दूसरे डिवाइस के स्टोरेज में मौजूद फ़ाइलें ऐक्सेस करने, उनमें बदलाव करने, और उन्हें मिटाने की अनुमति देना चाहते हैं? यह ऐप्लिकेशन आपसे पूछे बिना फ़ाइलें ऐक्सेस कर सकता है."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"इस अनुमति वाले ऐप्लिकेशन <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"इस अनुमति वाले ऐप्लिकेशन यह कर सकते हैं: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"इसकी अनुमति वाले ऐप्लिकेशन, आपकी शारीरिक गतिविधियों की जानकारी ऐक्सेस कर सकते हैं. इसमें पैदल चलने, बाइक चलाने, गाड़ी चलाने, और कदमों की संख्या जैसी कई जानकारी शामिल है"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"इस अनुमति वाले ऐप्लिकेशन आपके कैलेंडर को ऐक्सेस कर सकते हैं"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"ऐसे ऐप्लिकेशन जिनके पास अनुमति है, वे फ़ोन में कॉल लॉग को पढ़ सकते हैं और लिख सकते हैं"</string>
@@ -397,10 +399,20 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं को पढ़ सकेगा और उन पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके कनेक्ट किए गए डिवाइस पर, आपके ऐप्लिकेशन का कॉन्टेंट चला पाएगा."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"यह सेवा आपके फ़ोन की फ़ोटो, मीडिया, और सूचनाओं को दूसरे डिवाइसों पर शेयर करती है."</string>
- <string name="role_notes_label" msgid="7451627001058089536">"नोट लेने का डिफ़ॉल्ट ऐप्लिकेशन"</string>
- <string name="role_notes_short_label" msgid="8796604147546125285">"नोट लेने के लिए ऐप्लिकेशन"</string>
- <string name="role_notes_description" msgid="8496852798616883551">"आपके डिवाइस पर नोट लेने की सुविधा देने वाले ऐप्लिकेशन"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"नोट लिखने का डिफ़ॉल्ट ऐप्लिकेशन"</string>
+ <string name="role_notes_short_label" msgid="8796604147546125285">"नोट लिखने के लिए ऐप्लिकेशन"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"आपके डिवाइस पर नोट लिखने की सुविधा देने वाले ऐप्लिकेशन"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"नोट"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"मौजूदा डिफ़ॉल्ट"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"फिर से न पूछें"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"डिफ़ॉल्ट के रूप में सेट करें"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"असिस्टेंट ऐप्लिकेशन का माइक्रोफ़ोन चालू है या बंद, इसकी सूचना दिखाएं"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"आवाज़ से डिवाइस का इस्तेमाल करने के लिए, माइक्रोफ़ोन का इस्तेमाल करते समय स्थिति बार में आइकॉन दिखाएं"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने डिवाइस में मौजूद फ़ोटो और मीडिया ऐक्सेस करने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"क्या &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"क्या &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> की जगह की जानकारी का डेटा ऐक्सेस करने की अनुमति देनी है?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"यह ऐप्लिकेशन शायद आपके डिवाइस की जगह की जानकारी हर समय ऐक्सेस करना चाहता है. उस समय भी जब आप इसका इस्तेमाल न कर रहे हों. "<annotation id="link">"सेटिंग में इसकी अनुमति दें."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; के लिए जगह की जानकारी का ऐक्सेस बदलना चाहते हैं?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; के लिए, आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; की जगह की जानकारी का ऐक्सेस बदलना है?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"यह ऐप्लिकेशन आपके डिवाइस की जगह की जानकारी हर समय ऐक्सेस करना चाहता है. उस समय भी जब आप इसका इस्तेमाल न कर रहे हों. "<annotation id="link">"सेटिंग में इसकी अनुमति दें."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"क्या आपको &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आस-पास मौजूद डिवाइसों को खोजने, उनसे कनेक्ट करने, और उनकी जगह की जानकारी का पता लगाने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; के आस-पास मौजूद डिवाइसों को खोजने, उनसे कनेक्ट करने, और उनकी जगह की जानकारी का पता लगाने की अनुमति देनी है?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"क्या आप &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आस-पास मौजूद डिवाइसों को खोजने, उनसे कनेक्ट करने, और उनकी जगह की जानकारी का पता लगाने की अनुमति देना चाहते हैं? "<annotation id="link">"सेटिंग में जाकर अनुमति दें."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"क्या <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> आपकी जगह की अनुमानित जानकारी के बजाय सटीक जानकारी ऐक्सेस करे?"</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_fineupgrade" msgid="3947134846432067176">"क्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; के लिए, <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> की जगह की जानकारी का ऐक्सेस अनुमानित से सटीक में बदलना है?"</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="9001956706241104626">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को &lt;b&gt;<xliff:g id="DEVICE">%2$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_calendar" msgid="1493150855673603806">"&lt;b&gt;<xliff:g id="APP_NAME">%1$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; को एसएमएस (मैसेज) भेजने और देखने की अनुमति देना चाहते हैं?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%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; को एसएमएस (मैसेज) भेजने और देखने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; में मौजूद फ़ोटो, मीडिया, और फ़ाइल का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को इस डिवाइस में मौजूद &lt;b&gt;फ़ोटो, वीडियो, संगीत, और ऑडियो&lt;/b&gt; का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को डिवाइस में मौजूद &lt;b&gt;फ़ोटो, वीडियो, संगीत, ऑडियो, और अन्य फ़ाइल&lt;/b&gt; का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को इस डिवाइस में मौजूद संगीत और ऑडियो ऐक्सेस करने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g> में मौजूद संगीत और ऑडियो का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को इस डिवाइस में मौजूद फ़ोटो और वीडियो ऐक्सेस करने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; में मौजूद फ़ोटो और वीडियो का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को इस डिवाइस पर मौजूद अन्य फ़ोटो और वीडियो का ऐक्सेस देना है?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; पर मौजूद अन्य फ़ोटो और वीडियो का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को ऑडियो रिकॉर्ड करने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; पर ऑडियो रिकॉर्ड करने की अनुमति देनी है?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"ऐप्लिकेशन सिर्फ़ तब ही ऑडियो रिकॉर्ड कर पाएगा, जब आप ऐप्लिकेशन इस्तेमाल कर रहे हों"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"क्या आप &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को ऑडियो रिकॉर्ड करने की अनुमति देना चाहते हैं?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; पर ऑडियो रिकॉर्ड करने की अनुमति देनी है?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"यह ऐप्लिकेशन हर समय ऑडियो रिकॉर्ड कर सकता है. ऐप्लिकेशन इस्तेमाल न करने पर भी ऐसा हो सकता है. "<annotation id="link">"सेटिंग में जाकर अनुमति दें."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"क्या आप &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; के लिए, माइक्रोफ़ोन के ऐक्सेस की अनुमति बदलना चाहते हैं?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; के लिए, आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; के माइक्रोफ़ोन का ऐक्सेस बदलना है?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"यह ऐप्लिकेशन हर समय ऑडियो रिकॉर्ड करना चाहता है, तब भी जब आप ऐप्लिकेशन इस्तेमाल न कर रहे हों. "<annotation id="link">"सेटिंग में जाकर अनुमति दें."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपनी शारीरिक गतिविधि की जानकारी पाने की अनुमति देना चाहते हैं?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; में मौजूद, आपकी शारीरिक गतिविधि की जानकारी का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को फ़ोटो खींचने और वीडियो रिकॉर्ड करने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; पर फ़ोटो लेने और वीडियो रिकॉर्ड करने की अनुमति देनी है?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"ऐप्लिकेशन सिर्फ़ तब ही तस्वीरें ले पाएगा और वीडियो रिकॉर्ड कर पाएगा, जब आप ऐप्लिकेशन इस्तेमाल कर रहे हों"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"क्या आप &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को तस्वीरें लेने और वीडियो रिकॉर्ड करने की अनुमति देना चाहते हैं?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; पर फ़ोटो लेने और वीडियो रिकॉर्ड करने की अनुमति देनी है?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"यह ऐप्लिकेशन हर समय तस्वीरें ले सकता है और वीडियो रिकॉर्ड कर सकता है. ऐप्लिकेशन इस्तेमाल न करने पर भी ऐसा हो सकता है. "<annotation id="link">"सेटिंग में जाकर अनुमति दें."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"क्या आप &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; के लिए, कैमरे के ऐक्सेस की अनुमति बदलना चाहते हैं?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; के लिए, आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; के कैमरे का ऐक्सेस बदलना है?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"यह ऐप्लिकेशन हर समय तस्वीरें लेना और वीडियो रिकॉर्ड करना चाहता है, तब भी जब आप ऐप्लिकेशन इस्तेमाल न कर रहे हों. "<annotation id="link">"सेटिंग में जाकर अनुमति दें."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने फ़ोन के काॅल लाॅग को ऐक्सेस करने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; में मौजूद, कॉल लॉग का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को फ़ोन कॉल करने और उन्हें मैनेज करने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g> से फ़ोन कॉल करने और उन्हें मैनेज करने का ऐक्सेस देना है?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने स्वास्थ्य से जुड़ी ज़रूरी जानकारी इस्तेमाल करने की अनुमति देनी है?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; में मौजूद, शरीर के बारे में जानकारी देने वाले सेंसर डेटा का ऐक्सेस देना है?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"यह ऐप्लिकेशन, आपके शरीर के बारे में ज़रूरी जानकारी देने वाले सेंसर डेटा को हमेशा ऐक्सेस करने की अनुमति मांगता है. यह अनुमति उस समय के लिए भी मांगी जाती है जिस समय ऐप्लिकेशन का इस्तेमाल न हो रहा हो. यह अनुमति देने के लिए, "<annotation id="link">"सेटिंग पर जाएं."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने शरीर के बारे में जानकारी देने वाले लक्षणों के सेंसर डेटा को ऐक्सेस करने की अनुमति दें?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; में मौजूद, शरीर के बारे में जानकारी देने वाले सेंसर डेटा का ऐक्सेस देना है?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"इस ऐप्लिकेशन का इस्तेमाल न किए जाने पर भी, इसे बॉडी सेंसर के डेटा को हमेशा ऐक्सेस करने की अनुमति देने के लिए, "<annotation id="link">"सेटिंग पर जाएं."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"क्या इस्तेमाल के दौरान, &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को बॉडी सेंसर के डेटा का ऐक्सेस देते रहना है?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"क्या इस्तेमाल के दौरान, &lt;b&gt;<xliff:g id="DEVICE">%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_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को सूचनाएं भेजने की अनुमति दें?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"क्या &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को आपके &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; पर सूचनाएं भेजने की अनुमति देनी है?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"कंट्रोल की गई अनुमतियां"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> के पास, डिवाइस की जगह की जानकारी का ऐक्सेस है"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"आपके संगठन ने <xliff:g id="APP_NAME">%1$s</xliff:g> को, डिवाइस की जगह की जानकारी का ऐक्सेस दिया है"</string>
@@ -582,13 +621,14 @@
<string name="perm_toggle_description" msgid="7801326363741451379">"ऐप्लिकेशन और सेवाओं के लिए"</string>
<string name="mic_toggle_description" msgid="9163104307990677157">"ऐप्लिकेशन और सेवाओं के लिए. इस सेटिंग के बंद होने पर भी, माइक्रोफ़ोन डेटा को शेयर किया जा सकता है. ऐसा तब होता है, जब किसी आपातकालीन नंबर पर कॉल किया जाता है."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"उन ऐप्लिकेशन और सेवाओं को देखें जिनके पास जगह की जानकारी का ऐक्सेस है"</string>
- <string name="show_clip_access_notification_title" msgid="5168467637351109096">"क्लिपबोर्ड का डेटा ऐक्सेस किए जाने पर मैसेज पाएं"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"जब कोई ऐप्लिकेशन आपके कॉपी किए गए टेक्स्ट, इमेज या अन्य कॉन्टेंट को ऐक्सेस करे, तो मैसेज से इसकी सूचना पाएं"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"क्लिपबोर्ड का डेटा ऐक्सेस किए जाने पर मैसेज दिखाएं"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"जब कोई ऐप्लिकेशन आपके कॉपी किए गए टेक्स्ट, इमेज या अन्य कॉन्टेंट को ऐक्सेस करे, तो मैसेज दिखाएं"</string>
<string name="show_password_title" msgid="2877269286984684659">"पासवर्ड दिखाएं"</string>
<string name="show_password_summary" msgid="1110166488865981610">"टाइप करते समय वर्ण दिखाएं"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"इस ऐप्लिकेशन ने बताया है कि यह जगह की जानकारी का डेटा, तीसरे पक्ष के साथ शेयर कर सकता है"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"डेटा शेयर करने का तरीका और जगह की जानकारी"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"डेटा शेयर करने के तरीके की जानकारी यहां से मिलती है:"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"डेवलपर ने डिवाइस बनाने वाली कंपनी को, इस ऐप्लिकेशन के डेटा शेयर करने के तरीकों की जानकारी दी है. डेवलपर समय-समय पर इस जानकारी को अपडेट कर सकता है."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"डेवलपर ने "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" पर, इस ऐप्लिकेशन के डेटा शेयर करने के तरीकों की जानकारी दी है. डेवलपर समय-समय पर इस जानकारी को अपडेट कर सकता है."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ऐप जगह की जानकारी का डेटा इनके लिए शेयर करता है:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"डेटा शेयर करने के अलग-अलग तरीके"</string>
@@ -606,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"डेटा की सुरक्षा"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"जगह की जानकारी का डेटा शेयर किया जा सकता है"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"इस ऐप्लिकेशन में बताया गया है कि यह तीसरे पक्ष के साथ जगह की जानकारी का डेटा शेयर कर सकता है"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"यह लिंक नहीं खोला जा सका"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"जगह की जानकारी का डेटा शेयर करने के तरीके के बारे में अपडेट"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"ऐसे ऐप्लिकेशन देखें जिन्होंने आपकी जगह की जानकारी के डेटा को शेयर करने का तरीका बदल दिया है"</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"ऐसे ऐप्लिकेशन देखें जिन्होंने शायद आपकी जगह की जानकारी के डेटा को शेयर करने का तरीका बदल दिया है"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"इन ऐप्लिकेशन ने आपकी जगह की जानकारी के डेटा को शेयर करने का तरीका बदल दिया है. ऐसा हो सकता है कि ये ऐप्लिकेशन पहले जगह की जानकारी का डेटा शेयर न करते हों या फिर अब विज्ञापन या मार्केटिंग के लिए यह डेटा शेयर किया हो."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"इन ऐप्लिकेशन के डेवलपर ने किसी ऐप स्टोर पर डेटा शेयर करने के उनके तरीकों की जानकारी बताई है. वे समय-समय पर इस जानकारी को अपडेट कर सकते हैं.\n\nडेटा शेयर करने के तरीके अलग-अलग हो सकते हैं. ये आपकी जगह, उम्र, ऐप्लिकेशन के वर्शन, और उसके इस्तेमाल के हिसाब से तय किए जाते हैं."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"डेटा शेयर करने की नीतियों के बारे में जानें"</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"डेटा शेयर करने के तरीके के बारे में अपडेट"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"कुछ ऐप्लिकेशन ने आपकी जगह की जानकारी के डेटा को शेयर करने का तरीका बदल दिया है"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"सेटिंग"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g> को ऐक्सेस किया गया"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"<xliff:g id="TIME_DATE">%1$s</xliff:g> को कल ऐक्सेस किया गया था"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g> को ऐक्सेस किया गया"</string>
</resources>
diff --git a/PermissionController/res/values-hr-v33/strings.xml b/PermissionController/res/values-hr-v33/strings.xml
index 648afedea..a50e58158 100644
--- a/PermissionController/res/values-hr-v33/strings.xml
+++ b/PermissionController/res/values-hr-v33/strings.xml
@@ -30,10 +30,9 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Više upozorenja"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Odbačena upozorenja"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Proširite i pogledajte još jedno upozorenje}one{Proširite i pogledajte još # upozorenje}few{Proširite i pogledajte još # upozorenja}other{Proširite i pogledajte još # upozorenja}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Upozorenje. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Radnja je dovršena"</string>
- <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Provjerite postavke koje mogu vašem uređaju dodati zaštitu"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Provjerite postavke kojima možete dodatno zaštititi svoj uređaj"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Brze postavke sigurnosti i privatnosti"</string>
<string name="safety_center_qs_close_button" msgid="1352313308176244599">"Zatvori"</string>
<string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Opcije proširivanja i prikazivanja"</string>
diff --git a/PermissionController/res/values-hr-v34/strings.xml b/PermissionController/res/values-hr-v34/strings.xml
index 822862be3..74a1d7d1e 100644
--- a/PermissionController/res/values-hr-v34/strings.xml
+++ b/PermissionController/res/values-hr-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Sigurnost i privatnost"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kontrole"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Upravljajte pristupom aplikacija podacima o zdravlju"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Upravljajte kojim podacima o zdravlju pristupaju aplikacije"</string>
<string name="location_settings" msgid="8863940440881290182">"Pristup lokaciji"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"Za aplikacije i usluge. Ako je ta postavka isključena, podaci mikrofona i dalje se mogu dijeliti kad nazovete broj hitne službe"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Za aplikacije i usluge"</string>
diff --git a/PermissionController/res/values-hr/strings.xml b/PermissionController/res/values-hr/strings.xml
index 3f0121378..71beb6cb4 100644
--- a/PermissionController/res/values-hr/strings.xml
+++ b/PermissionController/res/values-hr/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Više podataka"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Dopusti sve"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Uvijek dopusti sve"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Omogućivanje ograničenog pristupa"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Odaberite slike i videozapise"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Odaberite više"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nemojte odabrati više"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nemoj dopustiti"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ipak nemoj dopustiti"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Odbaci"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> od <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti sljedeće: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Želite li uvijek dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sljedeće: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Dopuštate li da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; može <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Dopuštate li da aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; može <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Samo dok se aplikacija koristi"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Uvijek"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Nemoj dopustiti i više ne pitaj"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikacije"</string>
<string name="app_permissions" msgid="3369917736607944781">"Dopuštenja za aplikacije"</string>
<string name="unused_apps" msgid="2058057455175955094">"Nekorištene aplikacije"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Uređivanje odabranih fotografija za ovu aplikaciju"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nema nekorištenih aplikacija"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Nema nekorištenih aplikacija"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nedavne odluke o dopuštenjima"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Sva dopuštenja"</string>
<string name="other_permissions" msgid="2901186127193849594">"Ostale mogućnosti aplikacije"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Zahtijevanje dopuštenja"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Radnje instaliranja i deinstaliranja nisu podržane na Wearu."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Odaberite čemu će &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; moći pristupiti"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ažurirana je. Odaberite čemu će moći pristupiti."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Otkaži"</string>
@@ -126,7 +126,7 @@
<string name="app_name_unknown" msgid="1319665005754048952">"Nepoznato"</string>
<string name="permission_usage_title" msgid="1568233336351734538">"Nadzorna ploča za privatnost"</string>
<string name="auto_permission_usage_summary" msgid="7335667266743337075">"Prikaz aplikacija koje su nedavno upotrebljavale dopuštenja"</string>
- <string name="permission_group_usage_title" msgid="2595013198075285173">"Upotreba grupe dopuštenja: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
+ <string name="permission_group_usage_title" msgid="2595013198075285173">"Upotreba dopuštenja: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Pogledajte ostala dopuštenja"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
<string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> i još <xliff:g id="NUM">%3$s</xliff:g>"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Ukloni dopuštenja ako se aplikacija ne upotrebljava"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Ukloni dopuštenja i oslobodi prostor"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pauziraj aktivnosti u aplikacijama ako se ne koriste"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Upravljajte nekorištenom aplikacijom"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Uklonite dopuštenja, izbrišite privremene datoteke i zaustavite obavijesti"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Uklonite dopuštenja, izbrišite privremene datoteke, zaustavite obavijesti i arhivirajte aplikaciju"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Kako bi se vaši podaci zaštitili, dopuštenja za ovu aplikaciju uklonit će se ako se aplikacija ne upotrebljava nekoliko mjeseci."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Kako bi se vaši podaci zaštitili, ako se aplikacija ne upotrebljava nekoliko mjeseci, uklonit će se sljedeća dopuštenja: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Radi zaštite vaših podataka uklonjena su dopuštenja aplikacijama koje nekoliko mjeseci niste upotrebljavali."</string>
@@ -356,7 +358,7 @@
<string name="role_browser_request_title" msgid="2895200507835937192">"Želite li postaviti aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g> kao zadanu aplikaciju za preglednik?"</string>
<string name="role_browser_request_description" msgid="5888803407905985941">"Nije potrebno nijedno dopuštenje"</string>
<string name="role_dialer_label" msgid="1100224146343237968">"Zadana aplikacija telefona"</string>
- <string name="role_dialer_short_label" msgid="7186888549465352489">"Aplikacija telefona"</string>
+ <string name="role_dialer_short_label" msgid="7186888549465352489">"Aplikacija za pozive"</string>
<string name="role_dialer_description" msgid="8768708633696539612">"Aplikacije koje vam omogućuju upućivanje i primanje telefonskih poziva na uređaju"</string>
<string name="role_dialer_request_title" msgid="5959618560705912058">"Želite li postaviti aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g> kao svoju zadanu aplikaciju telefona?"</string>
<string name="role_dialer_request_description" msgid="6288839625724909320">"Aplikacija će dobiti pristup vašoj kameri, kontaktima, mikrofonu, telefonu i SMS-ovima"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikacija za bilješke"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplikacije koje vam omogućuju vođenje bilješki na uređaju"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"napomene"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Trenutačna zadana"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Više me ne pitaj"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Postavi kao zadano"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Prikaz otkrivanja okidača asistenta"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Prikazuje ikonu na traci statusa kada se za aktiviranje glasovne pomoći upotrebljava mikrofon"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fotografijama i medijima na vašem uređaju?"</string>
- <string name="permgrouprequest_contacts" msgid="8391550064551053695">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa vašim kontaktima?"</string>
- <string name="permgrouprequest_location" msgid="6990232580121067883">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa fotografijama i medijima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_contacts" msgid="8391550064551053695">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da pristupa vašim kontaktima?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa vašim kontaktima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_location" msgid="6990232580121067883">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji uređaja &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikacija će imati pristup lokaciji samo dok upotrebljavate aplikaciju"</string>
- <string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da pristupa lokaciji ovog uređaja?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa lokaciji vašeg uređaja &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Ova aplikacija možda će uvijek htjeti imati pristup vašoj lokaciji, čak i kad je ne koristite. "<annotation id="link">"Dopustite u postavkama."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Želite li promijeniti pristup lokaciji za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Promijeniti pristup lokaciji za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Ova aplikacija želi uvijek pristupati vašoj lokaciji, čak i kad je ne koristite. "<annotation id="link">"Dopustite u postavkama."</annotation></string>
- <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; traži uređaje u blizini, poveže se s njima i odredi njihov približni položaj?"</string>
+ <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da traži uređaje u blizini, povezuje se s njima i određuje njihov približni položaj?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pronađe uređaje u blizini i njihov relativan položaj i poveže se s njima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; traži uređaje u blizini, poveže se s njima i odredi njihov približni položaj? "<annotation id="link">"Dopustite u postavkama."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Želite li aplikaciji <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> promijeniti pristup iz približne lokacije u točnu?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Promijeniti aplikaciji <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> pristup lokaciji na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; iz približne u točnu?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa približnoj lokaciji ovog uređaja?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa približnoj lokaciji vašeg uređaja &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Točno"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Približno"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa vašem kalendaru?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa vašem kalendaru na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da šalje i pregledava SMS poruke?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje i pregledava SMS poruke na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa fotografijama, medijima i datotekama na vašem uređaju?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa fotografijama, medijima i datotekama na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup &lt;b&gt;foto/video/audiodatotekama i glazbi&lt;/b&gt; na ovom uređaju?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Dopustiti apl. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup &lt;b&gt;foto/video/audio i drugim datotekama te glazbi&lt;/b&gt; na uređaju?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup glazbi i audiodatotekama na ovom uređaju?"</string>
- <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup fotografijama i videozapisima na ovom uređaju?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup većem broju fotografija i videozapisa na ovom uređaju?"</string>
- <string name="permgrouprequest_microphone" msgid="2825208549114811299">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima audiozapise?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa glazbi i audiodatotekama na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti pristup fotografijama i videozapisima na ovom uređaju?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa fotografijama i videozapisima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti pristup većem broju fotografija i videozapisa na ovom uređaju?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa većem broju fotografija i videozapisa na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_microphone" msgid="2825208549114811299">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da snima audiozapise?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima audiozapise na vašem uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikacija će moći snimati audiozapise samo dok je upotrebljavate"</string>
- <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima audiozapise?"</string>
+ <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da snima audiozapise?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima audiozapise na vašem uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Aplikacija će možda snimati audiozapise u svakom trenutku, čak i kad je ne upotrebljavate. "<annotation id="link">"Dopustite u postavkama."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Želite li promijeniti pristup mikrofonu za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Promijeniti pristup mikrofonu za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Aplikacija traži dopuštenje za snimanje audiozapisa u svakom trenutku, čak i kad je ne upotrebljavate. "<annotation id="link">"Dopustite u postavkama."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Želite li dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa vašoj tjelesnoj aktivnosti?"</string>
- <string name="permgrouprequest_camera" msgid="5123097035410002594">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima fotografije i videozapise?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa vašoj tjelesnoj aktivnosti na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_camera" msgid="5123097035410002594">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da snima fotografije i videozapise?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima fotografije i videozapise na vašem uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikacija će moći snimati fotografije i videozapise samo dok je upotrebljavate"</string>
- <string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da snima fotografije i videozapise?"</string>
+ <string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da snima fotografije i videozapise?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snima fotografije i videozapise na vašem uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Aplikacija će možda snimati fotografije i videozapise u svakom trenutku, čak i kad je ne upotrebljavate. "<annotation id="link">"Dopustite u postavkama."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Želite li promijeniti pristup kameri za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Promijeniti pristup kameri za aplikaciju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Aplikacija traži dopuštenje za snimanje fotografija i videozapisa u svakom trenutku, čak i kad je ne upotrebljavate. "<annotation id="link">"Dopustite u postavkama."</annotation></string>
- <string name="permgrouprequest_calllog" msgid="2065327180175371397">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa zapisnicima poziva vašeg telefona?"</string>
- <string name="permgrouprequest_phone" msgid="1829234136997316752">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da upućuje telefonske pozive i upravlja njima?"</string>
+ <string name="permgrouprequest_calllog" msgid="2065327180175371397">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da pristupa zapisnicima poziva vašeg telefona?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa zapisnicima poziva vašeg telefona na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_phone" msgid="1829234136997316752">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da upućuje telefonske pozive i upravlja njima?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; upućuje telefonske pozive i upravlja njima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa podacima senzora o vašim vitalnim znakovima?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa podacima senzora o vašim vitalnim znakovima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Aplikacija želi uvijek pristupati podacima senzora o vašim vitalnim znakovima, čak i kad je ne upotrebljavate. Da biste unijeli tu promjenu, "<annotation id="link">"otvorite postavke"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupa podacima senzora o vašim vitalnim znakovima?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Dopustiti da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristupa podacima senzora o vašim vitalnim znakovima na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Da biste omogućili aplikaciji da uvijek pristupa podacima s biometrijskih senzora, čak i kada je ne upotrebljavate, "<annotation id="link">"otvorite postavke."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Nastaviti dopuštati aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup podacima s biometrijskih senzora dok je upotrebljavate?"</string>
- <string name="permgrouprequest_notifications" msgid="6396739062335106181">"Želite li dopustiti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da vam šalje obavijesti?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Nastaviti dopuštati da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tijekom upotrebe pristupa podacima biometrijskih senzora na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_notifications" msgid="6396739062335106181">"Želite li aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da vam šalje obavijesti?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Dopustiti da vam &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje obavijesti na uređaju &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontrolirana dopuštenja"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ima pristup lokaciji"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Vaša organizacija dopušta da <xliff:g id="APP_NAME">%1$s</xliff:g> pristupa vašoj lokaciji"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Ostala dopuštenja"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Dopuštenja koja upotrebljava sustav"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Dopuštenja koja upotrebljavaju samo aplikacije sustava."</string>
@@ -549,7 +586,7 @@
<string name="active_call_usage_qs" msgid="8559974395932523391">"Koristi telefonski poziv"</string>
<string name="recent_call_usage_qs" msgid="743044899599410935">"Nedavno korišteno tijekom telefonskog poziva"</string>
<string name="active_app_usage_qs" msgid="4063912870936464727">"Koristi aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="recent_app_usage_qs" msgid="6650259601306212327">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="recent_app_usage_qs" msgid="6650259601306212327">"Nedavno je koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="active_app_usage_1_qs" msgid="4325136375823357052">"Koristi aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="active_app_usage_2_qs" msgid="6107866785243565283">"Koristi aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
@@ -585,12 +622,13 @@
<string name="mic_toggle_description" msgid="9163104307990677157">"Za aplikacije i usluge. Ako je ta postavka isključena, podaci mikrofona i dalje se mogu dijeliti kad nazovete broj hitne službe."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Pogledajte aplikacije i usluge koje imaju pristup lokaciji"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Prikaži pristup međuspremniku"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Primite poruku kad aplikacije pristupe tekstu, slikama ili drugom kopiranom sadržaju"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Prikazuje se poruka kad aplikacije pristupe tekstu, slikama ili drugom kopiranom sadržaju"</string>
<string name="show_password_title" msgid="2877269286984684659">"Prikaži zaporke"</string>
- <string name="show_password_summary" msgid="1110166488865981610">"Nakratko prikaži znakove tijekom unosa"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Znakovi se nakratko prikazuju tijekom unosa"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Aplikacija je navela da može dijeliti podatke o lokaciji s trećim stranama"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Dijeljenje podataka i lokacije"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Tko određuje kako se podaci dijele"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Razvojni programer pružio je proizvođaču ovog uređaja informacije o načinu na koji ova aplikacija dijeli podatke. Razvojni programer može s vremenom ažurirati te informacije."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Razvojni programer je usluzi "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" poslao informacije o načinu na koji aplikacija dijeli podatke. Razvojni programer može s vremenom ažurirati informacije."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Aplikacija može dijeliti podatke o lokaciji radi:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Način dijeljenja može se razlikovati"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Sigurnost podataka"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Podaci o lokaciji mogu se dijeliti"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Aplikacija je navela da vaše podatke o lokaciji može dijeliti s trećim stranama"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Vezu nije moguće otvoriti"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Ažuriranja o dijeljenju podataka za lokaciju"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Pregledajte aplikacije koje su promijenile način na koji mogu dijeliti vaše podatke o lokaciji"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Ove su aplikacije promijenile način na koji mogu dijeliti vaše podatke o lokaciji. Ranije ih možda nisu dijelile ili ih sada mogu dijeliti u svrhe oglašavanja ili marketinga."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Ažuriranja o dijeljenju podataka"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Neke su aplikacije promijenile način na koji mogu dijeliti vaše podatke o lokaciji"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Postavke"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Pristupljeno: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Pristupljeno jučer: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Pristupljeno: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-hu-v33/strings.xml b/PermissionController/res/values-hu-v33/strings.xml
index d906e63d2..ee454fc12 100644
--- a/PermissionController/res/values-hu-v33/strings.xml
+++ b/PermissionController/res/values-hu-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Több értesítés"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Elvetett értesítések"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Ha kibontja, még egy értesítést láthat}other{Ha kibontja, még # értesítést láthat}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Figyelmeztetés. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Művelet befejezve"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Tekintse át a beállításokat, amelyek növelhetik eszköze védelmét"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Biztonsági és adatvédelmi gyorsbeállítások"</string>
diff --git a/PermissionController/res/values-hu/strings.xml b/PermissionController/res/values-hu/strings.xml
index e1bd29599..e0bb8c5bb 100644
--- a/PermissionController/res/values-hu/strings.xml
+++ b/PermissionController/res/values-hu/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Bővebben"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Összes engedélyezése"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Összes engedélyezése mindig"</string>
- <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Jelöljön ki fotókat, videókat"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Korlátozott hozzáférés engedélyezése"</string>
+ <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Fotók és videók kijelölése"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Több kijelölése"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ne válasszon ki többet"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nem jelölök ki többet"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Semmiképpen se engedélyezze"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Elvetés"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>/<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>."</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Alkalmazások"</string>
<string name="app_permissions" msgid="3369917736607944781">"Alkalmazásengedélyek"</string>
<string name="unused_apps" msgid="2058057455175955094">"Nem használt alkalmazások"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Az alkalmazáshoz kiválasztott fotók módosítása"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nincsenek nem használt appok"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 nem használt alkalmazás"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Friss engedélyezési döntések"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Az összes engedély"</string>
<string name="other_permissions" msgid="2901186127193849594">"Egyéb alkalmazáslehetőségek"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Engedélykérés"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"A Wear nem támogatja a telepítés/eltávolítás műveletet."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Válassza ki, hogy a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mihez férjen hozzá"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"A(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; frissítése megtörtént. Válassza ki, hogy mihez férjen hozzá ez az alkalmazás."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Mégse"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Engedélyek eltávolítása, ha nem használja az alkalmazást"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Engedélytörlés és tárhely-felszabadítás"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"App szüneteltetése, ha nem használja"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Használaton kívüli alkalmazás kezelése"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Engedélyek eltávolítása, ideiglenes fájlok törlése és értesítések leállítása"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Engedélyek eltávolítása, ideiglenes fájlok törlése, értesítések leállítása és az alkalmazás archiválása"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Az adatok védelme érdekében az ennek az alkalmazásnak adott engedélyek visszavonásra kerülnek, ha néhány hónapon át nem használja az alkalmazást."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Ha néhány hónapon át nem használja az alkalmazást, az adatok védelme érdekében a rendszer visszavonja a következő engedélyeket: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Az adatok védelme érdekében a rendszer eltávolította a néhány hónapja nem használt alkalmazások engedélyeit."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Jegyzetkészítő alkalmazás"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Alkalmazások, amelyek lehetővé teszik, hogy jegyzeteket készítsen az eszközén."</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"jegyzetek"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Aktuális alapérték"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ne jelenjen meg többé"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Alapértelmezett"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Segédet aktiváló parancsok észlelésének megjelenítése"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Ikon megjelenítése az állapotsoron, amikor a rendszer a mikrofont használja a hangsegéd aktiválásához"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"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 és médiatartalmakhoz?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"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 fotókhoz és médiatartalmakhoz itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"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 névjegyekhez?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"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 névjegyeihez ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"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 helyadataihoz?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"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 következő eszköz helyadataihoz: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Az alkalmazás csak akkor férhet hozzá a helyadatokhoz, amikor Ön használja az alkalmazást"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"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 helyadataihoz?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"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 következő eszköz helyadataihoz: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Előfordulhat, hogy az alkalmazás akkor is hozzá szeretne férni a helyadataihoz, amikor nem használja az alkalmazást. "<annotation id="link">"A beállításokban engedélyezheti."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Megváltoztatja a helyadatokhoz való hozzáférést a következő számára: &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Módosítja a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; helyadatokhoz való hozzáférését ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Az alkalmazás akkor is hozzá szeretne férni az Ön helyadataihoz, amikor Ön nem használja az alkalmazást. "<annotation id="link">"A beállításokban engedélyezheti."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"A(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; megkeresheti a közeli eszközöket, meghatározhatja relatív pozíciójukat, és csatlakozhat hozzájuk?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Megtalálhatja a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; a közeli eszközöket, csatlakozhat hozzájuk, és meghatározhatja a relatív pozíciójukat itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"A(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; megkeresheti a közeli eszközöket, meghatározhatja relatív pozíciójukat, és csatlakozhat hozzájuk? "<annotation id="link">"Engedélyezés a beállításokban."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Megváltoztatja a(z) <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> helyhozzáférését hozzávetőlegesről pontosra?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Módosítja a(z) <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> számára biztosított helyhozzáférést hozzávetőlegesről pontosra ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"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 hozzávetőleges helyadataihoz?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"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 következő hozzávetőleges helyéhez: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Pontos"</string>
<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="3103987548035171850">"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 itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&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_device_aware_sms" msgid="7212083972999874267">"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üldjön és tekintsen meg itt: &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"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 fotókhoz, médiatartalmakhoz és fájlokhoz itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Hozzáférhet a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; az eszközön lévő &lt;b&gt;fotókhoz, videókhoz, zenékhez és hangfájlokhoz&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Hozzáférhet a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; az eszközön tárolt &lt;b&gt;fotókhoz, hang-, videó- és egyéb fájlokhoz&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Hozzáférhet a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; az eszközön tárolt zenékhez és egyéb hanganyagokhoz?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"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 zenékhez ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Hozzáférhet a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; az eszközön tárolt fotókhoz és videókhoz?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"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 fotókhoz és a videókhoz itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"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 további fotókhoz és videókhoz?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"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 további képekhez és videókhoz itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy hangfelvételt készíthessen?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy hangfelvételt készítsen ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Az alkalmazás csak akkor tud majd hangfelvételt készíteni, amikor Ön használja az alkalmazást."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy hangfelvételt készíthessen?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy hangfelvételt készítsen ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Lehet, hogy az alkalmazás akkor is szeretne hangfelvételt készíteni, amikor Ön nem használja az alkalmazást. "<annotation id="link">"A beállításokban engedélyezheti."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Módosítja a mikrofonhoz való hozzáférést a következő számára: &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Módosítja a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mikrofonhoz való hozzáférését ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Az alkalmazás akkor is szeretne hangfelvételt készíteni, amikor Ön nem használja az alkalmazást. "<annotation id="link">"A beállításokban engedélyezheti."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára a testmozgási adataihoz való hozzáférést?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"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 testmozgásadatokhoz itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy képeket és videókat készíthessen?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy képeket és videót készítsen ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Az alkalmazás csak akkor tud majd fényképeket és videókat készíteni, amikor Ön használja az alkalmazást."</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy fényképeket és videókat készíthessen?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy képeket és videót készítsen ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Lehet, hogy az alkalmazás akkor is szeretne fotókat és videókat készíteni, amikor Ön nem használja az alkalmazást. "<annotation id="link">"A beállításokban engedélyezheti."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Módosítja a kamerához való hozzáférést a következő számára: &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Módosítja a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kamerához való hozzáférését ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Az alkalmazás akkor is szeretne fényképeket és videókat készíteni, amikor Ön nem használja az alkalmazást. "<annotation id="link">"A beállításokban engedélyezheti."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Engedélyezi, hogy a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; hozzáférjen az Ön hívásnaplóihoz?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"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 telefon hívásnaplóihoz itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy hívásokat indíthasson és kezelhessen?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy hívást indítson, és kezelje a hívásokat itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"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 életjelekkel kapcsolatos szenzoradatokhoz?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"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 életfunkciókkal kapcsolatos szenzoradatokhoz itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Ez az alkalmazás akkor is hozzá szeretne férni az életjelekkel kapcsolatos szenzoradatokhoz, ha nincs használatban. A módosításhoz "<annotation id="link">"lépjen a beállításokhoz."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"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 életjelekkel kapcsolatos szenzoradatokhoz?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"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 életfunkció-adatokhoz itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Ha engedélyezni szeretné, hogy ez az alkalmazás mindig hozzáférjen a testérzékelők adataihoz (még akkor is, amikor nem használja), "<annotation id="link">"lépjen a beállításokhoz"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Továbbra is hozzáférhessen használat közben a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; alkalmazás a testérzékelők adataihoz?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"A(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; továbbra is hozzáférhet a testérzékelők adataihoz használat közben itt: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy értesítéseket küldjön Önnek?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy értesítéseket küldjön Önnek ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Szabályozott engedélyek"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> hozzáfér a tartózkodási helyhez"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Szervezete lehetővé teszi a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> számára, hogy hozzáférjen az Ön tartózkodási helyéhez"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"További engedélyek"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Rendszer által használt engedélyek"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Csak rendszeralkalmazások által használt engedélyek."</string>
@@ -523,7 +560,7 @@
<string name="blocked_mic_summary" msgid="8960466941528458347">"Segélyhívó szám hívásakor a rendszer továbbra is megoszthatja a mikrofonadatokat."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Módosítás"</string>
<string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Biztonság és adatvédelem"</string>
- <string name="safety_center_rescan_button" msgid="4517514567809409596">"Keresés az eszközön"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Eszközvizsgálat"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Elvetés"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Elveti ezt az értesítést?"</string>
<string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Bármikor áttekintheti biztonsági és adatvédelmi beállításait, és növelheti a védelmet"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Az alkalmazás jelezte, hogy megoszthat helyadatokat harmadik felekkel"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Adatmegosztás és hely"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Az adatmegosztással kapcsolatos információ forrása"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"A fejlesztő információt adott meg az eszköz gyártójának arról, hogy az alkalmazás minként oszt meg adatokat. A fejlesztő idővel módosíthatja ezt az információt."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"A fejlesztő információt adott meg "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" számára arról, hogy az alkalmazás miként oszt meg adatokat. A fejlesztő idővel módosíthatja ezt az információt."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Az app helyadatokat oszthat meg az alábbi célból:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Az adatmegosztás változik"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Adatbiztonság"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Az alkalmazás megoszthat helyadatokat"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Az alkalmazás jelezte, hogy megoszthatja az Ön helyadatait harmadik felekkel"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Nem sikerült megnyitni a linket"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"A helyadatok megosztását érintő frissítések"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Áttekintheti az appokat, amelyek módosították, hogy miként oszthatják meg a helyadatait"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Ezek az alkalmazások módosították, hogy miként oszthatják meg az Ön helyadatait. Előfordulhat, hogy korábban nem osztották meg az adatokat, illetve ezentúl hirdetési vagy marketing célokra oszthatják meg őket."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Adatmegosztási frissítések"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Egyes alkalmazások módosították, hogy miként oszthatják meg az Ön helyadatait"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Beállítások"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Hozzáférés: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Hozzáférés: tegnap, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Hozzáférés: <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-hy-v33/strings.xml b/PermissionController/res/values-hy-v33/strings.xml
index d8836f16a..6efb079ef 100644
--- a/PermissionController/res/values-hy-v33/strings.xml
+++ b/PermissionController/res/values-hy-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Այլ ծանուցումներ"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Անտեսված ծանուցումներ"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Ծավալել և տեսնել ևս մեկ զգուշացում}one{Ծավալել և տեսնել ևս # զգուշացում}other{Ծավալել և տեսնել ևս # զգուշացում}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Ծանուցում։ <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Գործողությունն ավարտված է"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Ծանոթացեք կարգավորումներին, որոնց օգնությամբ կարող եք բարձրացնել ձեր սարքի անվտանգության մակարդակը"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Անվտանգության և գաղտնիության արագ կարգավորումներ"</string>
diff --git a/PermissionController/res/values-hy/strings.xml b/PermissionController/res/values-hy/strings.xml
index f1aa222cc..2abca24fd 100644
--- a/PermissionController/res/values-hy/strings.xml
+++ b/PermissionController/res/values-hy/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Մանրամասն"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Թույլատրել բոլորը"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Միշտ թույլատրել բոլորը"</string>
- <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Ընտրել լուսանկարներ և տեսանյութեր"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Տրամադրել սահմանափակ հասանելիություն"</string>
+ <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Կոնկրետ լուսանկարներ և տեսանյութեր"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Ընտրել այլ տարրեր"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Չընտրել ավելի շատ"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Չընտրել այլ լուսանկարներ"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Միևնույն է չթույլատրել"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Փակել"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Հավելվածներ"</string>
<string name="app_permissions" msgid="3369917736607944781">"Հավելվածների թույլտվություններ"</string>
<string name="unused_apps" msgid="2058057455175955094">"Չօգտագործվող հավելվածներ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Փոխել այս հավելվածի համար ընտրված լուսանկարները"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Չօգտագործվող հավելվածներ չկան"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Չօգտագործվող հավելվածներ չկան"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Թույլտվության որոշումներ"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Բոլոր թույլտվությունները"</string>
<string name="other_permissions" msgid="2901186127193849594">"Էլ ինչ կարող է անել հավելվածը"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Թույլտվության հարցում"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Տեղադրման/հեռացման գործողությունները Android Wear-ում չեն աջակցվում:"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Ընտրեք՝ ինչ թույլտվություններ եք ուզում տրամադրել &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածը թարմացվել է: Ընտրեք՝ ինչ թույլտվություններ եք ուզում տրամադրել այդ հավելվածին:"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Չեղարկել"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Հեռացնել թույլտվությունները, եթե հավելվածը չի օգտագործվում"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Հեռացնել թույլտվությունները և տարածք ազատել"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Դադարեցնել աշխատանքը ոչ ակտիվ վիճակում"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Կառավարել հավելվածը, եթե չի օգտագործվում"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Հեռացնել թույլտվությունները, ջնջել ժամանակավոր ֆայլերը և դադարեցնել ծանուցումները"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Հեռացնել թույլտվությունները, ջնջել ժամանակավոր ֆայլերը, դադարեցնել ծանուցումները և արխիվացնել հավելվածը"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Եթե հավելվածը չի օգտագործվել մի քանի ամիս, դրա թույլտվությունները կհեռացվեն՝ ձեր տվյալները պաշտպանելու համար։"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Եթե հավելվածը չի օգտագործվել մի քանի ամիս, ձեր տվյալները պաշտպանելու համար հետևյալ թույլտվությունները կհեռացվեն՝ <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Հավելվածներից, որոնք մի քանի ամիս չեք օգտագործել, թույլտվությունները հեռացվել են՝ ձեր տվյալները պաշտպանելու համար։"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Նշումների հավելված"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Հավելվածներ, որոնք թույլ են տալիս նշումներ ստեղծել ձեր սարքում"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"նշումներ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Օգտագործվում է ըստ կանխադրման"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Նորից չհարցնել"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Նշել կանխադրված"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Ցույց տալ ձայնային օգնականի ակտիվացման պատկերակը"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Ցույց տալ պատկերակը կարգավիճակի գոտում, երբ ձայնային օգնականի ակտիվացման համար օգտագործվում է խոսափողը"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել սարքի լուսանկարներն ու մուլտիմեդիա ֆայլերը"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել ձեր կոնտակտները &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"Թույլատրե՞լ &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Թույլատրե՞լ &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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Հավելվածին անհրաժեշտ է ձեր գտնվելու վայրը հետագծելու թույլտվություն, նույնիսկ երբ դուք չեք օգտվում դրանից։ "<annotation id="link">"Թույլտվությունը տրամադրեք այստեղ"</annotation>"։"</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Փոխե՞լ տեղադրության մասին տվյալների հասանելիությունը &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածի համար։"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Փոխե՞լ տեղորոշման թույլտվությունը &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ի համար ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Հավելվածին անհրաժեշտ է ձեր գտնվելու վայրը հետագծելու թույլտվություն, նույնիսկ երբ դուք չեք օգտվում դրանից։ "<annotation id="link">"Թույլտվությունը տրամադրեք այստեղ"</annotation>"։"</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին գտնել մոտակա սարքերը, միանալ դրանց և որոշել դրանց հարաբերական դիրքավորումը։"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին գտնել մոտակա սարքերը, միանալ դրանց և որոշել դրանց հարաբերական դիրքը &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին գտնել մոտակա սարքերը, միանալ դրանց և որոշել դրանց հարաբերական դիրքավորումը։ Թույլատրելու համար անցեք "<annotation id="link">"կարգավորումներ։"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"«<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>» հավելվածի տեղորոշումը փոխե՞լ մոտավորից ճգշրիտի"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Թույլատրե՞լ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>-ին օգտագործել ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել ձեր օրացույցը &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին SMS-ներ ուղարկել և դիտել &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ի&lt;/b&gt; լուսանկարները, մեդիա նյութերը և ֆայլերը։"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել այս սարքի &lt;b&gt;լուսանկարները, տեսանյութերը, երաժշտությունը և աուդիո ֆայլերը&lt;/b&gt;"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել այս սարքի &lt;b&gt;նկարները, երգերը, տեսանյութերը, աուդիո ֆայլերը և մյուս ֆայլերը&lt;/b&gt;"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել այս սարքի երաժշտությունը և մյուս աուդիո ֆայլերը"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ի&lt;/b&gt; երաժշտությունը և մյուս աուդիո ֆայլերը։"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել այս սարքի լուսանկարներն ու տեսանյութերը"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել այս սարքի լուսանկարներն ու տեսանյութերը։"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ի&lt;/b&gt; լուսանկարներն ու տեսանյութերը։"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել այս սարքի լուսանկարներն ու տեսանյութերը"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել այլ լուսանկարներ և տեսանյութեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին ձայնագրել"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին ձայնագրություններ անել ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Այս հավելվածը կկարողանա ձայնագրություններ անել միայն, երբ այն օգտագործելիս լինեք"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին ձայնագրություններ անել։"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին ձայնագրություններ անել ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Այս հավելվածը հավանաբար կուզենա ձայնագրություններ անել նույնիսկ այն ժամանակ, երբ չեք օգտվում դրանից։ "<annotation id="link">"Թույլտվությունը տրամադրեք այստեղ։"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Փոխե՞լ խոսափողի հասանելիության կարգավորումները &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածի համար։"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Փոխե՞լ խոսափողի հասանելիության կարգավորումները &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ի համար ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Այս հավելվածն ուզւոմ է ձայնագրություններ անել նույնիսկ այն ժամանակ, երբ չեք օգտվում դրանից։ "<annotation id="link">"Թույլտվությունը տրամադրեք այստեղ։"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել ձեր ֆիզիկական ակտիվության տվյալները"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել ձեր ֆիզիկական ակտիվության տվյալները &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին լուսանկարել և տեսագրել"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին լուսանկարել և տեսագրել ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Այս հավելվածը կկարողանա լուսանկարել և տեսագրել միայն, երբ այն օգտագործելիս լինեք"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին լուսանկարել և տեսագրել։"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին լուսանկարել և տեսագրել ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Այս հավելվածը հավանաբար կուզենա լուսանկարել և տեսագրել նույնիսկ այն ժամանակ, երբ չեք օգտվում դրանից։ "<annotation id="link">"Թույլտվությունը տրամադրեք այստեղ։"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Փոխե՞լ տեսախցիկի հասանելիության կարգավորումները &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածի համար։"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Փոխե՞լ տեսախցիկի հասանելիության կարգավորումները &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ի համար ձեր &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Այս հավելվածն ուզում է լուսանկարել և տեսագրել նույնիսկ այն ժամանակ, երբ չեք օգտվում դրանից։ "<annotation id="link">"Թույլտվությունը տրամադրեք այստեղ։"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել ձեր հեռախոսազանգերի մատյանները"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել ձեր հեռախոսի զանգերի մատյանները &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին կատարել հեռախոսազանգեր և կառավարել դրանք"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին հեռախոսազանգեր կատարել և կառավարել դրանք &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին սենսորից ստանալ ձեր կենսագործունեության հիմնական տվյալները:"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել ձեր մարմնի սենսորների տվյալները &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Հավելվածին անհրաժեշտ է մարմնի սենսորների տվյալների հասանելիություն, նույնիսկ երբ չեք օգտվում դրանից։ Այս փոփոխությունը կատարելու համար "<annotation id="link">"անցեք կարգավորումներ"</annotation>"։"</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Թույլ տա՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին ձեր կենսագործունեության տվյալները ստանալ սենսորներից"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին օգտագործել ձեր մարմնի սենսորների տվյալները &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Եթե ուզում եք, որ այս հավելվածին հասանելի լինեն մարմնի սենսորների տվյալները, նույնիսկ երբ չեք օգտվում հավելվածից, "<annotation id="link">"փոխեք կարգավորումները"</annotation>"։"</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Մարմնի սենսորների տվյալները հասանելի դարձնե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին, միայն երբ այն օգտագործվում է"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին աշխատանքի ընթացքում օգտագործել մարմնի սենսորների տվյալները &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին ծանուցումներ ուղարկել ձեզ"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Թույլատրե՞լ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ին ծանուցումներ ուղարկել ձեզ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>ում&lt;/b&gt;։"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Կառավարվող թույլտվություններ"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն ունի տեղորոշման թույլտվություն"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Ձեր կազմակերպությունը հասանելի է դարձրել ձեր տեղադրությունը <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Այլ թույլտվություններ"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Համակարգի կողմից օգտագործվող հավելվածներ"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Միայն համակարգի հավելվածների կողմից օգտագործվող թույլտվություններ"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Այս հավելվածը կարող է երրորդ կողմերի հետ կիսվել տեղադրության տվյալներով"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Տվյալների փոխանցում և տեղորոշում"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Որտեղից են վերցվում տվյալներով կիսվելու մասին տեղեկությունները"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Մշակողն այս սարքի արտադրողին տրամադրել է տեղեկություններ, թե ինչպես է այս հավելվածը կիսվում տվյալներով։ Ժամանակի ընթացքում մշակողը կարող է թարմացնել այս տեղեկությունները։"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Մշակողը "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"-ին տրամադրել է տեղեկություններ, թե ինչպես է այս հավելվածը կիսվում տվյալներով։ Ժամանակի ընթացքում մշակողը կարող է թարմացնել այս տեղեկությունները։"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Տեղադրության տվյալներով կիսվելու նպատակները՝"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Տվյալներով կիսվելու եղանակները տարբեր են"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Տվյալների պաշտպանություն"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Տեղադրության տվյալները կարող են փոխանցվել"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Այս հավելվածը կարող է երրորդ կողմերի հետ կիսվել ձեր տեղադրության տվյալներով"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Չհաջողվեց բացել հղումը"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Տեղադրության մասին տվյալներով կիսվելու թույլտվության թարմացում"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Ստուգեք հավելվածների ցանկը, որոնք փոխել են ձեր տեղադրության տվյալներով կիսվելու եղանակը"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Այս հավելվածները փոխել են ձեր տեղադրության տվյալներով կիսվելու եղանակը։ Հնարավոր է, որ նշված հավելվածները նախկինում չեն կիսվել այդ տվյալներով կամ այժմ կիսվում են դրանցով գովազդային կամ մարքեթինգային նպատակներով։"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Տվյալներով կիսվելու եղանակի փոփոխություն"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Որոշ հավելվածներ փոխել են ձեր տեղադրության տվյալներով կիսվելու եղանակը"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Կարգավորումներ"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Բացվել է <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Բացվել է երեկ, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Բացվել է <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-in-v33/strings.xml b/PermissionController/res/values-in-v33/strings.xml
index f2215a915..b74e806df 100644
--- a/PermissionController/res/values-in-v33/strings.xml
+++ b/PermissionController/res/values-in-v33/strings.xml
@@ -19,7 +19,7 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Aplikasi ini akan diizinkan untuk mengirim Notifikasi, dan akan diberi akses ke Kamera, Kontak, Mikrofon, Telepon, dan SMS Anda"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Aplikasi ini akan diizinkan untuk mengirim Notifikasi, dan akan diberi akses ke Kamera, Kontak, File, Mikrofon, Telepon, dan SMS Anda"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikasi yang memiliki izin ini dapat mengakses semua file di perangkat ini"</string>
- <string name="work_policy_title" msgid="832967780713677409">"Info kebijakan kerja Anda"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Info kebijakan profil kerja Anda"</string>
<string name="work_policy_summary" msgid="3886113358084963931">"Setelan yang dikelola oleh admin IT"</string>
<string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Luaskan dan tampilkan daftar"</string>
<string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Ciutkan daftar dan sembunyikan setelan"</string>
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Peringatan lainnya"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Peringatan yang ditutup"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Luaskan untuk melihat satu peringatan lain}other{Luaskan untuk melihat # peringatan lain}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Peringatan. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Tindakan selesai"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Periksa setelan yang dapat menambahkan perlindungan ke perangkat Anda"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Setelan cepat keamanan dan privasi"</string>
diff --git a/PermissionController/res/values-in-v34/strings.xml b/PermissionController/res/values-in-v34/strings.xml
index b26f77dc0..7e0c0a609 100644
--- a/PermissionController/res/values-in-v34/strings.xml
+++ b/PermissionController/res/values-in-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Keamanan &amp; privasi"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kontrol"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Mengelola akses aplikasi ke data kesehatan"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Kelola akses aplikasi ke data kesehatan"</string>
<string name="location_settings" msgid="8863940440881290182">"Akses lokasi"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"Untuk aplikasi dan layanan. Jika setelan ini nonaktif, data mikrofon mungkin tetap dibagikan saat Anda menelepon nomor darurat"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Untuk aplikasi dan layanan"</string>
diff --git a/PermissionController/res/values-in/strings.xml b/PermissionController/res/values-in/strings.xml
index 4540ba8e3..243cbcbc1 100644
--- a/PermissionController/res/values-in/strings.xml
+++ b/PermissionController/res/values-in/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Info lengkap"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Izinkan semua"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Selalu izinkan semua"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Izinkan akses terbatas"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Pilih foto dan video"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Pilih lainnya"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Jangan pilih lainnya"</string>
@@ -51,7 +52,7 @@
<string name="grant_dialog_button_allow" msgid="5314677880021102550">"Izinkan"</string>
<string name="grant_dialog_button_allow_always" msgid="4485552579273565981">"Izinkan sepanjang waktu"</string>
<string name="grant_dialog_button_allow_foreground" msgid="501896824973636533">"Saat aplikasi digunakan"</string>
- <string name="grant_dialog_button_change_to_precise_location" msgid="3273115879467236033">"Ubah ke lokasi akurat"</string>
+ <string name="grant_dialog_button_change_to_precise_location" msgid="3273115879467236033">"Ubah ke lokasi presisi"</string>
<string name="grant_dialog_button_keey_approximate_location" msgid="438025182769080011">"Tetap gunakan perkiraan"</string>
<string name="grant_dialog_button_allow_one_time" msgid="2618088516449706391">"Hanya kali ini"</string>
<string name="grant_dialog_button_allow_background" msgid="8236044729434367833">"Izinkan sepanjang waktu"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikasi"</string>
<string name="app_permissions" msgid="3369917736607944781">"Izin aplikasi"</string>
<string name="unused_apps" msgid="2058057455175955094">"Aplikasi tidak digunakan"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edit foto yang dipilih untuk aplikasi ini"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Tak ada aplikasi tidak dipakai"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 aplikasi tidak digunakan"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Keputusan izin terbaru"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Izinkan sepanjang waktu"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Izinkan saat apl digunakan"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Izinkan saat aplikasi digunakan"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Jangan izinkan"</string>
<string name="loading" msgid="4789365003890741082">"Memuat…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Semua izin"</string>
<string name="other_permissions" msgid="2901186127193849594">"Kemampuan aplikasi lainnya"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Permintaan izin"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Instal/Uninstal tidak didukung di Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Pilih item yang boleh diakses oleh &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; telah diperbarui. Pilih item yang boleh diakses oleh aplikasi ini."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Batal"</string>
@@ -191,10 +191,10 @@
<string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Selalu izinkan semua"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Selalu tanya"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Jangan izinkan"</string>
- <string name="precise_image_description" msgid="6349638632303619872">"Lokasi akurat"</string>
+ <string name="precise_image_description" msgid="6349638632303619872">"Lokasi presisi"</string>
<string name="approximate_image_description" msgid="938803699637069884">"Perkiraan lokasi"</string>
- <string name="app_permission_location_accuracy" msgid="7166912915040018669">"Gunakan lokasi akurat"</string>
- <string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Saat lokasi akurat dinonaktifkan, aplikasi dapat mengakses perkiraan lokasi"</string>
+ <string name="app_permission_location_accuracy" msgid="7166912915040018669">"Gunakan lokasi presisi"</string>
+ <string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Saat lokasi presisi dinonaktifkan, aplikasi dapat mengakses perkiraan lokasi"</string>
<string name="app_permission_title" msgid="2090897901051370711">"Izin <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_header" msgid="2951363137032603806">"Akses <xliff:g id="PERM">%1$s</xliff:g> untuk aplikasi ini"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Lihat semua izin <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Hapus izin jika aplikasi tidak digunakan"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Hapus izin &amp; kosongkan ruang penyimpanan"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Jeda aktivitas aplikasi jika tak dipakai"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Kelola aplikasi jika tidak digunakan"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Hapus izin dan file sementara, serta hentikan notifikasi"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Menghapus izin dan file sementara, menghentikan notifikasi, serta mengarsipkan aplikasi"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Untuk melindungi data Anda, izin aplikasi ini akan dihapus jika aplikasi tidak digunakan dalam beberapa bulan."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Untuk melindungi data Anda, izin berikut akan dihapus jika aplikasi tidak digunakan dalam beberapa bulan: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Untuk melindungi data Anda, izin dari aplikasi yang tidak digunakan dalam beberapa bulan telah dihapus."</string>
@@ -247,7 +249,7 @@
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"Ditolak / Tidak pernah mengakses"</string>
<string name="allowed_header" msgid="7769277978004790414">"Diizinkan"</string>
<string name="allowed_always_header" msgid="6455903312589013545">"Diizinkan sepanjang waktu"</string>
- <string name="allowed_foreground_header" msgid="6845655788447833353">"Hanya diizinkan saat digunakan"</string>
+ <string name="allowed_foreground_header" msgid="6845655788447833353">"Diizinkan hanya saat digunakan"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"Hanya diizinkan akses ke media"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"Diizinkan untuk mengelola semua file"</string>
<string name="ask_header" msgid="2633816846459944376">"Selalu tanya"</string>
@@ -399,8 +401,18 @@
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Layanan ini membagikan foto, media, dan notifikasi dari ponsel ke perangkat lain."</string>
<string name="role_notes_label" msgid="7451627001058089536">"Aplikasi catatan default"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikasi catatan"</string>
- <string name="role_notes_description" msgid="8496852798616883551">"Aplikasi yang memungkinkan Anda membuat catatan di perangkat"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"Aplikasi untuk membuat catatan di perangkat"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"catatan"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Default saat ini"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Jangan tanya lagi"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Jadikan default"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Tampilkan deteksi pemicu asisten"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Tampilkan ikon di status bar saat mikrofon digunakan untuk mengaktifkan asisten suara"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan media di perangkat?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan media di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses kontak?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses kontak di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi perangkat ini?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikasi ini hanya akan memiliki akses ke lokasi selagi Anda menggunakan aplikasi"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi perangkat ini?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Aplikasi ini mungkin ingin selalu mengakses lokasi, meski tidak sedang digunakan. "<annotation id="link">"Izinkan di setelan."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Ubah akses lokasi untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Ubah akses lokasi untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Aplikasi ini mungkin ingin selalu mengakses lokasi, meski tidak sedang digunakan. "<annotation id="link">"Izinkan di setelan."</annotation></string>
- <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; untuk menemukan, terhubung ke, dan menentukan posisi relatif perangkat di sekitar?"</string>
- <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; untuk menemukan, terhubung ke, dan menentukan posisi relatif perangkat di sekitar? "<annotation id="link">"Izinkan di setelan."</annotation></string>
- <string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Ubah akses lokasi <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> dari perkiraan ke lokasi akurat?"</string>
+ <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; menemukan, terhubung ke, dan menentukan posisi relatif perangkat di sekitar?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; menemukan, menghubungkan, dan menentukan posisi relatif perangkat di sekitar di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; menemukan, terhubung ke, dan menentukan posisi relatif perangkat di sekitar? "<annotation id="link">"Izinkan di setelan."</annotation></string>
+ <string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Ubah akses lokasi <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> dari perkiraan ke lokasi presisi?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Ubah akses lokasi <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; dari perkiraan menjadi presisi?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses perkiraan lokasi perangkat ini?"</string>
- <string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Akurat"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses perkiraan lokasi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Presisi"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Perkiraan"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses kalender?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses kalender di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengirim dan melihat SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengirim dan melihat pesan SMS di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto, media, dan file di perangkat?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto, media, dan file di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses &lt;b&gt;foto, video, musik, dan audio&lt;/b&gt; di perangkat ini?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses &lt;b&gt;foto, video, musik, audio, dan file lainnya&lt;/b&gt; di perangkat ini?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses musik dan audio di perangkat ini?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses musik dan audio di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan video di perangkat ini?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan video di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan video lainnya di perangkat ini?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan video lainnya di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merekam audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merekam audio di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikasi hanya dapat merekam audio saat aplikasi sedang digunakan"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merekam audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merekam audio di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Aplikasi ini mungkin ingin selalu merekam audio, meski aplikasi tidak sedang digunakan. "<annotation id="link">"Izinkan di setelan"</annotation>"."</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Ubah akses mikrofon untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Ubah akses mikrofon untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Aplikasi ini ingin selalu merekam audio, meski aplikasi tidak sedang digunakan. "<annotation id="link">"Izinkan di setelan"</annotation>"."</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses aktivitas fisik Anda?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses aktivitas fisik di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengambil gambar dan merekam video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengambil gambar dan merekam video di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikasi hanya dapat mengambil gambar dan merekam video saat aplikasi sedang digunakan"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengambil gambar dan merekam video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengambil gambar dan merekam video di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Aplikasi ini mungkin ingin selalu mengambil gambar dan merekam video, meski aplikasi tidak sedang digunakan. "<annotation id="link">"Izinkan di setelan"</annotation>"."</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Ubah akses kamera untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Ubah akses kamera untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Aplikasi ini ingin selalu mengambil gambar dan merekam video, meski aplikasi tidak sedang digunakan. "<annotation id="link">"Izinkan di setelan"</annotation>"."</string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses log panggilan telepon?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses log panggilan telepon di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; melakukan dan mengelola panggilan telepon?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; melakukan dan mengelola panggilan telepon di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data sensor tentang tanda-tanda vital Anda?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data sensor terkait tanda-tanda vital Anda di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Aplikasi ini ingin selalu mengakses data sensor tentang tanda-tanda vital Anda, meski aplikasi tidak sedang digunakan. Untuk melakukan perubahan ini, "<annotation id="link">"buka setelan"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Izinkan &lt;/b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data sensor tentang tanda-tanda vital Anda?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data sensor terkait tanda-tanda vital Anda di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Untuk selalu mengizinkan aplikasi ini mengakses data sensor tubuh, meski saat aplikasi tidak sedang digunakan, "<annotation id="link">"buka setelan."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Terus izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data sensor tubuh saat aplikasi sedang digunakan?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Terus izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data sensor tubuh di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; saat apl sedang digunakan?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengirim notifikasi kepada Anda?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengirimi Anda notifikasi di &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Izin terkontrol"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> memiliki akses lokasi"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Organisasi Anda mengizinkan <xliff:g id="APP_NAME">%1$s</xliff:g> mengakses lokasi Anda"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Izin lainnya"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Izin yang digunakan oleh sistem"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Izin hanya digunakan oleh aplikasi sistem."</string>
@@ -585,12 +622,13 @@
<string name="mic_toggle_description" msgid="9163104307990677157">"Untuk aplikasi dan layanan. Jika setelan ini nonaktif, data mikrofon mungkin tetap dibagikan saat Anda menelepon nomor darurat."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Lihat aplikasi dan layanan yang memiliki akses ke lokasi"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Tampilkan akses papan klip"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Menampilkan pesan saat aplikasi mengakses teks, gambar, atau konten lainnya yang telah Anda salin"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Tampilkan pesan saat aplikasi mengakses teks, gambar, atau konten lain yang telah Anda salin"</string>
<string name="show_password_title" msgid="2877269286984684659">"Tampilkan sandi"</string>
- <string name="show_password_summary" msgid="1110166488865981610">"Menampilkan karakter sejenak saat Anda mengetik"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Tampilkan karakter sejenak saat Anda mengetik"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Aplikasi ini menyatakan bahwa aplikasi mungkin membagikan data lokasi ke pihak ketiga"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Berbagi data dan lokasi"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Sumber info berbagi data"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Developer memberikan info kepada produsen perangkat ini tentang cara aplikasi ini berbagi data. Developer dapat memperbarui info ini dari waktu ke waktu."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Developer memberikan info kepada "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" tentang cara aplikasi ini berbagi data. Developer dapat memperbarui info ini dari waktu ke waktu."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Aplikasi ini mungkin membagikan data lokasi untuk:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Praktik berbagi data dapat berbeda-beda"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Keamanan data"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Data lokasi mungkin dibagikan"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Aplikasi ini menyatakan bahwa aplikasi mungkin membagikan data lokasi Anda kepada pihak ketiga"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Tidak dapat membuka link ini"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Pembaruan berbagi data untuk lokasi"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Tinjau aplikasi yang mengubah caranya berbagi data lokasi Anda"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Aplikasi ini telah mengubah caranya berbagi data lokasi Anda. Aplikasi mungkin sebelumnya tidak membagikan data, atau mungkin kini membagikan data untuk tujuan iklan atau pemasaran."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Pembaruan berbagi data"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Beberapa aplikasi mengubah caranya berbagi data lokasi Anda"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Setelan"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Diakses <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Diakses kemarin <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Diakses <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-is-v33/strings.xml b/PermissionController/res/values-is-v33/strings.xml
index 4fba44171..3f7695027 100644
--- a/PermissionController/res/values-is-v33/strings.xml
+++ b/PermissionController/res/values-is-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Fleiri tilkynningar"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Hunsaðar viðvaranir"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Stækka og sjá eina viðvörun í viðbót}one{Stækka og sjá # viðvörun í viðbót}other{Stækka og sjá # viðvaranir í viðbót}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Viðvörun. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Aðgerð lokið"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Skoðunarstillingar sem geta bætt öryggi tækisins þíns"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Flýtistillingar öryggis og persónuverndar"</string>
diff --git a/PermissionController/res/values-is/strings.xml b/PermissionController/res/values-is/strings.xml
index 83f737166..a31211712 100644
--- a/PermissionController/res/values-is/strings.xml
+++ b/PermissionController/res/values-is/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Upplýsingar"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Leyfa allt"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Alltaf leyfa allt"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Leyfa takmarkaðan aðgang"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Velja myndir og myndskeið"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Velja meira"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ekki velja fleiri"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Forrit"</string>
<string name="app_permissions" msgid="3369917736607944781">"Heimildir forrits"</string>
<string name="unused_apps" msgid="2058057455175955094">"Ónotuð forrit"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Breyttu myndavali fyrir þetta forrit"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Engin ónotuð forrit"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ónotuð forrit"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nýlegar heimildaákvarðanir"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Allar heimildir"</string>
<string name="other_permissions" msgid="2901186127193849594">"Aðrir forritseiginleikar"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Beiðni um heimild"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Aðgerðir til að setja upp / fjarlægja eru ekki studdar í Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Veldu hverju &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fær aðgang að"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; hefur verið uppfært. Veldu hverju forritið fær aðgang að."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Hætta við"</string>
@@ -124,7 +124,7 @@
<string name="current_permissions_category" msgid="4292990083585728880">"Núgildandi heimildir"</string>
<string name="message_staging" msgid="9110563899955511866">"Setur upp forrit…"</string>
<string name="app_name_unknown" msgid="1319665005754048952">"Óþekkt"</string>
- <string name="permission_usage_title" msgid="1568233336351734538">"Einkastjórnborð"</string>
+ <string name="permission_usage_title" msgid="1568233336351734538">"Persónuverndarstjórnborð"</string>
<string name="auto_permission_usage_summary" msgid="7335667266743337075">"Skoða hvaða forrit notuðu heimildir nýlega"</string>
<string name="permission_group_usage_title" msgid="2595013198075285173">"<xliff:g id="PERMGROUP">%1$s</xliff:g>: notkun"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Sjá aðrar heimildir"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Fjarlægja heimildir ef forrit er ekki notað"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Fjarlægja heimildir og losa um pláss"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Gera hlé á forritavirkni ef ekki notað"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Stjórna forriti ef það er ónotað"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Fjarlægja heimildir, eyða tímabundnum skrám og stöðva tilkynningar"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Fjarlægja heimildir, eyða tímabundnum skrám, stöðva tilkynningar og setja forritið í geymslu"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Til að vernda gögnin þín verða heimildir þessa forrits fjarlægðar ef það er ekki notað í nokkra mánuði."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Til að vernda gögnin þín verða eftirfarandi heimildir fjarlægðar ef forritið er ekki notað í nokkra mánuði: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Til að vernda gögnin þín voru heimildir fjarlægðar úr forritum sem þú hefur ekki notað í nokkra mánuði."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Síðast opnað <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ef þú leyfir stjórnun allra skráa getur þetta forrit opnað, breytt og eytt öllum skrám í sameiginlegri geymslu í þessu tæki eða tengdum geymslutækjum. Þetta forrit getur opnað skrár án þess að spyrja þig."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Viltu gefa þessu forriti aðgang að skrám í tækinu eða tengdum geymslutækjum og leyfi til að breyta þeim og eyða? Þetta forrit getur opnað skrár án þess að spyrja þig."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Forrit með þessa heimild <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Forrit með þessa heimild mega <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Forrit með þessa heimild hafa aðgang að upplýsingum um hreyfingu þína, svo sem göngu, hjólreiðar, akstur, skrefafjölda og fleira"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Forrit með þessa heimild hafa aðgang að dagatalinu þínu"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Forrit með þessa heimild geta lesið og skrifað símtalaskrá síma"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Glósuforrit"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Forrit sem gera þér kleift að taka glósur í tækinu þínu"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"glósur"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Núverandi sjálfgefið forrit"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ekki spyrja aftur"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Velja sem sjálfgefið"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Sýna virkjunarkennsl hjálpara"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Sýna tákn á stöðustiku þegar hljóðnemi er notaður til að ræsa raddaðstoð"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að myndum og efni í tækinu?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að myndum og efni í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að tengiliðunum þínum?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að tengiliðunum þínum í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að staðsetningu þessa tækis?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að staðsetningu fyrir: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Forritið hefur aðeins aðgang að staðsetningunni á meðan þú notar forritið"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að staðsetningu þessa tækis?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að staðsetningu: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Þetta forrit gæti beðið um aðgang að staðsetningu þinni öllum stundum, jafnvel þegar þú ert ekki að nota forritið. "<annotation id="link">"Þú getur leyft það í stillingum."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Viltu breyta aðgangi að staðsetningu fyrir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Breyta staðsetningaraðgangi fyrir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Þetta forrit vill fá aðgang að staðsetningu þinni öllum stundum, jafnvel þegar þú ert ekki að nota forritið. "<annotation id="link">"Þú getur leyft það í stillingum."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að finna, tengjast við og ákvarða fjarlægð milli nálægra tækja?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að finna, tengjast og greina áætlaða staðsetningu nálægra tækja í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að finna, tengjast við og ákvarða fjarlægð milli nálægra tækja? "<annotation id="link">"Þú getur leyft það í stillingunum."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Breyta aðgangi <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> að staðsetningu úr áætlaðri í nákvæma?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Breyta staðsetningaraðgangi <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> úr áætluðum í nákvæman í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að áætlaðri staðsetningu þessa tækis?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að áætlaðri staðsetningu fyrir: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Nákvæm"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Áætluð"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að dagatalinu þínu?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að dagatalinu þínu í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Viltu leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að senda og skoða SMS-skilaboð?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að senda og skoða SMS-skilaboð í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að myndum, efni og skrám í tækinu?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að myndum, efni og skrám í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að &lt;b&gt;myndum, myndskeiðum, tónlist og hljóði&lt;/b&gt; í þessu tæki?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að &lt;b&gt;myndum, myndskeiðum, tónlist, hljóði og öðrum skrám&lt;/b&gt; í þessu tæki?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að tónlist og hljóði í þessu tæki?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að tónlist og hljóði í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að myndum og myndskeiðum í þessu tæki?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að myndum og vídeóum í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að fleiri myndum og myndskeiðum í þessu tæki?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að fleiri myndum og vídeóum í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að taka upp hljóð?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að taka upp hljóð í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Forritið mun aðeins geta tekið upp hljóð þegar þú ert að nota forritið"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Viltu leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að taka upp hljóð?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að taka upp hljóð í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Þetta forrit gæti viljað taka upp hljóð hvenær sem er, jafnvel þegar þú ert ekki að nota forritið. "<annotation id="link">"Þú getur leyft það í stillingum."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Viltu breyta aðgangi að hljóðnema fyrir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Breyta hljóðnemaaðgangi fyrir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Þetta forrit vill taka upp hljóð hvenær sem er, jafnvel þegar þú ert ekki að nota forritið. "<annotation id="link">"Þú getur leyft það í stillingum."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Viltu leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að fá aðgang að hreyfingu þinni?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að gögnum um hreyfingu í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Viltu leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að taka myndir og myndskeið?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að taka myndir og taka upp vídeó í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Forritið mun aðeins geta tekið myndir og tekið upp myndskeið þegar þú ert að nota forritið"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Viltu leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að taka myndir og myndskeið?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að taka myndir og taka upp vídeó í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Þetta forrit gæti viljað taka myndir og taka upp myndskeið hvenær sem er, jafnvel þegar þú ert ekki að nota forritið. "<annotation id="link">"Þú getur leyft það í stillingum."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Viltu breyta aðgangi að myndavél fyrir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Breyta myndavélaraðgangi fyrir &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Þetta forrit vill taka myndir og taka upp myndskeið hvenær sem er, jafnvel þegar þú ert ekki að nota forritið. "<annotation id="link">"Þú getur leyft það í stillingum."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að símtalaskrám símans?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að símtalaskránum þínum í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Viltu leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að hringja og stjórna símtölum?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að hringja og stjórna símtölum í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að skynjaragögnum um lífsmörk þín?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að skynjaragögnum um lífsmörk þín í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Þetta forrit vill fá stöðugan aðgang að skynjaragögnum um lífsmörk þín, líka þegar þú ert ekki að nota forritið. Ef þú vilt gera þessa breytingu skaltu "<annotation id="link">"opna stillingar."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Viltu veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að skynjaragögnum um lífsmörk þín?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aðgang að skynjaragögnum um lífsmörk þín í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Til að veita þessu forriti samfelldan aðgang að gögnum líkamsskynjara skaltu "<annotation id="link">"opna stillingarnar."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; áfram aðgang að gögnum líkamsskynjara á meðan forritið er í notkun?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Veita &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; áfram aðgang að líkamsskynjaragögnum á meðan forritið er í notkun í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að senda þér tilkynningar?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Leyfa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; að senda þér tilkynningar í: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Stýrðar heimildir"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> er með staðsetningaraðgang"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Fyrirtækið þitt veitir <xliff:g id="APP_NAME">%1$s</xliff:g> aðgang að staðsetningu þinni"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Aðrar heimildir"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Heimildir sem kerfið notar"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Heimildir aðeins notaðar af kerfisforritum."</string>
@@ -581,7 +618,7 @@
<string name="privacy_controls_title" msgid="7605929972256835199">"Persónuverndarstillingar"</string>
<string name="camera_toggle_title" msgid="1251201397431837666">"Aðgangur að myndavél"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Aðgangur að hljóðnema"</string>
- <string name="perm_toggle_description" msgid="7801326363741451379">"Fyrir forrit og þjónustu"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Fyrir forrit og þjónustur"</string>
<string name="mic_toggle_description" msgid="9163104307990677157">"Fyrir forrit og þjónustur. Þegar slökkt er á þessari stillingu verður hljóðnemagögnum þó hugsanlega deilt þegar þú hringir í neyðarnúmer."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Skoða forrit og þjónustur sem eru með aðgang að staðsetningu"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Sýna aðgang að klippiborði"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Þetta forrit gaf til kynna að það kunni að deila staðsetningargögnum með þriðju aðilum"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Gagnadeiling og staðsetning"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Hvaðan koma upplýsingar um gagnadeilingu"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Þróunaraðilinn veitti framleiðanda þessa tækis upplýsingar um hvernig þetta forrit deilir gögnum. Þróunaraðilinn kann að uppfæra þessar upplýsingar síðar."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Þróunaraðilinn veitti "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" upplýsingar um hvernig þetta forrit deilir gögnum. Þróunaraðilinn kann að uppfæra þessar upplýsingar síðar."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Forritið kann að deila staðsetningargögnum til að:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Gagnadeiling er mismunandi"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Gagnaöryggi"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Staðsetningargögnum kann að vera deilt"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Þetta forrit gaf til kynna að það kunni að deila staðsetningargögnum frá þér með þriðju aðilum"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Ekki er hægt að opna þennan tengil"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Uppfærslur um gagnadeilingu varðandi staðsetningu"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Yfirfarðu forrit sem breyttu því hvernig þau geta deilt staðsetningargögnunum þínum"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Deiling staðsetningargagna hefur breyst í þessum forritum. Þau hafa hugsanlega ekki deilt gögnunum áður eða deila þeim nú í auglýsinga- eða markaðssetningartilgangi."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Gagnadeilingaruppfærslur"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Deiling staðsetningargagna hefur breyst í sumum forritum"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Stillingar"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Opnað kl. <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Opnað í gær kl. <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Opnað <xliff:g id="TIME_DATE_0">%1$s</xliff:g> kl. <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-it/strings.xml b/PermissionController/res/values-it/strings.xml
index a122a5fa7..cd69876ae 100644
--- a/PermissionController/res/values-it/strings.xml
+++ b/PermissionController/res/values-it/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Altre info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Consenti tutto"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Consenti sempre tutto"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Consenti accesso limitato"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Seleziona foto e video"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Seleziona più messaggi"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Non selezionare altri dati"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Non selezionare altro"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Non consentire comunque"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Ignora"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> di <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"App"</string>
<string name="app_permissions" msgid="3369917736607944781">"Autorizzazioni app"</string>
<string name="unused_apps" msgid="2058057455175955094">"App inutilizzate"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Modifica le foto selezionate per questa app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nessuna app inutilizzata"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 app inutilizzate"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Decisioni recenti per le autorizzazioni"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Tutte le autorizzazioni"</string>
<string name="other_permissions" msgid="2901186127193849594">"Altre funzionalità dell\'app"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Richiesta di autorizzazione"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Le azioni di installazione/disinstallazione non sono supportate su Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Scegli i dati a cui l\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; può accedere"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"L\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; è stata aggiornata. Scegli i dati a cui può accedere."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Annulla"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Rimuovi autorizzazioni se non in uso"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Rimuovi autorizzazioni e libera spazio"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Sospendi attività app se inutilizzata"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gestisci l\'app se inutilizzata"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Rimuovi le autorizzazioni, elimina i file temporanei e interrompi le notifiche"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Rimuovi le autorizzazioni, elimina i file temporanei, interrompi le notifiche e archivia l\'app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Per proteggere i tuoi dati, le autorizzazioni di questa app verranno rimosse se l\'app non viene usata per alcuni mesi."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Per proteggere i tuoi dati, se l\'app non viene usata per alcuni mesi, le seguenti autorizzazioni verranno rimosse: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Per proteggere i tuoi dati, sono state rimosse le autorizzazioni dalle app che non hai utilizzato per alcuni mesi."</string>
@@ -245,13 +247,13 @@
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"Al momento rifiutata/Ultimo accesso: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"Accesso mai eseguito"</string>
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"Rifiutata/Accesso mai effettuato"</string>
- <string name="allowed_header" msgid="7769277978004790414">"Autorizzate"</string>
+ <string name="allowed_header" msgid="7769277978004790414">"Autorizzata"</string>
<string name="allowed_always_header" msgid="6455903312589013545">"Autorizzazione sempre concessa"</string>
<string name="allowed_foreground_header" msgid="6845655788447833353">"Autorizzazione concessa solo durante l\'uso"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"Autorizzate solo per contenuti multimediali"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"Autorizzate per gestire tutti i file"</string>
<string name="ask_header" msgid="2633816846459944376">"Chiedi ogni volta"</string>
- <string name="denied_header" msgid="903209608358177654">"Non autorizzate"</string>
+ <string name="denied_header" msgid="903209608358177654">"Non autorizzata"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Visualizza altre app che possono accedere a tutti i file"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 giorno}many{# giorni}other{# giorni}}"</string>
<string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ora}many{# ore}other{# ore}}"</string>
@@ -338,7 +340,7 @@
<string name="no_permissions_allowed" msgid="6081976856354669209">"Nessuna autorizzazione consentita"</string>
<string name="no_permissions_denied" msgid="8159923922804043282">"Nessuna autorizzazione rifiutata"</string>
<string name="no_apps_allowed" msgid="7718822655254468631">"Nessuna app autorizzata"</string>
- <string name="no_apps_allowed_full" msgid="8011716991498934104">"Nessuna app consentita per tutti i file"</string>
+ <string name="no_apps_allowed_full" msgid="8011716991498934104">"Nessuna app autorizzata per tutti i file"</string>
<string name="no_apps_allowed_scoped" msgid="4908850477787659501">"Nessuna app autorizzata solo per i contenuti multimediali"</string>
<string name="no_apps_denied" msgid="7663435886986784743">"A nessuna app è stata negata l\'autorizzazione"</string>
<string name="car_permission_selected" msgid="180837028920791596">"Selezionato"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"App per le note"</string>
<string name="role_notes_description" msgid="8496852798616883551">"App che ti permettono di prendere appunti sul tuo dispositivo"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"note"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Valore predefinito attuale"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Non chiedermelo più"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Imposta predefinito"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Mostra il rilevamento dell\'attivazione dell\'assistente"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mostra l\'icona nella barra di stato quando viene usato il microfono per attivare l\'assistente vocale"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alle foto e ai contenuti multimediali sul tuo dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a foto e contenuti multimediali sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai tuoi contatti?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai contatti sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla posizione di questo dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla posizione del tuo &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"L\'app avrà accesso alla posizione soltanto quando la usi"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla posizione di questo dispositivo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla posizione del tuo &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Questa app potrebbe voler accedere sempre alla tua posizione, anche quando non la usi. "<annotation id="link">"Consenti l\'accesso nelle impostazioni"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Vuoi cambiare l\'accesso alla posizione per l\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Cambiare l\'accesso alla posizione per l\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Questa app vorrebbe accedere sempre alla tua posizione, anche quando non la usi. "<annotation id="link">"Consenti l\'accesso nelle impostazioni"</annotation>"."</string>
- <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di trovare e connettersi a dispositivi vicini, nonché stabilirne la posizione relativa?"</string>
- <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di trovare e connettersi a dispositivi vicini, nonché stabilirne la posizione relativa? "<annotation id="link">"Consenti nelle impostazioni."</annotation></string>
+ <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di trovare e connettersi ai dispositivi vicini, e di stabilirne la posizione relativa?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di connettersi a dispositivi vicini e stabilirne la posizione relativa su &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di trovare e connettersi ai dispositivi vicini, e di stabilirne la posizione relativa? "<annotation id="link">"Consenti nelle impostazioni."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Modificare l\'accesso alla posizione di <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> da approssimativa a esatta?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Modificare l\'accesso alla posizione dell\'app <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; da approssimativa a esatta?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla posizione approssimativa di questo dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla posizione approssimativa del tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;’?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Esatta"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Approssimativa"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere al tuo calendario?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere al tuo calendario sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di inviare e visualizzare SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di inviare e visualizzare SMS sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a foto, contenuti multimediali e file memorizzati sul dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a foto, contenuti multimediali e file sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a &lt;b&gt;foto, video, musica e audio&lt;/b&gt; sul dispositivo?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a &lt;b&gt;foto, video, musica, audio e altri file&lt;/b&gt; sul dispositivo?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a musica e audio sul dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a musica e audio sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a foto e video sul dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere a foto e video sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ad altri video e foto sul dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ad altri video e foto sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di registrare audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di registrare audio sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"L\'app potrà registrare audio soltanto quando la usi"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Vuoi consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di registrare audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di registrare audio sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Questa app potrebbe voler registrare sempre audio, anche quando non la usi. "<annotation id="link">"Consenti l\'accesso nelle impostazioni."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Vuoi cambiare l\'accesso al microfono per l\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Cambiare l\'accesso al microfono per l\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Questa app vorrebbe registrare sempre audio, anche quando non la usi. "<annotation id="link">"Consenti l\'accesso nelle impostazioni."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla tua attività fisica?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla tua attività fisica sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di scattare foto e registrare video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di scattare foto e registrare video sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"L\'app potrà scattare foto e registrare video soltanto quando la usi"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Vuoi consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di scattare foto e registrare video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di scattare foto e registrare video sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Questa app potrebbe voler scattare foto e registrare video sempre, anche quando non la usi. "<annotation id="link">"Consenti l\'accesso nelle impostazioni."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Vuoi cambiare l\'accesso alla fotocamera per l\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Cambiare l\'accesso alla fotocamera per l\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Questa app vorrebbe scattare foto e registrare video sempre, anche quando non la usi. "<annotation id="link">"Consenti l\'accesso nelle impostazioni."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai registri chiamate del tuo telefono?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai registri chiamate dello smartphone sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di effettuare e gestire telefonate?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di effettuare e gestire telefonate sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai dati dei sensori relativi ai parametri vitali?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai dati dei sensori sui parametri vitali del tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Questa app vuole accedere sempre ai dati dei sensori relativi ai tuoi parametri vitali, anche quando non la usi. Per apportare questa modifica, "<annotation id="link">"vai alle impostazioni."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai dati dei sensori relativi ai parametri vitali?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai dati dei sensori sui parametri vitali del tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Per consentire a questa app di accedere sempre ai dati dei sensori del corpo, anche quando non la usi, "<annotation id="link">"vai alle impostazioni"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Continuare a consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai dati dei sensori del corpo mentre l\'app è in uso?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ad accedere ai dati dei sensori del corpo mentre è in uso sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di inviarti notifiche?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di inviarti notifiche sul tuo &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Autorizzazioni controllate"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> ha accesso alla posizione"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"La tua organizzazione consente all\'app <xliff:g id="APP_NAME">%1$s</xliff:g> di accedere alla tua posizione"</string>
@@ -532,7 +571,7 @@
<string name="security_settings" msgid="3808106921175271317">"Impostazioni di sicurezza"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"Autorizzazioni"</string>
<string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sicurezza e privacy"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Verifica lo stato"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Verifica stato"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Controlli per la privacy"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Altre impostazioni"</string>
<string name="camera_toggle_label_qs" msgid="3880261453066157285">"Accesso alla fotocamera"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Questa app ha dichiarato che potrebbe condividere dati sulla posizione con terze parti"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Condivisione dei dati e posizione"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Da dove provengono le informazioni sulla condivisione dei dati"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Lo sviluppatore ha fornito al produttore di questo dispositivo le informazioni sulla modalità di condivisione dei dati nell\'app. Lo sviluppatore potrebbe aggiornare queste informazioni nel tempo."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Lo sviluppatore ha fornito a "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" informazioni sulla modalità di condivisione dei dati in questa app. Lo sviluppatore potrebbe aggiornare queste informazioni nel tempo."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"L\'app può condividere dati sulla posizione per:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"La condivisione dei dati varia"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Sicurezza dei dati"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Potrebbero essere condivisi dati sulla posizione"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Questa app ha dichiarato che potrebbe condividere i tuoi dati sulla posizione con terze parti"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Impossibile aprire questo link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Aggiornamenti relativi alla condivisione dei dati sulla posizione"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Controlla le app che hanno cambiato la modalità di condivisione dei tuoi dati sulla posizione"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Le app che seguono hanno cambiato la modalità di condivisione dei tuoi dati sulla posizione. Potrebbero non averli condivisi in precedenza oppure ora potrebbero condividerli per scopi pubblicitari o di marketing."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Aggiornamenti relativi alla condivisione dei dati"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Alcune app hanno cambiato la modalità di condivisione dei tuoi dati sulla posizione"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Impostazioni"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Ultimo accesso: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Ultimo accesso ieri: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Ultimo accesso: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-iw-v33/strings.xml b/PermissionController/res/values-iw-v33/strings.xml
index 5525ff31f..b94c5f360 100644
--- a/PermissionController/res/values-iw-v33/strings.xml
+++ b/PermissionController/res/values-iw-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"התראות נוספות"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"התראות שנסגרו"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{הרחבה וצפייה בהתראה נוספת אחת}one{הרחבה וצפייה ב-# התראות נוספות}two{הרחבה וצפייה ב-# התראות נוספות}other{הרחבה וצפייה ב-# התראות נוספות}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"התראה. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"הפעולה הושלמה"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"בדיקת ההגדרות שיכולות לשפר את ההגנה על המכשיר"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"הגדרות מהירות של אבטחה ופרטיות"</string>
diff --git a/PermissionController/res/values-iw/strings.xml b/PermissionController/res/values-iw/strings.xml
index 020d318bb..d1abc61d8 100644
--- a/PermissionController/res/values-iw/strings.xml
+++ b/PermissionController/res/values-iw/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"מידע נוסף"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"אישור של הכול"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"אישור של הכול תמיד"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"הרשאה לגישה מוגבלת"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"בחירת תמונות וסרטונים"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"בחירת תמונות נוספות"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"לא לבחור עוד"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"אין אישור בכל זאת"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"סגירה"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> מתוך <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"‏האם לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ‏<xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"‏תמיד לאשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לבצע <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"‏לאשר לאפליקציית &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ‏<xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"‏תמיד לאשר לאפליקציית &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"רק בזמן השימוש באפליקציה"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"תמיד"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"אין אישור ואין צורך לשאול שוב"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"אפליקציות"</string>
<string name="app_permissions" msgid="3369917736607944781">"הרשאות לאפליקציות"</string>
<string name="unused_apps" msgid="2058057455175955094">"אפליקציות שמזמן לא השתמשת בהן"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"עריכת הרשימה של התמונות שנבחרו לאפליקציה הזו"</string>
<string name="no_unused_apps" msgid="12809387670415295">"אין אפליקציות שאינן בשימוש"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"אין אפליקציות שאינן בשימוש"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"ההחלטות האחרונות לגבי הרשאות"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"כל ההרשאות"</string>
<string name="other_permissions" msgid="2901186127193849594">"הרשאות אחרות של האפליקציה"</string>
<string name="permission_request_title" msgid="8790310151025020126">"בקשת הרשאה"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"‏פעולות התקנה/הסרת התקנה אינן נתמכות ב-Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"‏בחירה בהרשאות הגישה שברצונך לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"‏אפליקציית &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; עודכנה. יש לבחור הרשאות גישה לאפליקציה הזו."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"ביטול"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"הסרת ההרשאות כשלא בשימוש"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"הסרת הרשאות ופינוי מקום אחסון"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"השהיית הפעילות באפליקציה אם אין בה שימוש"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ניהול האפליקציה כשהיא לא בשימוש"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ההרשאות של האפליקציה יוסרו, הקבצים הזמניים יימחקו ותופסק קבלת ההתראות ממנה"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"הסרת ההרשאות, מחיקה של הקבצים הזמניים, הפסקה של קבלת ההתראות והעברת האפליקציה לארכיון"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"כדי להגן על הנתונים שלך, אם האפליקציה הזו לא תהיה בשימוש במשך מספר חודשים, ההרשאות שניתנו לה יוסרו."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"כדי להגן על הנתונים שלך, אם האפליקציה לא תהיה בשימוש במשך מספר חודשים, ההרשאות הבאות יוסרו: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"כדי להגן על הנתונים שלך, הוסרו הרשאות מאפליקציות שלא השתמשת בהן במשך מספר חודשים."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"אפליקציית פתקים"</string>
<string name="role_notes_description" msgid="8496852798616883551">"אפליקציות שמאפשרות לך לרשום הערות במכשיר"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"הערות"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"ברירת המחדל הנוכחית"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"לא לשאול שוב"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"הגדרה כברירת מחדל"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"הצגת הזיהוי של הפעלת האסיסטנט"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"הצגת הסמל בשורת הסטטוס כשהמיקרופון בשימוש, לצורך הפעלת האסיסטנט"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; גישה לתמונות ולמדיה במכשיר שלך?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לתמונות ולמדיה במכשיר &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לאנשי הקשר במכשיר &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"‏לתת לאפליקציה &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"‏לתת לאפליקציה &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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ייתכן שהאפליקציה הזו תרצה לקבל גישה לנתוני המיקום שלך כל הזמן, גם כשהיא לא בשימוש. "<annotation id="link">"ניתן לאשר זאת בהגדרות."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"‏לשנות את הרשאת הגישה למיקום של &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"‏לשנות את הרשאת הגישה של האפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; למיקום במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"האפליקציה הזו רוצה לקבל גישה לנתוני המיקום שלך כל הזמן, גם כשהיא לא בשימוש. "<annotation id="link">"ניתן לאשר זאת בהגדרות."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"‏לאשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לאתר מכשירים קרובים, להתחבר אליהם ולזהות את מיקומם היחסי?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לאתר מכשירים קרובים, להתחבר אליהם ולזהות את מיקומם היחסי במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"‏לאשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לאתר מכשירים קרובים, להתחבר אליהם ולזהות את מיקומם היחסי? "<annotation id="link">"יש לתת הרשאה בהגדרות"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"לשנות את הרשאת הגישה של <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ממיקום משוער למיקום מדויק?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"‏לשנות את הרשאת הגישה של האפליקציה <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> למיקום במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה למיקום המשוער של מכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;’s?"</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="3103987548035171850">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה ליומן במכשיר &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לשלוח הודעות SMS ולראות אותן במכשיר &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לתמונות, למדיה ולקבצים במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"‏לתת לאפליקציה ‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎‏ הרשאת גישה ‎&lt;b&gt;‎‏לתמונות, לסרטונים, למוזיקה ולאודיו‎&lt;/b&gt;‎‏ במכשיר?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"‏לתת לאפליקציה ‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎‏ הרשאת גישה ‎&lt;b&gt;‎‏לתמונות, לסרטונים, למוזיקה, לאודיו ולקבצים אחרים‎&lt;/b&gt;‎‏ במכשיר?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"‏לתת לאפליקציה ‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎‏ הרשאת גישה למוזיקה ולקובצי אודיו במכשיר?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה למוזיקה ולאודיו במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"‏לתת לאפליקציה ‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎‏ הרשאת גישה לתמונות ולסרטונים במכשיר?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לתמונות ולסרטונים במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"‏לתת לאפליקציה ‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎‏ הרשאת גישה לתמונות ולסרטונים נוספים במכשיר?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לתמונות ולסרטונים נוספים במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"‏לאשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; להקליט אודיו?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה להקליט אודיו במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"האפליקציה תוכל להקליט אודיו רק כאשר היא בשימוש"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה להקליט אודיו?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה להקליט אודיו במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ייתכן שהאפליקציה הזו תרצה להקליט אודיו כל הזמן, גם כשהיא לא בשימוש. "<annotation id="link">"ניתן לאשר זאת בהגדרות."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"‏לשנות את הרשאת הגישה אל המיקרופון עבור &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"‏לשנות את הרשאת הגישה של האפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; למיקרופון במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"האפליקציה הזו רוצה להקליט אודיו כל הזמן, גם כשהיא לא בשימוש. "<annotation id="link">"ניתן לאשר זאת בהגדרות."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"‏האם לאפשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; גישה לפעילות הגופנית שלך?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לנתונים של הפעילות הגופנית במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"‏לאשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לצלם תמונות וסרטונים?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לצלם תמונות וסרטונים במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"האפליקציה תוכל לצלם תמונות וסרטונים רק כאשר היא בשימוש"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לצלם תמונות וסרטונים?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לצלם תמונות וסרטונים במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ייתכן שהאפליקציה הזו תרצה לצלם תמונות וסרטונים כל הזמן, גם כשהיא לא בשימוש. "<annotation id="link">"ניתן לאשר זאת בהגדרות."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"‏לשנות את הרשאת הגישה למצלמה של &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"‏לשנות את הרשאת הגישה למצלמה של האפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"האפליקציה זו רוצה לצלם תמונות ולהקליט סרטונים כל הזמן, גם כשהיא לא בשימוש. "<annotation id="link">"ניתן לאשר זאת בהגדרות."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה ליומני השיחות של הטלפון?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה ליומני השיחות של הטלפון במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לבצע ולנהל שיחות טלפון?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לבצע התקשרות ולנהל את שיחות הטלפון במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לנתוני חיישנים העוקבים אחר הסימנים החיוניים שלך?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לנתוני החיישנים שמודדים את הסימנים החיוניים במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"האפליקציה הזו מבקשת הרשאת גישה לנתוני החיישנים שמודדים את הסימנים החיוניים שלך כל הזמן, גם כשלא נעשה בה שימוש. כדי לשנות את ההגדרה הזו, "<annotation id="link">"צריך לעבור להגדרות"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"‏להעניק לאפליקציה &lt;b‏/&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>‏&lt;b&gt; הרשאת גישה לנתוני החיישנים שמודדים את הסימנים החיוניים שלך?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לנתוני החיישנים שמודדים את הסימנים החיוניים במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"כדי לאפשר לאפליקציה הזו לגשת לנתונים של החיישנים הגופניים כל הזמן, גם כשהיא לא בשימוש, "<annotation id="link">"צריך להיכנס להגדרות."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"‏להמשיך לאפשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לגשת לנתונים של חיישני גוף כשהיא נמצאת בשימוש?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"‏להמשיך לאפשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לגשת לנתונים של חיישנים גופניים במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; כשהיא בשימוש?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לשלוח לך התראות?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לשלוח לך התראות במכשיר &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"הרשאות בבקרה"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"לאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> יש הרשאת גישה למיקום"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"הארגון שלך מאפשר לאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לגשת למיקום שלך"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"הרשאות אחרות"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"הרשאות שהמערכת משתמשת בהן"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"הרשאות שרק אפליקציות מערכת משתמשות בהן."</string>
@@ -548,8 +585,8 @@
<string name="manage_permissions_qs" msgid="3780541819763475434">"ניהול הרשאות"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"בשימוש על ידי שיחת טלפון"</string>
<string name="recent_call_usage_qs" msgid="743044899599410935">"נעשה שימוש לאחרונה על ידי שיחת טלפון"</string>
- <string name="active_app_usage_qs" msgid="4063912870936464727">"בשימוש על ידי <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="recent_app_usage_qs" msgid="6650259601306212327">"נעשה שימוש לאחרונה על ידי <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="active_app_usage_qs" msgid="4063912870936464727">"בשימוש על ידי: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="recent_app_usage_qs" msgid="6650259601306212327">"נעשה שימוש לאחרונה על ידי: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="active_app_usage_1_qs" msgid="4325136375823357052">"בשימוש על ידי <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"נעשה שימוש לאחרונה על ידי <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="active_app_usage_2_qs" msgid="6107866785243565283">"בשימוש על ידי <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"האפליקציה הזו הצהירה שהיא עשויה לשתף נתוני מיקום עם צדדים שלישיים"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"שיתוף נתונים ומיקום"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"מאיפה מגיע המידע לגבי שיתוף הנתונים"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"מפתחי האפליקציה סיפקו מידע ליצרן המכשיר הזה על האופן שבו האפליקציה משתפת נתונים. המפתחים עשויים לעדכן את המידע הזה עם הזמן."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"‏המפתחים סיפקו מידע על האופן שבו האפליקציה משתפת נתונים כאן: "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". המפתחים עשויים לעדכן את המידע הזה עם הזמן."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"האפליקציה עשויה לשתף את נתוני המיקום למטרות הבאות:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"שיתוף הנתונים עשוי להיות שונה"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"אבטחת נתונים"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"ייתכן שנתוני המיקום ישותפו"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"מפתחי האפליקציה הזו הצהירו שהאפליקציה עשויה לשתף את נתוני המיקום שלך עם צדדים שלישיים"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"לא ניתן לפתוח את הקישור הזה"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"עדכונים לגבי שיתוף נתוני מיקום"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"בדיקת אפליקציות שהדרך שלהן לשתף נתוני מיקום השתנתה"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"באפליקציות האלה, השתנה האופן שבו הן עשויות לשתף את נתוני המיקום שלך. יכול להיות שהן לא שיתפו את הנתונים האלה בעבר, או שעכשיו הן משתפות את נתוני המיקום לצורכי פרסום ושיווק."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"עדכונים לגבי שיתוף הנתונים"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"בחלק מהאפליקציות, השתנה האופן שבו הן עשויות לשתף את נתוני המיקום שלך"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"הגדרות"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"תאריך גישה: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"גישה אתמול: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"תאריך גישה: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> ב-<xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-ja-v34/strings.xml b/PermissionController/res/values-ja-v34/strings.xml
index 5048fa031..1a27a1df1 100644
--- a/PermissionController/res/values-ja-v34/strings.xml
+++ b/PermissionController/res/values-ja-v34/strings.xml
@@ -20,8 +20,8 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"セキュリティとプライバシー"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"管理"</string>
<string name="health_connect_title" msgid="2132233890867430855">"ヘルスコネクト"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"健康に関するデータへのアプリのアクセス権を管理する"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"健康に関するデータへのアプリのアクセス権を管理します"</string>
<string name="location_settings" msgid="8863940440881290182">"位置情報へのアクセス"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"アプリとサービス。この設定が OFF の場合、緊急通報番号に発信したときは、マイクのデータが共有されることがあります。"</string>
- <string name="location_settings_subtitle" msgid="6846532794702613851">"アプリとサービス"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"アプリとサービスによるアクセス。この設定が OFF の場合でも、緊急通報番号に発信したときは、マイクのデータが共有されることがあります"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"アプリとサービスによるアクセス"</string>
</resources>
diff --git a/PermissionController/res/values-ja/strings.xml b/PermissionController/res/values-ja/strings.xml
index 890ccd894..a143b39de 100644
--- a/PermissionController/res/values-ja/strings.xml
+++ b/PermissionController/res/values-ja/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"詳細"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"すべて許可"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"常にすべて許可"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"アクセス制限を許可する"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"写真と動画を選択"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"さらに選択"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"他を選択しない"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"アプリ"</string>
<string name="app_permissions" msgid="3369917736607944781">"アプリの権限"</string>
<string name="unused_apps" msgid="2058057455175955094">"使用されていないアプリ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"このアプリがアクセスできる写真を変更します"</string>
<string name="no_unused_apps" msgid="12809387670415295">"使用されていないアプリはありません"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"使用していないアプリ: 0 個"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"最近の権限の許可 / 拒否"</string>
@@ -71,7 +73,7 @@
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{今日}=1{1 日前}other{# 日前}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"アプリを無効にする"</string>
<string name="app_disable_dlg_text" msgid="3126943217146120240">"このアプリを無効にすると、Android などの他のアプリが正しく動作しなくなるおそれがあります。このアプリはデバイスにプリインストールされているため、削除できません。無効にするには、このアプリをオフにし、デバイスにアプリが表示されないようにします。"</string>
- <string name="app_permission_manager" msgid="3903811137630909550">"権限マネージャー"</string>
+ <string name="app_permission_manager" msgid="3903811137630909550">"権限マネージャ"</string>
<string name="never_ask_again" msgid="4728762438198560329">"今後表示しない"</string>
<string name="no_permissions" msgid="3881676756371148563">"権限がありません"</string>
<string name="additional_permissions" msgid="5801285469338873430">"その他の権限"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"すべての権限"</string>
<string name="other_permissions" msgid="2901186127193849594">"その他のアプリ機能"</string>
<string name="permission_request_title" msgid="8790310151025020126">"権限のリクエスト"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear ではインストールやアンインストールはできません。"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可する権限の選択"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; が更新されました。このアプリに許可する権限を選択してください。"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"キャンセル"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"アプリが使用されていない場合に権限を削除"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"権限を削除して空き容量を増やす"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"使用していないアプリを一時停止する"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"使用していないアプリを管理する"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"権限と一時ファイルを削除し、通知を停止します"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"権限と一時ファイルを削除し、通知を停止し、アプリをアーカイブします"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"データ保護のため、このアプリが数か月使用されていない場合はアプリの権限が取り消されます。"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"データ保護のため、アプリが数か月使用されていない場合は以下の権限が取り消されます。<xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"データ保護のため、数か月使用していないアプリの権限を削除しました。"</string>
@@ -349,7 +351,7 @@
<string name="accessibility_service_dialog_bottom_text_multiple" msgid="7009848932395519852">"これらのアプリでは、画面、アクション、入力の表示、アクションの実行、ディスプレイの操作を行えます。"</string>
<string name="role_assistant_label" msgid="4727586018198208128">"デフォルトのデジタル アシスタント アプリ"</string>
<string name="role_assistant_short_label" msgid="3369003713187703399">"デジタル アシスタント アプリ"</string>
- <string name="role_assistant_description" msgid="6622458130459922952">"アシストアプリは、表示している画面の情報に基づいてアシスタントを提供します。一部のアプリはランチャーと音声入力サービスの両方に対応しており、統合されたアシスタントを提供します。"</string>
+ <string name="role_assistant_description" msgid="6622458130459922952">"アシストアプリは、表示している画面の情報に基づいてサポートを提供します。一部のアプリはランチャーと音声入力サービスの両方に対応しており、統合されたサポートを提供します。"</string>
<string name="role_browser_label" msgid="2877796144554070207">"デフォルトのブラウザアプリ"</string>
<string name="role_browser_short_label" msgid="6745009127123292296">"ブラウザアプリ"</string>
<string name="role_browser_description" msgid="3465253637499842671">"インターネットにアクセスするためのアプリです。タップしたリンクは、このアプリで開きます。"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"メモアプリ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"デバイスでメモの作成に使うアプリ"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"メモ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"現在のデフォルト"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"次回から表示しない"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"デフォルトに設定"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"アシスタントのトリガー検出を表示"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"マイクを使って音声アシスタントを有効にする場合にステータスバーにアイコンを表示する"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"デバイス内の写真やメディアへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="DEVICE">%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_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="2270563860206654757">"&lt;b&gt;<xliff:g id="DEVICE">%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_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="6641436550953715107">"&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="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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"このアプリは、未使用時も含め、常に位置情報にアクセスする可能性があります。"<annotation id="link">"[設定] で許可してください。"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に対する位置情報へのアクセス許可を変更しますか?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"このアプリは、未使用時も含め、常に位置情報へのアクセスを試みます。"<annotation id="link">"[設定] で許可してください。"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"付近のデバイスの検出、接続、相対位置の特定を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"付近のデバイスの検出、接続、相対位置の特定を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"<annotation id="link">"設定で許可してください。"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> の位置情報へのアクセスを「おおよそ」から「正確」に変更しますか?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"&lt;b&gt;<xliff:g id="DEVICE">%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="9001956706241104626">"&lt;b&gt;<xliff:g id="DEVICE">%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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="DEVICE">%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>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; での SMS メッセージの送信と表示を &lt;b&gt;<xliff:g id="APP_NAME">%1$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="872629037299467086">"&lt;b&gt;<xliff:g id="DEVICE">%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_storage_q_to_s" msgid="8213701872983685505">"このデバイス内の&lt;b&gt;写真、動画、音楽、音声&lt;/b&gt;へのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"このデバイス内の&lt;b&gt;写真、動画、音楽、音声など&lt;/b&gt;へのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"このデバイス内の音楽と音声へのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="DEVICE">%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_read_media_visual" msgid="5548780620779729975">"このデバイス内の写真と動画へのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="DEVICE">%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_more_photos" msgid="128933814654231321">"このデバイス内の他の写真や動画へのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="DEVICE">%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_microphone" msgid="2825208549114811299">"音声の録音を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_microphone" msgid="8510456971528228861">"アプリは、ユーザーがアプリを使用している場合のみ音声を録音できます"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"音声の録音を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"このアプリは、いつでも(ユーザーがアプリを使用していない場合でも)音声を録音する可能性があります。"<annotation id="link">"[設定] で許可してください。"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に対するマイクへのアクセス許可を変更しますか?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"このアプリは、いつでも(ユーザーがアプリを使用していない場合でも)音声を録音できる権限を求めています。"<annotation id="link">"[設定] で許可してください。"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"身体活動データへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="DEVICE">%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_camera" msgid="5123097035410002594">"写真と動画の撮影を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_camera" msgid="9085323239764667883">"アプリは、ユーザーがアプリを使用している場合のみ写真や動画を撮影できます"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"写真と動画の撮影を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"このアプリは、いつでも(ユーザーがアプリを使用していない場合でも)写真や動画を撮影する可能性があります。"<annotation id="link">"[設定] で許可してください。"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に対するカメラへのアクセス許可を変更しますか?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"このアプリは、いつでも(ユーザーがアプリを使用していない場合でも)写真や動画を撮影できる権限を求めています。"<annotation id="link">"[設定] で許可してください。"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"通話履歴へのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="DEVICE">%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_phone" msgid="1829234136997316752">"電話の発信と管理を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="DEVICE">%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_sensors" msgid="4397358316850652235">"バイタルサインに関するセンサーデータへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"このアプリは、未使用時も含め、常にバイタルサインに関するセンサーデータへのアクセスを試みます。これを変更するには、"<annotation id="link">"設定に移動"</annotation>"してください。"</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"バイタルサインに関するセンサーデータへのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"アプリの未使用時も、常にボディセンサー データにアクセスすることをこのアプリに許可するには、"<annotation id="link">"設定に移動"</annotation>"してください。"</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ボディセンサー データへのアクセスを、引き続きアプリの使用時のみ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="DEVICE">%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_notifications" msgid="6396739062335106181">"通知の送信を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="DEVICE">%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="auto_granted_permissions" msgid="6009452264824455892">"権限は管理されています"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> は位置情報にアクセスできます"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"<xliff:g id="APP_NAME">%1$s</xliff:g> が位置情報にアクセスすることを組織が許可します"</string>
@@ -510,14 +549,14 @@
<string name="privdash_label_location" msgid="6882400763866489291">"位置情報"</string>
<string name="privdash_label_other" msgid="3710394147423236033">"その他"</string>
<string name="privdash_label_none" msgid="5991866260360484858">"なし"</string>
- <string name="privdash_label_24h" msgid="1512532123865375319">"24 時間\n以内"</string>
+ <string name="privdash_label_24h" msgid="1512532123865375319">"過去 \n24 時間"</string>
<string name="privdash_label_7d" msgid="5645301995348656931">"過去\n7 日間"</string>
<string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"<xliff:g id="APP_NAME">%1$s</xliff:g> は Android によって保護されています。あなたのデータはこのデバイス上で処理されるため、このアプリの権限の使用状況はステータスバーやプライバシー ダッシュボードには表示されません。"</string>
<string name="exempt_info_label" msgid="6286190981253476699">"<xliff:g id="APP_NAME">%1$s</xliff:g> は Android によって保護されています。あなたのデータはこのデバイス上で処理されるため、このアプリの権限の使用状況はプライバシー ダッシュボードには表示されません。"</string>
<string name="blocked_camera_title" msgid="1128510551791284384">"デバイスのカメラがブロックされています"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"デバイスのマイクがブロックされています"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"デバイスの位置情報が OFF です"</string>
- <string name="blocked_sensor_summary" msgid="4443707628305027375">"アプリとサービス"</string>
+ <string name="blocked_sensor_summary" msgid="4443707628305027375">"アプリとサービスによるアクセス"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"緊急通報番号に発信したときは、マイクのデータが引き続き共有されることがあります。"</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"変更"</string>
<string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"セキュリティとプライバシー"</string>
@@ -570,26 +609,27 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"このアプリは最新バージョンの Android に対応していません。このアプリが音楽ファイルや音声ファイルにアクセスできない場合は、写真や動画へのアクセスも許可されません。"</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"このアプリは最新バージョンの Android に対応していません。このアプリが写真や動画にアクセスできる場合は、音楽ファイルや音声ファイルへのアクセスも許可されます。"</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"このアプリは最新バージョンの Android に対応していません。このアプリが音楽ファイルや音声ファイルにアクセスできない場合は、写真や動画へのアクセスも許可されません。"</string>
- <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"バックグラウンドでの位置情報へのアクセス権があるアプリの確認"</string>
- <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> は、閉じているときも、常に位置情報にアクセスできます"</string>
- <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"バックグラウンドでの位置情報へのアクセス権があるアプリの確認"</string>
- <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"このアプリは、閉じているときも、常に位置情報にアクセスできます。\n\n緊急情報アプリや緊急通報アプリのなかには、バックグラウンドで位置情報にアクセスできないと、意図したとおりに動作しないものがあります。"</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"バックグラウンドで位置情報にアクセスできるアプリを確認"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> は、開いていなくても常に位置情報にアクセスできます"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"バックグラウンドで位置情報にアクセスできるアプリを確認"</string>
+ <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="camera_toggle_title" msgid="1251201397431837666">"カメラへのアクセス"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"マイクへのアクセス"</string>
- <string name="perm_toggle_description" msgid="7801326363741451379">"アプリとサービス"</string>
- <string name="mic_toggle_description" msgid="9163104307990677157">"アプリとサービス。この設定が OFF の場合でも、緊急通報番号に発信するとマイクのデータが共有されることがあります。"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"アプリとサービスによるアクセス"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"アプリとサービスによるアクセス。この設定が OFF の場合でも、緊急通報番号に発信したときは、マイクのデータが共有されることがあります。"</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"位置情報にアクセスできるアプリとサービスを確認"</string>
- <string name="show_clip_access_notification_title" msgid="5168467637351109096">"クリップボードへのアクセスを表示"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"クリップボードにコピーしたテキストや画像などにアプリがアクセスすると、メッセージで通知する"</string>
- <string name="show_password_title" msgid="2877269286984684659">"パスワードの表示"</string>
- <string name="show_password_summary" msgid="1110166488865981610">"入力した文字を短い間表示する"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"クリップボードへのアクセスを通知"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"クリップボードにコピーしたテキストや画像などにアプリがアクセスすると、メッセージが表示されます"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"パスワードを表示"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"入力した文字を一瞬だけ表示します"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"このアプリは、位置情報をサードパーティと共有する可能性があります"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"データ共有と位置情報"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"データ共有情報の提供元"</string>
- <string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"デベロッパーは、このアプリがデータを共有する方法に関する情報を "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" に提供しています。この情報は時間が経つと更新される可能性があります。"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"デベロッパーは、このデバイスのメーカーに、このアプリによるデータ共有方法についての情報を提供しています。この情報は将来更新される場合があります。"</string>
+ <string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"デベロッパーは、このアプリによるデータ共有方法についての情報を "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" に提供しています。この情報は将来更新される場合があります。"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"このアプリが位置情報を共有する目的"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"さまざまなデータ共有方法"</string>
<string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"データの取り扱いは、アプリのバージョンや使用方法、ユーザーの年齢やお住まいの地域によって異なることがあります。"<annotation id="link">"データ共有の詳細"</annotation></string>
@@ -606,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"データ セーフティ"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"位置情報が共有されることがあります"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"このアプリは位置情報をサードパーティと共有することがあります"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"このリンクを開くことができません"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"位置情報を共有する方法の更新"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"ユーザーの位置情報を共有する方法が変更されたアプリを確認できます"</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"ユーザーの位置情報を共有する方法が変更されたアプリを確認します"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"これらのアプリで、ユーザーの位置情報を共有する方法が変更されました。以前は共有していなかったか、広告またはマーケティングの目的で共有されるようになった可能性があります。"</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"これらのアプリのデベロッパーは、データの共有方法に関する情報をアプリストアに提供しています。この情報は時間が経つと更新される可能性があります。\n\nデータの共有方法は、アプリのバージョンや使用方法、ユーザーの年齢やお住まいの地域によって異なることがあります。"</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"データ共有の詳細"</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"データ共有に関する更新"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"ユーザーの位置情報を共有する方法が変更されたアプリがあります"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"設定"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g> にアクセス"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"昨日の <xliff:g id="TIME_DATE">%1$s</xliff:g> にアクセス"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g> にアクセス"</string>
</resources>
diff --git a/PermissionController/res/values-ka-v33/strings.xml b/PermissionController/res/values-ka-v33/strings.xml
index 5e668e51d..f92c9ebe8 100644
--- a/PermissionController/res/values-ka-v33/strings.xml
+++ b/PermissionController/res/values-ka-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"სხვა გაფრთხილებები"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"დახურული გაფრთხილებები"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{გააფართოვეთ და ნახეთ კიდევ ერთი გაფრთხილება}other{გააფართოვეთ და იხილეთ კიდევ # გაფრთხილება}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"გაფრთხილება. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"მოქმედება დასრულებულია"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"შეამოწმეთ პარამეტრები თქვენი მოწყობილობის უსაფრთხოების გასაძლიერებლად"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"უსაფრთხოებისა და კონფიდენციალურობის სწრაფი პარამეტრები"</string>
diff --git a/PermissionController/res/values-ka/strings.xml b/PermissionController/res/values-ka/strings.xml
index 3de674f1c..ef77ad748 100644
--- a/PermissionController/res/values-ka/strings.xml
+++ b/PermissionController/res/values-ka/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"მეტი ინფორმაცია"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"ყველას დაშვება"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"ყოველთვის ყველას დაშვება"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"შეზღუდული წვდომის დაშვება"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ფოტოებისა და ვიდეოების არჩევა"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"მეტის არჩევა"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ნუ აირჩევთ მეტს"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"მეტის აღარ არჩევა"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"მაინც არ დაიშვას"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"დახურვა"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>-დან"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"აპები"</string>
<string name="app_permissions" msgid="3369917736607944781">"აპის ნებართვები"</string>
<string name="unused_apps" msgid="2058057455175955094">"გამოუყენებელი აპები"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"დაარედაქტირეთ არჩეული ფოტოები ამ აპისთვის"</string>
<string name="no_unused_apps" msgid="12809387670415295">"გამოუყენებელი აპები არ არის"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 გამოუყენებელი აპი"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"ნებართვის შეს. უახ. გადაწყვეტ."</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"ყველა ნებართვა"</string>
<string name="other_permissions" msgid="2901186127193849594">"აპის სხვა შესაძლებლობები"</string>
<string name="permission_request_title" msgid="8790310151025020126">"ნებართვის მოთხოვნა"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"ინსტალაციის/დეინსტალაციის მოქმედებები არ არის მხარდაჭერილი Wear-ზე."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"აირჩიეთ, რაზე ჰქონდეს წვდომა &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; განახლდა. აირჩიეთ, რაზე ჰქონდეს წვდომა ამ აპს."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"გაუქმება"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ნებართვების ამოშლა აპის გამოუყენებლობის შემთხვევაში."</string>
<string name="unused_apps_label" msgid="2595428768404901064">"ნებართვების ამოშლა და მეხსიერების გათავისუფლება"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"დაპაუზდეს აპში აქტივობა, თუ არ იყენებენ"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"აპის მართვა გამოუყენებლობის შემთხვევაში"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ნებართვების ამოშლა, დროებითი ფაილების წაშლა და შეტყობინებების გამორთვა"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ნებართვების ამოშლა, დროებითი ფაილების წაშლა, შეტყობინებების გამორთვა და აპის დაარქივება"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"თქვენი მონაცემების დასაცავად ნებართვები ამოიშლება ამ აპიდან, თუ ის რამდენიმე თვის განმავლობაში არ გამოგიყენებიათ."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"თქვენი მონაცემების დაცვის მიზნით, თუ აპს რამდენიმე თვის განმავლობაში არ გამოიყენებთ, ამოიშლება შემდეგი ნებართვები: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"თქვენი მონაცემების დასაცავად ნებართვები ამოიშალა აპებიდან, რომლებიც რამდენიმე თვის განმავლობაში არ გამოგიყენებიათ."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"ჩანიშვნების აპი"</string>
<string name="role_notes_description" msgid="8496852798616883551">"აპები, რომლებიც საშუალებას გაძლევთ, გააკეთოთ ჩანიშვნები თქვენს მოწყობილობაზე"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ჩანიშვნები"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"ამჟამინდელი ნაგულისხმევი"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"აღარ მკითხოთ"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ნაგულისხმ. დაყენება"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"ასისტენტის გაშვების ხატულის ჩვენება"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"მიკროფონის მეშვეობით ხმოვანი ასისტენტის გააქტიურებისას სტატუსის ზოლში ხატულის ჩვენება"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს თქვენს მოწყობილობაზე არსებულ ფოტოებსა და მედია-კონტენტზე წვდომის ნებართვა?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა ფოტოებსა და მედიაზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა თქვენს კონტაქტებზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"ნებას დართავთ &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"ნებას დართავთ &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>-ის მდებარეობაზე?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"აპი ითხოვს თქვენს მდებარეობაზე წვდომას ნებისმიერ დროს, მაშინაც კი, როცა მას არ იყენებთ. "<annotation id="link">"დაუშვით პარამეტრებიდან."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"გსურთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის&lt;/b&gt; მდებარეობაზე წვდომის შეცვლა?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"შეცვლით მდებარეობაზე წვდომას &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპისთვის თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"აპი ითხოვს თქვენს მდებარეობაზე წვდომას ნებისმიერ დროს, მაშინაც კი, როცა მას არ იყენებთ. "<annotation id="link">"დაუშვით პარამეტრებიდან."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"მიეცეს საშუალება &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს იპოვოს ახლომახლო მოწყობილობები, დაუკავშირდეს მათ და დაადგინოს პოზიცია მათ მიმართ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, იპოვოს, დაუკავშირდეს და დაადგინოს ახლომახლო მოწყობილობების შედარებითი პოზიცია თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"მიეცეს საშუალება &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს იპოვოს ახლომახლო მოწყობილობები, დაუკავშირდეს მათ და დაადგინოს პოზიცია მათ მიმართ? "<annotation id="link">"დაუშვით პარამეტრებიდან."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"შეიცვალოს <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>-ის მდებარეობაზე წვდომა მიახლოებითის მაგიერ ზუსტით?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"შეცვლით <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>-ის მდებარეობის (მიახლოებითს ზუსტით) წვდომას თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა თქვენი &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა თქვენს კალენდარზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, გაგზავნოს და ნახოს SMS შეტყობინებები თქვენს &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა ფოტოებზე, მედიასა და ფაილებზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"მიანიჭებთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს წვდომას ამ მოწყ. &lt;b&gt;ფოტოებზე, ვიდეოებზე, მუსიკასა და აუდიოფაილებზე&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"მიანიჭებთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ის წვდომას თქვენი მოწყ. &lt;b&gt;ფოტოებზე, ვიდეოებზე, მუსიკაზე, აუდიო და სხვა &lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"მიანიჭებთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს წვდომას თქვენი მოწყობილობის მუსიკასა და აუდიოფაილებზე?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა მუსიკასა და აუდიოზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"მიანიჭებთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს წვდომას თქვენი მოწყობილობის ფოტოებსა და ვიდეოებზე?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"მიანიჭეთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს წვდომა თქვენი მოწყობილობის ფოტოებსა და ვიდეოებზე?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა ფოტოებსა და ვიდეოებზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"მიენიჭოს &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს წვდომა თქვენი მოწყობილობის ფოტოებსა და ვიდეოებზე?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა მეტ ფოტოსა და ვიდეოზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/b&gt; აუდიოს ჩაწერის ნებართვა?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჩაწეროს აუდიო თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"ეს აპი აუდიოს ჩაწერას მხოლოდ მაშინ შეძლებს, როცა მას იყენებთ"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/b&gt; აუდიოს ჩაწერის ნებართვა?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჩაწეროს აუდიო თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ამ აპს შეუძლია აუდიოს ჩაწერა ნებისმიერ დროს, მაშინაც კი, როცა აპს არ იყენებთ. "<annotation id="link">"დაუშვით პარამეტრებიდან."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"გსურთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის&lt;/b&gt; მიკროფონის წვდომის შეცვლა?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"შეცვლით მიკროფონზე წვდომას &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპისთვის თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"ეს აპი აუდიოს ჩაწერს ნებისმიერ დროს, მაშინაც კი, როცა აპს არ იყენებთ. "<annotation id="link">"Allow in settings."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს თქვენს ფიზიკურ აქტივობაზე წვდომის ნებართვა?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა თქვენს ფიზიკურ აქტივობაზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/b&gt; სურათების გადაღების და ვიდეოების ჩაწერის ნებართვა?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, გადაიღოს სურათები და ჩაწეროს ვიდეო თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"ეს აპი სურათების გადაღებას და ვიდეოს ჩაწერას მხოლოდ მაშინ შეძლებს, როცა მას იყენებთ"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/b&gt; სურათების გადაღების და ვიდეოების ჩაწერის ნებართვა?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, გადაიღოს სურათები და ჩაწეროს ვიდეო თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ამ აპს შეუძლია სურათების გადაღება და ვიდეოს ჩაწერა ნებისმიერ დროს, მაშინაც კი, როცა აპს არ იყენებთ. "<annotation id="link">"დაუშვით პარამეტრებიდან."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"გსურთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის&lt;/b&gt; კამერის წვდომის შეცვლა?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"შეცვლით კამერაზე წვდომას &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპისთვის თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"ეს აპი სურათების გადაიღებს და ვიდეოს ჩაწერს ნებისმიერ დროს, მაშინაც კი, როცა აპს არ იყენებთ. "<annotation id="link">"დაუშვით პარამეტრებიდან."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს თქვენს ზარების ჟურნალებზე წვდომის ნებართვა?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა თქვენი ტელ-ის ზარების ჟურნალზე &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/b&gt; სატელეფონო ზარების განხორციელების და მართვის ნებართვა?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, განახორციელოს და მართოს სატელეფ. ზარები თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/b&gt; თქვენი სასიცოცხლო ფუნქციების შესახებ სენსორის მონაცემებზე წვდომის ნებართვა?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა სენსორის მონაცემებზე (სასიცოცხლო მაჩვენებლები) &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"ეს აპი ითხოვს თქვენი სასიცოცხლო ფუნქციების შესახებ სენსორის მონაცემებზე წვდომას ნებისმიერ დროს, მაშინაც კი, როცა აპს არ იყენებთ. ამ ცვლილებისთვის "<annotation id="link">"გადადით პარამეტრებზე."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"გსურთ, მიანიჭოთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს თქვენი სასიცოცხლო ფუნქციების შესახებ სენსორის მონაცემებზე წვდომის ნებართვა?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, ჰქონდეს წვდომა სენსორის მონაცემებზე (სასიცოცხლო მაჩვენებლები) &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"ამ აპისთვის სხეულის სენსორების მონაცემებზე მუდმივი წვდომის მისანიჭებლად (მაშინაც კი, როცა აპს არ იყენებთ), "<annotation id="link">"გადადით პარამეტრებზე."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"გსურთ გამოყენებისას &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს მიანიჭოთ სხეულის სენსორების მონაცემებზე წვდომა?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, გამოყენებისას ჰქონდეს წვდომა სხეულის სენსორების მონაცემებზე თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"მისცემთ უფლებას &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ს, გამოგიგზავნოთ შეტყობინებები?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"ნებას დართავთ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; აპს, გამოგიგზავნოთ შეტყობინებები თქვენს &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;-ზე?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"კონტროლირებული ნებართვები"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს მდებარეობაზე წვდომა აქვს"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"თქვენი ორგანიზაცია ნებას რთავს <xliff:g id="APP_NAME">%1$s</xliff:g>-ს, წვდომა ჰქონდეს თქვენ მდებარეობაზე"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"სხვა ნებართვები"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"ნებართვები, რომლებსაც სისტემა იყენებს"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"ნებართვები, რომლებსაც მხოლოდ სისტემის აპლიკაციები იყენებს."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"ამ აპის თანახმად, მან შესაძლოა გაუზიაროს მდებარეობის მონაცემები მესამე მხარეს"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"მონაცემთა გაზიარება და მდებარეობა"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"საიდან მოდის მონაცემთა გაზიარების ინფორმაცია"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"დეველოპერმა მოცემული მოწყობილობის მწარმოებელს მიაწოდა ინფორმაცია ამ აპის მიერ ინფორმაციის გაზიარების შესახებ. დეველოპერმა, შესაძლოა, დროთა განმავლობაში განაახლოს ეს ინფორმაცია."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"დეველოპერმა ინფორმაცია დაურთო "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"-ს ამ აპის მიერ ინფორმაციის გაზიარების შესახებ. დეველოპერმა შესაძლოა, დროთა განმავლობაში განაახლოს ეს ინფორმაცია."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"აპმა შესაძლოა, გაუზიაროს მდებარეობის მონაცემები:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"მონაცემთა გაზიარება განსხვავდება"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"მონაცემთა უსაფრთხოება"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"მდებარეობის მონაცემები შესაძლოა გაზიარებულია"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"ამ აპის თანახმად, მან შესაძლოა გაუზიაროს თქვენი მდებარეობის მონაცემები მესამე მხარეს"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ამ ბმულის გახსნა შეუძლებელია"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"მონაცემების გაზიარ. განახლებები მდებარეობისთვის"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"გადახედეთ აპებს, რომლებშიც შეიცვალა თქვენი მდებარეობის მონაცემების გაზიარების მეთოდი"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"ამ აპებმა შეცვალა თქვენი მდებარეობის მონაცემების გაზიარების გზები. შესაძლოა, ისინი ადრე არ გაუზიარებიათ, ან გაზიარდა ახლა რეკლამირების ან მარკეტინგული მიზნით."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"მონაცემთა გაზიარების განახლება"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"ზოგიერთმა აპმა შეცვალა თქვენი მდებარეობის მონაც. გაზიარების გზები"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"პარამეტრები"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"წვდომა განხორციელდა: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"წვდომა განხორციელდა გუშინ: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"წვდომა განხორციელდა: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-kk-v33/strings.xml b/PermissionController/res/values-kk-v33/strings.xml
index 06da81337..9538c1503 100644
--- a/PermissionController/res/values-kk-v33/strings.xml
+++ b/PermissionController/res/values-kk-v33/strings.xml
@@ -30,10 +30,9 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Басқа хабарландырулар"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Жабылған хабарландырулар"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Тағы бір хабарландыруды жаю және көру}other{Тағы # хабарландыруды жаю және көру}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Ескерту. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Әрекет аяқталды."</string>
- <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Құрығыңыздың қауіпсіздігін арттыруы ықтимал параметрлерді тексеріңіз."</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Құрығыңыздың қауіпсіздігін арттыратын параметрлерді тексеріңіз."</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Қауіпсіздік және құпиялық жылдам параметрлері"</string>
<string name="safety_center_qs_close_button" msgid="1352313308176244599">"Жабу"</string>
<string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Опцияларды жаю және көрсету"</string>
@@ -41,7 +40,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-kk-v34/strings.xml b/PermissionController/res/values-kk-v34/strings.xml
index 45ed52f2f..002624b5a 100644
--- a/PermissionController/res/values-kk-v34/strings.xml
+++ b/PermissionController/res/values-kk-v34/strings.xml
@@ -23,5 +23,5 @@
<string name="health_connect_summary" msgid="815473513776882296">"Қолданбаның денсаулық деректерін пайдалану рұқсатын басқару"</string>
<string name="location_settings" msgid="8863940440881290182">"Локацияны пайдалану рұқсаты"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"Қолданбалар мен қызметтерге арналған. Бұл параметр өшірілсе де, құтқару қызметінің нөміріне қоңырау шалғанда, микрофон деректері жіберілуі мүмкін."</string>
- <string name="location_settings_subtitle" msgid="6846532794702613851">"Қолданбалар мен қызметтер үшін"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Қолданбалар мен қызметтерге арналған."</string>
</resources>
diff --git a/PermissionController/res/values-kk/strings.xml b/PermissionController/res/values-kk/strings.xml
index 862cb1c12..8617e8bfb 100644
--- a/PermissionController/res/values-kk/strings.xml
+++ b/PermissionController/res/values-kk/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Толығырақ"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Бәріне рұқсат беру"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Әрдайым бәріне рұқсат беру"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Шектеулі рұқсат беру"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Фотосуреттер мен бейнелерді таңдау"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Тағы таңдау"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Тағы басқасын таңдамау"</string>
@@ -41,7 +42,7 @@
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Жабу"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына <xliff:g id="ACTION">%2$s</xliff:g> рұқсатын беру керек пе?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы үшін <xliff:g id="ACTION">%2$s</xliff:g> әрекетіне әрқашан рұқсат етілсін бе?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына <xliff:g id="ACTION">%2$s</xliff:g> рұқсаты әрдайым берілсін бе?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Қолданба пайдаланылғанда ғана"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Әрқашан"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Рұқсат бермеу және қайта сұрамау"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Қолданбалар"</string>
<string name="app_permissions" msgid="3369917736607944781">"Қолданба рұқсаттары"</string>
<string name="unused_apps" msgid="2058057455175955094">"Пайдаланылмайтын қолданбалар"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Осы қолданба пайдалана алатын фотосуреттер тізімін өзгертеді."</string>
<string name="no_unused_apps" msgid="12809387670415295">"Пайдаланылмайтын қолданбалар жоқ"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 пайдаланылмайтын қолданба бар"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Рұқсат беру әрекеттері"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Барлық рұқсаттар"</string>
<string name="other_permissions" msgid="2901186127193849594">"Басқа қолданба мүмкіндіктері"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Рұқсат сұрау"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear жүйесінде \"Орнату\"/\"Жою\" әрекеттері қолданылмайды."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы қайда кіре алатынын таңдаңыз"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы жаңартылды. Бұл қолданбаның қайда кіре алатынын таңдаңыз."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Бас тарту"</string>
@@ -163,7 +163,7 @@
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Рұқсаттың соңғы 1 минутта пайдаланылуы"</string>
<string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Соңғы # күнде пайдаланылмады.}other{Соңғы # күнде пайдаланылмады.}}"</string>
<string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Соңғы # сағатта пайдаланылмады.}other{Соңғы # сағатта пайдаланылмады.}}"</string>
- <string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 қолданба пайдаланды}other{# қолданба пайдаланды}}"</string>
+ <string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 қолданба пайдаланды.}other{# қолданба пайдаланды.}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Барлығын бақылау тақтасынан көру"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Сүзгі шарты: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_usage_remove_filter" msgid="2926157607436428207">"Сүзгіні өшіру"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Қолданба пайдаланылмаса, рұқсаттарды өшіру"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Рұқсаттарды өшіру және орын босату"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Әрекетсіз қолданба жұмысын кідірту"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Қолданба пайдаланылмаса, оны басқарыңыз."</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Рұқсаттарды өшіру, уақытша файлдарды жою және хабарландыруларды тоқтату"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Рұқсаттарды өшіру, уақытша файлдарды жою, хабарландыруларды тоқтату және қолданбаны мұрағаттау."</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Бұл қолданба бірнеше ай бойы пайдаланылмаса, деректеріңізді қорғау үшін оған берілген рұқсаттар өшіріледі."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Қолданба бірнеше ай бойы пайдаланылмаса, деректеріңізді қорғау үшін мына рұқсаттар өшіріледі: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Бірнеше ай бойы пайдаланылмаған қолданбаларға берілген рұқсаттар деректеріңізді қорғау үшін өшірілді."</string>
@@ -258,12 +260,12 @@
<string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# минут}other{# минут}}"</string>
<string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# секунд}other{# секунд}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Рұқсат туралы еске салғыштар"</string>
- <string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 пайдаланылмайтын қолданба"</string>
- <string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> пайдаланылмайтын қолданба бар"</string>
+ <string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 қолданба пайдаланылмайды"</string>
+ <string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> қолданба пайдаланылмайды бар"</string>
<string name="auto_revoke_permission_reminder_notification_content" msgid="4492228990462107487">"Құпиялықты қорғау үшін рұқсаттар өшірілді. Көру үшін түртіңіз."</string>
<string name="auto_revoke_permission_notification_title" msgid="2629844160853454657">"Пайдаланылмайтын қолданбалар үшін рұқсаттар өшірілді"</string>
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Кейбір қолданбалар бірнеше ай бойы пайдаланылмаған. Көру үшін түртіңіз."</string>
- <string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# пайдаланылмайтын қолданба}other{# пайдаланылмайтын қолданба}}"</string>
+ <string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# қолданба пайдаланылмайды}other{# қолданба пайдаланылмайды}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Рұқсаттар мен уақытша файлдар өшірілді және хабарландырулар тоқтатылды. Көру үшін түртіңіз."</string>
<string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Рұқсаттары өшірілген қолданбаларды қарап шығыңыз"</string>
<string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Біраз уақыттан бері пайдаланылмаған қолданбалар бойынша рұқсаттар мен уақытша файлдар өшірілді және хабарландырулар тоқтатылды."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Ескертпелер қолданбасы"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Құрылғыда ескертпелер жазуға арналған қолданбалар"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ескертпелер"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Ағымдағы әдепкі қолданба"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Қайта сұралмасын"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Әдепкі етіп орнату"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Көмекшінің іске қосылғанын анықтауды көрсету"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Микрофон арқылы дауыс көмекшісін іске қосқанда, күй жолағында белгішені көрсету"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$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_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>’s&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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> құрылғысының локациясын пайдалану рұқсаты берілсін бе?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Қолданбаны пайдаланбасаңыз да, ол үнемі геодеректеріңізді пайдаланғысы келуі мүмкін. "<annotation id="link">"Параметрлерден рұқсат беріңіз."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына геодеректі пайдалануға рұқсат етілсін бе?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы үшін &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында локацияны пайдалану рұқсатын өзгерту керек пе?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Қолданбаны пайдаланбасаңыз да, ол үнемі геодеректеріңізді пайдаланғысы келеді. "<annotation id="link">"Параметрлерден рұқсат беріңіз."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына маңайдағы құрылғыларды табуға, олармен байланысуға және олардың орналасуын анықтауға рұқсат берілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында маңайдағы құрылғыларды табу, олармен байланысу және қатысты локациясын анықтау рұқсаты берілсін бе?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына маңайдағы құрылғыларды табуға, олармен байланысуға және олардың орналасуын анықтауға рұқсат берілсін бе? "<annotation id="link">"Параметрлерден рұқсат бере аласыз."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> қолданбасының болжалды емес, нақты локацияны пайдалануына рұқсат беру керек пе?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> қолданбасының &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында SMS хабарларын жіберу және көру рұқсаты берілсін бе?"</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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысындағы фотосуреттерді, медиа және файлдарды пайдалану рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына осы құрылғыдағы &lt;b&gt;фотосурет, бейне, музыка мен аудионы&lt;/b&gt; пайдалану рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына осы құрылғыдағы &lt;b&gt;фотосурет, бейне, музыка, аудио мен басқа файлдарды&lt;/b&gt; пайдалану рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына осы құрылғыдағы музыка мен аудионы пайдалану рұқсаты берілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысындағы музыка мен аудионы пайдалану рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына осы құрылғыдағы фотосурет пен бейнені пайдалану рұқсаты берілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысындағы фотосуреттер мен бейнелерді пайдалану рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы осы құрылғыдағы басқа фотосуреттер мен бейнелерді пайдалансын ба?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында басқа фотосуреттер мен бейнелерді пайдалану рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына дыбыс жазуға рұқсат берілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында аудио жазу рұқсаты берілсін бе?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Қолданба тек жұмыс кезінде ғана аудиомазмұн жаза алады."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына аудиомазмұн жазуға рұқсат берілсін бе?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында аудио жазу рұқсаты берілсін бе?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Қолданбаны пайдаланбасаңыз да, ол кез келген уақытта бейнелерді жаза алады. "<annotation id="link">"Параметрлерден рұқсат беріңіз."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына микрофонды пайдалануға рұқсат етілсін бе?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы үшін &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында микрофонды пайдалану рұқсатын өзгерту керек пе?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Қолданбаны пайдаланбасаңыз да, ол кез келген уақытта аудиомазмұн жазғысы келеді. "<annotation id="link">"Параметрлерден рұқсат беріңіз."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына қимыл-қозғалыс дерегін алуға рұқсат етілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында қимыл-қозғалыс деректерін пайдалану рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына суретке түсіруге және бейне жазуға рұқсат берілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында суретке түсіру және бейне жазу рұқсаты берілсін бе?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Қолданба тек жұмыс кезінде ғана суретке түсіріп, бейне жаза алады."</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына суретке түсіруге және бейне жазуға рұқсат берілсін бе?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында суретке түсіру және бейне жазу рұқсаты берілсін бе?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Қолданбаны пайдаланбасаңыз да, ол кез келген уақытта суретке түсіріп, бейнелер жаза алады. "<annotation id="link">"Параметрлерден рұқсат беріңіз."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына камераны пайдалануға рұқсат етілсін бе?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы үшін &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысындағы камераны пайдалану рұқсатын өзгерту керек пе?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Қолданбаны пайдаланбасаңыз да, ол кез келген уақытта суретке түсіріп, бейне жазғысы келеді. "<annotation id="link">"Параметрлерден рұқсат беріңіз."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына телефонның қоңыраулар журналына кіруге рұқсат берілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында қоңырау журналдарын пайдалану рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына қоңырау шалуға және қоңырауларды басқаруға рұқсат берілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында қоңыраулар шалу және басқару рұқсаты берілсін бе?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына негізгі физиологиялық көрсеткіштерді көрсететін сенсорлық деректерді пайдалануға рұқсат берілсін бе?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында тіршілік көрсеткіштеріне қатысты датчик деректерін пайдалану рұқсаты берілсін бе?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Қолданбаны пайдаланбасаңыз да, ол әрдайым тіршілік көрсеткіштері туралы датчик дерегін пайдалануға рұқсат сұрайды. Мұны өзгерту үшін "<annotation id="link">"параметрлерге өтіңіз."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына тіршілік көрсеткіштеріне қатысты датчик деректерін пайдалануға рұқсат берілсін бе?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында тіршілік көрсеткіштеріңіз туралы датчик деректерін пайдалану рұқсаты берілсін бе?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Бұл қолданбаға кез келген уақытта (ол пайдаланылмаған кезде де) дене датчигінен алынған деректі пайдалануға рұқсат беру үшін "<annotation id="link">"параметрлерге өтіңіз."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Жұмыс кезінде &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы дене датчигінен алынған деректі одан әрі пайдалана берсін бе?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Жұмыс кезінде &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында дене датчигінен алынған деректі одан әрі пайдалана берсін бе?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы хабарландыру жіберсін бе?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; құрылғысында хабарландыру жіберу рұқсаты берілсін бе?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Басқарылатын рұқсаттар"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы локацияны пайдаланады"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Ұйымыңыз <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасына локацияңызды пайдалануға рұқсат береді."</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Басқа рұқсаттар"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Жүйе пайдаланатын рұқсаттар"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Тек жүйе қолданбалары пайдаланатын рұқсаттар."</string>
@@ -516,8 +553,8 @@
<string name="privdash_label_7d" msgid="5645301995348656931">"Соңғы\n7 күн"</string>
<string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын Android қорғайды. Деректеріңіз осы құрылғыда өңделетіндіктен, бұл қолданба рұқсатының пайдаланылуы күй жолағында немесе құпиялық тақтасында көрсетілмейді."</string>
<string name="exempt_info_label" msgid="6286190981253476699">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын Android қорғайды. Деректеріңіз осы құрылғыда өңделетіндіктен, бұл қолданба рұқсатының пайдаланылуы құпиялық тақтасында көрсетілмейді."</string>
- <string name="blocked_camera_title" msgid="1128510551791284384">"Құрылғы камерасы бөгелген"</string>
- <string name="blocked_microphone_title" msgid="1631517143648232585">"Құрылғы микрофоны бөгелген"</string>
+ <string name="blocked_camera_title" msgid="1128510551791284384">"Құрылғы камерасы блокталған"</string>
+ <string name="blocked_microphone_title" msgid="1631517143648232585">"Құрылғы микрофоны блокталған"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"Құрылғы геодерегі өшірулі"</string>
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Қолданбалар мен қызметтер үшін"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Құтқару қызметінің нөміріне қоңырау шалу кезінде микрофон деректері әлі бөлісіліп жатуы мүмкін."</string>
@@ -548,11 +585,11 @@
<string name="manage_permissions_qs" msgid="3780541819763475434">"Рұқсаттарды басқару"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Телефон қоңырауы үшін пайдаланылуда."</string>
<string name="recent_call_usage_qs" msgid="743044899599410935">"Соңғы рет телефон қоңырауы үшін пайдаланылды."</string>
- <string name="active_app_usage_qs" msgid="4063912870936464727">"<xliff:g id="APP_NAME">%1$s</xliff:g> пайдалануда."</string>
+ <string name="active_app_usage_qs" msgid="4063912870936464727">"<xliff:g id="APP_NAME">%1$s</xliff:g> пайдаланып жатыр."</string>
<string name="recent_app_usage_qs" msgid="6650259601306212327">"Соңғы рет <xliff:g id="APP_NAME">%1$s</xliff:g> пайдаланды."</string>
- <string name="active_app_usage_1_qs" msgid="4325136375823357052">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) пайдалануда."</string>
+ <string name="active_app_usage_1_qs" msgid="4325136375823357052">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) пайдаланып жатыр."</string>
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Соңғы рет <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) пайдаланды."</string>
- <string name="active_app_usage_2_qs" msgid="6107866785243565283">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) пайдалануда."</string>
+ <string name="active_app_usage_2_qs" msgid="6107866785243565283">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) пайдаланып жатыр."</string>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Соңғы рет <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) пайдаланды."</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Растау"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Артқа"</string>
@@ -581,7 +618,7 @@
<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>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Қолданбалар мен қызметтерге арналған."</string>
<string name="mic_toggle_description" msgid="9163104307990677157">"Қолданбалар мен қызметтерге арналған. Бұл параметр өшірілсе де, құтқару қызметінің нөміріне қоңырау шалғанда, микрофон деректері жіберілуі мүмкін."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Локацияны пайдалана алатын қолданбалар мен қызметтерді көру"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Буфер пайдаланылғанын көрсету"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Бұл қолданба геодеректі үшінші тараптармен бөлісуі мүмкін екенін мәлімдеді."</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Деректерді бөлісу және локация"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Деректерді бөлісу туралы ақпарат қайдан алынады?"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Әзірлеуші осы құрылғының өндірушісіне қолданбаның деректерді қалай бөлісетіні туралы ақпарат берді. Әзірлеуші бұл ақпаратты уақыт өте келе жаңарта алады."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Әзірлеуші "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" қызметінде бұл қолданбаның деректерді бөлісу жолы туралы ақпарат берді. Ол бұл ақпаратты уақыт өте келе жаңарта алады."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Қолданбаның локация деректерін бөлісу мақсаттары:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Деректерді бөлісу әртүрлі болады"</string>
@@ -608,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Дерек қауіпсіздігі"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Локация деректері жіберілуі мүмкін."</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Бұл қолданба локация деректеріңізді үшінші тараптармен бөлісе алатынын мәлімдеді."</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Бұл сілтемені ашу мүмкін емес"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Локация деректерін бөлісу жаңартулары"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"Локация деректеріңізді бөлісу жолын өзгерткен қолданбаларды қарап шығыңыз."</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"Локация деректеріңізді бөлісу жолын өзгерткен қолданбаларды тексеру"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Осы қолданбалар локация деректерін бөлісу жолын өзгертті. Олар деректерді бұрын бөліспей, енді жарнамалау не маркетинг үшін бөлісуі мүмкін."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Бұл қолданбалардың әзірлеушілері App Store дүкенінде өздерінің деректерді бөлісу тәртібі туралы ақпарат берді. Олар уақыт өте келе оны жаңарта алады.\n\nДеректерді бөлісу тәртібі қолданбаңыздың нұсқасына, пайдаланылуына, аймағыңыз бен жасыңызға байланысты әртүрлі болуы мүмкін."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Деректерді бөлісу туралы ақпарат"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Деректерді бөлісуге қатысты жаңалық"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Кейбір қолданбалар локация деректеріңізді бөлісу жолын өзгертті."</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Параметрлер"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Пайдаланылған уақыты: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Кеше пайдаланылған уақыты: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Пайдаланылған уақыты: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-km/strings.xml b/PermissionController/res/values-km/strings.xml
index 81d05b141..49088e767 100644
--- a/PermissionController/res/values-km/strings.xml
+++ b/PermissionController/res/values-km/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"ព័ត៌មាន​បន្ថែម"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"អនុញ្ញាតទាំងអស់"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"អនុញ្ញាតទាំងអស់ជានិច្ច"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"អនុញ្ញាតឱ្យចូលប្រើដោយមានកម្រិត"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ជ្រើសរើស​រូបថត និង​វីដេអូ"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"ជ្រើសរើស​ច្រើន​ទៀត"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"កុំជ្រើសរើសទៀត"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"មិនអីទេ មិនអនុញ្ញាត"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"ច្រានចោល"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> ក្នុងចំណោម <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g> មែនទេ?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g> ជានិច្ចមែនទេ?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>​មែនទេ?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>​ជានិច្ចមែនទេ?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"ខណៈពេលប្រើ​កម្មវិធីតែប៉ុណ្ណោះ"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"ជានិច្ច"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"មិនអនុញ្ញាត និងកុំសួរម្ដងទៀត"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"កម្មវិធី"</string>
<string name="app_permissions" msgid="3369917736607944781">"ការអនុញ្ញាតកម្មវិធី"</string>
<string name="unused_apps" msgid="2058057455175955094">"កម្មវិធី​ដែលមិន​ប្រើ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"កែរូបថតដែលបានជ្រើសរើសសម្រាប់កម្មវិធីនេះ"</string>
<string name="no_unused_apps" msgid="12809387670415295">"មិនមានកម្មវិធីដែលមិនបានប្រើទេ"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"កម្មវិធី​ដែលមិន​ប្រើ 0"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"ការសម្រេចថ្មីៗលើការអនុញ្ញាត"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"ការអនុញ្ញាត​ទាំងអស់"</string>
<string name="other_permissions" msgid="2901186127193849594">"សមត្ថភាពកម្មវិធីផ្សេងទៀត"</string>
<string name="permission_request_title" msgid="8790310151025020126">"សំណើសុំ​ការអនុញ្ញាត"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"សកម្មភាព​ដំឡើង/លុបចេញមិនអាចប្រើ​នៅលើ Wear បានទេ។"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"ជ្រើសរើស​អ្វីដែលត្រូវ​អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើ"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ត្រូវបាន​ដំឡើងជំនាន់។ ជ្រើសរើស​អ្វីដែលត្រូវ​អនុញ្ញាតឱ្យ​កម្មវិធីនេះ​ចូលប្រើ។"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"បោះបង់"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ដកការ​អនុញ្ញាតចេញ ប្រសិនបើ​មិនប្រើប្រាស់​កម្មវិធី"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"ដក​ការអនុញ្ញាតចេញ និងបង្កើន​ទំហំផ្ទុក"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"ផ្អាក​សកម្មភាព​កម្មវិធី ប្រសិនបើមិនប្រើ"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"គ្រប់គ្រងកម្មវិធី ប្រសិនបើមិនបានប្រើ"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ដកការអនុញ្ញាតចេញ លុបឯកសារបណ្ដោះអាសន្ន និងបញ្ឈប់ការជូនដំណឹង"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ដកការអនុញ្ញាតចេញ លុបឯកសារបណ្ដោះអាសន្ន បញ្ឈប់ការជូនដំណឹង និងទុកកម្មវិធីក្នុងបណ្ណសារ"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"ដើម្បីការពារ​ទិន្នន័យរបស់អ្នក ការអនុញ្ញាត​សម្រាប់កម្មវិធីនេះ​នឹងត្រូវ​ដកចេញ ប្រសិនបើ​មិនប្រើប្រាស់​កម្មវិធីនេះ​រយៈពេល​ពីរបីខែ។"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"ដើម្បីការពារ​ទិន្នន័យរបស់អ្នក ការអនុញ្ញាត​ខាងក្រោម​នឹងត្រូវដកចេញ ប្រសិនបើ​មិនប្រើប្រាស់​កម្មវិធីនេះ​រយៈពេល​ពីរបីខែ៖ <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"ដើម្បីការពារ​ទិន្នន័យរបស់អ្នក ការអនុញ្ញាត​ត្រូវបាន​ដកចេញ​ពីកម្មវិធី​ដែល​អ្នកមិនបាន​ប្រើប្រាស់​រយៈពេល​ពីរបីខែ។"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"កម្មវិធី​កំណត់ចំណាំ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"កម្មវិធីដែលអនុញ្ញាតឱ្យអ្នក​កត់ចំណាំនៅលើឧបករណ៍របស់អ្នក"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"កំណត់ចំណាំ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"លំនាំដើម​បច្ចុប្បន្ន"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"កុំសួរទៀត"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"កំណត់ជាលំនាំដើម"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"បង្ហាញការ​ចាប់សញ្ញា​របស់ជំនួយការ"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"បង្ហាញ​រូបតំណាង​នៅក្នុង​របារស្ថានភាព នៅពេលប្រើប្រាស់​មីក្រូហ្វូន​ ដើម្បី​បើកដំណើរការ​ជំនួយការសំឡេង"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើ​រូបថត និង​មេឌៀ​នៅលើ​ឧបករណ៍​របស់អ្នក?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើរូបថត និងមេឌៀនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើទំនាក់ទំនងរបស់អ្នកនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"អនុញ្ញាតឱ្យ &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>’s&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"អនុញ្ញាតឱ្យ &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> របស់អ្នកឬ?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"កម្មវិធីនេះ​ប្រហែលជា​ចង់ចូលប្រើ​ទីតាំង​របស់អ្នក​គ្រប់ពេល ទោះបីជា​អ្នកមិនកំពុងប្រើ​កម្មវិធីនេះ​ក៏ដោយ។ "<annotation id="link">"អនុញ្ញាត​នៅក្នុងការកំណត់។"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"ប្ដូរសិទ្ធិ​ចូលប្រើ​ទីតាំង​សម្រាប់ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ដែរទេ?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"ប្ដូរសិទ្ធិចូលប្រើទីតាំងសម្រាប់ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; នៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"កម្មវិធីនេះ​ចង់ចូលប្រើ​ទីតាំង​របស់អ្នក​គ្រប់ពេល ទោះបីជា​អ្នកមិនកំពុងប្រើ​កម្មវិធីនេះ​ក៏ដោយ។ "<annotation id="link">"អនុញ្ញាត​នៅក្នុងការកំណត់។"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ស្វែងរក ភ្ជាប់ទៅ និងកំណត់ទីតាំង​ដែលពាក់ព័ន្ធនៃ​ឧបករណ៍ដែលនៅជិតឬ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ស្វែងរក ភ្ជាប់ទៅ និងកំណត់ទីតាំងដែលពាក់ព័ន្ធនៃឧបករណ៍នៅជិតនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ស្វែងរក ភ្ជាប់ទៅ និងកំណត់ទីតាំង​ដែលពាក់ព័ន្ធនៃ​ឧបករណ៍ដែលនៅជិតឬ? "<annotation id="link">"អនុញ្ញាតនៅក្នុងការកំណត់។"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"ផ្លាស់ប្ដូរ​ការចូលប្រើ​ទីតាំងរបស់ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ពីទីតាំងប្រហាក់ប្រហែល​ទៅជាក់លាក់ឬ?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"ប្ដូរសិទ្ធិចូលប្រើទីតាំងរបស់ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> នៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើទីតាំងប្រហាក់ប្រហែលនៃ &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើប្រតិទិនរបស់អ្នកនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ផ្ញើ និងមើលសារ SMS នៅលើ &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើរូបថត មេឌៀ និងឯកសារនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើប្រាស់&lt;b&gt;រូបថត វីដេអូ តន្ត្រី និងសំឡេង&lt;/b&gt;នៅលើឧបករណ៍នេះទេ?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើ &lt;b&gt;រូបថត វីដេអូ តន្ត្រី សំឡេង និងឯកសារផ្សេងទៀត&lt;/b&gt;នៅលើឧបករណ៍នេះទេ?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើប្រាស់តន្ត្រី និងសំឡេងនៅលើឧបករណ៍នេះទេ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើតន្ត្រី និងសំឡេងនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើប្រាស់រូបថត និងវីដេអូនៅលើឧបករណ៍នេះទេ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើរូបថត និងវីដេអូនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើប្រាស់រូបថត និងវីដេអូច្រើនទៀតនៅលើឧបករណ៍នេះឬ?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើរូបថត និងវីដេអូច្រើនទៀតនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ថតសំឡេង?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ថតសំឡេងនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"កម្មវិធីនេះនឹងអាចថតសំឡេង នៅពេលអ្នកកំពុងប្រើប្រាស់កម្មវិធីតែប៉ុណ្ណោះ"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ថតសំឡេងឬ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ថតសំឡេងនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"កម្មវិធីនេះអាចចង់ថតសំឡេងគ្រប់ពេល ទោះបីជានៅពេលអ្នកមិនកំពុងប្រើប្រាស់កម្មវិធីក៏ដោយ។ "<annotation id="link">"អនុញ្ញាតនៅក្នុងការកំណត់។"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"ប្ដូរសិទ្ធិ​ចូលប្រើ​មីក្រូហ្វូន​សម្រាប់ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ឬ?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"ប្ដូរសិទ្ធិចូលប្រើមីក្រូហ្វូនសម្រាប់ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; នៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"កម្មវិធីនេះចង់ថតសំឡេងគ្រប់ពេល ទោះបីជានៅពេលអ្នកមិនកំពុងប្រើប្រាស់កម្មវិធីក៏ដោយ។ "<annotation id="link">"អនុញ្ញាតនៅក្នុងការកំណត់។"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើ​សកម្មភាព​រាងកាយ​របស់អ្នក?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើសកម្មភាព​រាងកាយរបស់អ្នកនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ថតរូប និងថត​វីដេអូ?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ថតរូបភាព និងថតវីដេអូនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"កម្មវិធីនេះនឹងអាចថតរូប និងវីដេអូ នៅពេលអ្នកកំពុងប្រើប្រាស់កម្មវិធីតែប៉ុណ្ណោះ"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ថតរូប និងថត​វីដេអូឬ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ថតរូបភាព និងថតវីដេអូនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"កម្មវិធីនេះអាចចង់ថតរូប និងវីដេអូគ្រប់ពេល ទោះបីជានៅពេលអ្នកមិនកំពុងប្រើប្រាស់កម្មវិធីក៏ដោយ។ "<annotation id="link">"អនុញ្ញាតនៅក្នុងការកំណត់។"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"ប្ដូរសិទ្ធិ​ចូលប្រើ​កាមេរ៉ាសម្រាប់ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ឬ?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"ប្ដូរសិទ្ធិចូលប្រើកាមេរ៉ាសម្រាប់ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; នៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"កម្មវិធីនេះចង់ថតរូប និងវីដេអូគ្រប់ពេល ទោះបីជានៅពេលអ្នកមិនកំពុងប្រើប្រាស់កម្មវិធីក៏ដោយ។ "<annotation id="link">"អនុញ្ញាតនៅក្នុងការកំណត់។"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"អនុញ្ញាត​ឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូល​ប្រើ​កំណត់ហេតុ​ហៅទូរសព្ទ​របស់អ្នក?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើកំណត់​ហេតុ​ហៅ​ទូរសព្ទរបស់អ្នកនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; គ្រប់គ្រង និង​ធ្វើការហៅទូរសព្ទ?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; គ្រប់គ្រង និងធ្វើការហៅទូរសព្ទនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើ​ទិន្នន័យឧបករណ៍ចាប់សញ្ញាអំពីស្ថានភាពសុខភាពរបស់អ្នក?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើទិន្នន័យសេនស័រអំពីសញ្ញាសរីរាង្គសំខាន់ៗរបស់អ្នកនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"កម្មវិធីនេះចង់ចូលប្រើទិន្នន័យឧបករណ៍ចាប់សញ្ញាអំពីស្ថានភាពសុខភាពរបស់អ្នកគ្រប់ពេល ទោះបីជានៅពេលអ្នកមិនកំពុងប្រើកម្មវិធីនេះក៏ដោយ។ ដើម្បីធ្វើការផ្លាស់ប្ដូរនេះ សូម"<annotation id="link">"ចូលទៅកាន់ការកំណត់។"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើទិន្នន័យ​ឧបករណ៍ចាប់សញ្ញា​អំពីស្ថានភាពសុខភាព​របស់អ្នកឬ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើទិន្នន័យសេនស័រអំពីសញ្ញាសរីរាង្គសំខាន់ៗរបស់អ្នកនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"ដើម្បីអនុញ្ញាតឱ្យកម្មវិធីនេះចូលប្រើទិន្នន័យឧបករណ៍ចាប់សញ្ញារាងកាយគ្រប់ពេល ទោះបីជានៅពេលអ្នកមិនកំពុងប្រើកម្មវិធីនេះក៏ដោយ "<annotation id="link">"សូមចូលទៅកាន់ការកំណត់។"</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"បន្តអនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើទិន្នន័យឧបករណ៍ចាប់សញ្ញារាងកាយ ខណៈពេលកំពុងប្រើកម្មវិធីឬ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"បន្តអនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ចូលប្រើទិន្នន័យសេនស័ររាងកាយនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នក ពេលកំពុងប្រើកម្មវិធីឬ?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ផ្ញើ​ការជូនដំណឹង​ឱ្យអ្នកឬ?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"អនុញ្ញាតឱ្យ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ផ្ញើការជូនដំណឹងដល់អ្នកនៅលើ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; របស់អ្នកឬ?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"ការអនុញ្ញាត​ដែលស្ថិតក្រោម​ការគ្រប់គ្រង"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> មានសិទ្ធិចូលប្រើទីតាំង"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"ស្ថាប័នរបស់អ្នកអនុញ្ញាតឱ្យ <xliff:g id="APP_NAME">%1$s</xliff:g> ចូលប្រើទីតាំងរបស់អ្នក"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"កម្មវិធីនេះបានបញ្ជាក់ថា វាអាចចែករំលែកទិន្នន័យទីតាំងជាមួយភាគីទីបី"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ការចែករំលែកទិន្នន័យ និងទីតាំង"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"កន្លែងដែលព័ត៌មាន​អំពីការចែករំលែក​ទិន្នន័យបានមកពី"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"អ្នកអភិវឌ្ឍន៍បានផ្ដល់ព័ត៌មាន​ដល់ក្រុមហ៊ុនផលិតឧបករណ៍នេះ​អំពីរបៀបដែលកម្មវិធីនេះ​ចែករំលែកទិន្នន័យ។ អ្នក​អភិវឌ្ឍន៍អាចនឹងធ្វើបច្ចុប្បន្នភាព​ព័ត៌មាននេះ​ទៅតាមពេលវេលា។"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"អ្នកអភិវឌ្ឍន៍​បានផ្ដល់ព័ត៌មានដល់ "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" អំពីរបៀបដែល​កម្មវិធីនេះ​ចែករំលែកទិន្នន័យ។ អ្នក​អភិវឌ្ឍន៍អាចនឹងធ្វើបច្ចុប្បន្នភាព​ព័ត៌មាននេះ​ទៅតាមពេលវេលា។"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"កម្មវិធីនេះ​អាចនឹងចែករំលែក​ទិន្នន័យទីតាំងសម្រាប់៖"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ភាពខុសគ្នានៃ​ការចែករំលែកទិន្នន័យ"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"សុវត្ថិភាព​ទិន្នន័យ"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"ទិន្នន័យទីតាំងអាចនឹង​ត្រូវបានចែករំលែក"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"កម្មវិធីនេះ​បានបញ្ជាក់ថា វាអាចចែករំលែក​ទិន្នន័យទីតាំងរបស់អ្នក​ជាមួយភាគីទីបី"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"មិនអាចបើកតំណនេះបានទេ"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"បច្ចុប្បន្នភាពការចែករំលែកទិន្នន័យសម្រាប់ទីតាំង"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ពិនិត្យមើលកម្មវិធីដែលបានផ្លាស់ប្ដូររបៀបដែលកម្មវិធីទាំងនោះអាចចែករំលែកទិន្នន័យទីតាំងរបស់អ្នក"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"កម្មវិធីទាំងនេះ​បានផ្លាស់ប្ដូររបៀបដែលវា​អាចចែករំលែកទិន្នន័យ​ទីតាំងរបស់អ្នក។ កម្មវិធីទាំងនេះ​ប្រហែលជាមិនបានចែករំលែកទិន្នន័យទីតាំងពីមុនទេ ឬឥឡូវនេះប្រហែលជា​ចែករំលែកទិន្នន័យទីតាំងនេះ​សម្រាប់គោលបំណង​ផ្សាយពាណិជ្ជកម្ម ឬធ្វើទីផ្សារ។"</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"បច្ចុប្បន្នភាពការចែករំលែកទិន្នន័យ"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"កម្មវិធីមួយចំនួន​បានផ្លាស់ប្ដូររបៀបដែលវាអាចចែករំលែកទិន្នន័យ​ទីតាំងរបស់អ្នក"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ការកំណត់"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"បានចូលប្រើនៅម៉ោង <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"បានចូលប្រើម្សិលមិញនៅម៉ោង <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"បានចូលប្រើនៅថ្ងៃទី <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-kn-v33/strings.xml b/PermissionController/res/values-kn-v33/strings.xml
index 8179b964a..f4d39d7ac 100644
--- a/PermissionController/res/values-kn-v33/strings.xml
+++ b/PermissionController/res/values-kn-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"ಇನ್ನಷ್ಟು ಎಚ್ಚರಿಕೆಗಳು"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"ವಜಾಗೊಳಿಸಿದ ಎಚ್ಚರಿಕೆಗಳು"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{ವಿಸ್ತರಿಸಿ ಮತ್ತು ಇನ್ನೊಂದು ಎಚ್ಚರಿಕೆಯನ್ನು ನೋಡಿ}one{ವಿಸ್ತರಿಸಿ ಮತ್ತು # ಹೆಚ್ಚಿನ ಎಚ್ಚರಿಕೆಗಳನ್ನು ನೋಡಿ}other{ವಿಸ್ತರಿಸಿ ಮತ್ತು # ಹೆಚ್ಚಿನ ಎಚ್ಚರಿಕೆಗಳನ್ನು ನೋಡಿ}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"ಅಲರ್ಟ್. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"ಆ್ಯಕ್ಷನ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ರಕ್ಷಣೆಯನ್ನು ಸೇರಿಸಬಹುದಾದ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"ಭದ್ರತೆ ಮತ್ತು ಗೌಪ್ಯತೆ ಕುರಿತ ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
diff --git a/PermissionController/res/values-kn/strings.xml b/PermissionController/res/values-kn/strings.xml
index 1698eea2c..2f98be5a9 100644
--- a/PermissionController/res/values-kn/strings.xml
+++ b/PermissionController/res/values-kn/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"ಹೆಚ್ಚಿನ ಮಾಹಿತಿ"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"ಎಲ್ಲವನ್ನೂ ಅನುಮತಿಸಿ"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"ಯಾವಾಗಲೂ ಎಲ್ಲವನ್ನೂ ಅನುಮತಿಸಿ"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"ಸೀಮಿತ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"ಇನ್ನಷ್ಟು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ಹೆಚ್ಚಿನ ಫೋಟೋಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಬೇಡಿ"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ಆ್ಯಪ್‌ಗಳು"</string>
<string name="app_permissions" msgid="3369917736607944781">"ಆ್ಯಪ್ ಅನುಮತಿಗಳು"</string>
<string name="unused_apps" msgid="2058057455175955094">"ಬಳಕೆಯಾಗದ ಆ್ಯಪ್‌ಗಳು"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ಈ ಆ್ಯಪ್‌ಗಾಗಿ ಆಯ್ಕೆಮಾಡಲಾದ ಫೋಟೋಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ಯಾವುದೇ ಬಳಕೆಯಾಗದ ಆ್ಯಪ್‌ಗಳಿಲ್ಲ"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ಬಳಕೆಯಾಗದ ಆ್ಯಪ್‌ಗಳು"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"ಇತ್ತೀಚಿನ ಅನುಮತಿ ನಿರ್ಧಾರಗಳು"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"ಎಲ್ಲಾ ಅನುಮತಿಗಳು"</string>
<string name="other_permissions" msgid="2901186127193849594">"ಇತರ ಆ್ಯಪ್‌ ಸಾಮರ್ಥ್ಯಗಳು"</string>
<string name="permission_request_title" msgid="8790310151025020126">"ಅನುಮತಿಯ ವಿನಂತಿ"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್/ಅನ್ಇನ್‌ಸ್ಟಾಲ್ ಕ್ರಿಯೆಗಳು ಬೆಂಬಲಿತವಾಗಿಲ್ಲ."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಆ್ಯಪ್‌ಗೆ ಪ್ರವೇಶಿಸಲು ಯಾವುದನ್ನು ಅನುಮತಿಸಬೇಕು ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಆ್ಯಪ್ ಅನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ. ಈ ಆ್ಯಪ್‌ಗೆ ಪ್ರವೇಶಿಸಲು ಯಾವುದನ್ನು ಅನುಮತಿಸಬೇಕು ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಿ."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"ರದ್ದುಮಾಡಿ"</string>
@@ -149,12 +149,12 @@
<string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# ಗಂಟೆಯ ಹಿಂದೆ}one{ಕೊನೆಯ # ಗಂಟೆಗಳು}other{ಕೊನೆಯ # ಗಂಟೆಗಳು}}"</string>
<string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{ಕಳೆದ # ನಿಮಿಷ}one{ಹಿಂದಿನ # ನಿಮಿಷಗಳು}other{ಹಿಂದಿನ # ನಿಮಿಷಗಳು}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"ಅನುಮತಿಯ ಬಳಕೆಗಳು ಇಲ್ಲ"</string>
- <string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಪ್ರವೇಶ"</string>
- <string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"ಕಳೆದ 7 ದಿನಗಳಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಪ್ರವೇಶ"</string>
- <string name="permission_usage_list_title_last_day" msgid="8730907824567238461">"ಕಳೆದ 24 ಗಂಟೆಗಳಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಪ್ರವೇಶ"</string>
- <string name="permission_usage_list_title_last_hour" msgid="6624161487623223716">"ಕಳೆದ 1 ಗಂಟೆಯಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಪ್ರವೇಶ"</string>
- <string name="permission_usage_list_title_last_15_minutes" msgid="8615062016024296833">"ಕಳೆದ 15 ನಿಮಿಷಗಳಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಪ್ರವೇಶ"</string>
- <string name="permission_usage_list_title_last_minute" msgid="3572792262919886849">"ಕಳೆದ 1 ನಿಮಿಷದಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಪ್ರವೇಶ"</string>
+ <string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್"</string>
+ <string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"ಕಳೆದ 7 ದಿನಗಳಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್"</string>
+ <string name="permission_usage_list_title_last_day" msgid="8730907824567238461">"ಕಳೆದ 24 ಗಂಟೆಗಳಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್"</string>
+ <string name="permission_usage_list_title_last_hour" msgid="6624161487623223716">"ಕಳೆದ 1 ಗಂಟೆಯಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್"</string>
+ <string name="permission_usage_list_title_last_15_minutes" msgid="8615062016024296833">"ಕಳೆದ 15 ನಿಮಿಷಗಳಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್"</string>
+ <string name="permission_usage_list_title_last_minute" msgid="3572792262919886849">"ಕಳೆದ 1 ನಿಮಿಷದಲ್ಲಿನ ತೀರಾ ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್"</string>
<string name="permission_usage_bar_chart_title_any_time" msgid="2845251288192246754">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿನ ಅನುಮತಿಯ ಬಳಕೆ"</string>
<string name="permission_usage_bar_chart_title_last_7_days" msgid="5796577162176938349">"ಕಳೆದ 7 ದಿನಗಳಲ್ಲಿನ ಅನುಮತಿಯ ಬಳಕೆ"</string>
<string name="permission_usage_bar_chart_title_last_day" msgid="7950805735777472871">"ಕಳೆದ 24 ಗಂಟೆಗಳಲ್ಲಿನ ಅನುಮತಿಯ ಬಳಕೆ"</string>
@@ -181,8 +181,8 @@
<string name="permission_history_category_today" msgid="7496389369158806620">"ಇಂದು"</string>
<string name="permission_history_category_yesterday" msgid="7242517121222012521">"ನಿನ್ನೆ"</string>
<string name="app_permission_usage_title" msgid="6676802437831981822">"ಆ್ಯಪ್‌ ಅನುಮತಿಗಳ ಬಳಕೆ"</string>
- <string name="app_permission_usage_summary" msgid="390383661936709672">"ಪ್ರವೇಶ: <xliff:g id="NUM">%1$s</xliff:g> ಬಾರಿ. ಒಟ್ಟು ಅವಧಿ: <xliff:g id="DURATION">%2$s</xliff:g>. <xliff:g id="TIME">%3$s</xliff:g> ಸಮಯದ ಹಿಂದೆ ಕೊನೆಯದಾಗಿ ಬಳಸಲಾಗಿದೆ."</string>
- <string name="app_permission_usage_summary_no_duration" msgid="3698475875179457400">"ಪ್ರವೇಶ: <xliff:g id="NUM">%1$s</xliff:g> ಬಾರಿ. <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯದ ಹಿಂದೆ ಕೊನೆಯದಾಗಿ ಬಳಸಲಾಗಿದೆ."</string>
+ <string name="app_permission_usage_summary" msgid="390383661936709672">"ಆ್ಯಕ್ಸೆಸ್: <xliff:g id="NUM">%1$s</xliff:g> ಬಾರಿ. ಒಟ್ಟು ಅವಧಿ: <xliff:g id="DURATION">%2$s</xliff:g>. <xliff:g id="TIME">%3$s</xliff:g> ಸಮಯದ ಹಿಂದೆ ಕೊನೆಯದಾಗಿ ಬಳಸಲಾಗಿದೆ."</string>
+ <string name="app_permission_usage_summary_no_duration" msgid="3698475875179457400">"ಆ್ಯಕ್ಸೆಸ್: <xliff:g id="NUM">%1$s</xliff:g> ಬಾರಿ. <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯದ ಹಿಂದೆ ಕೊನೆಯದಾಗಿ ಬಳಸಲಾಗಿದೆ."</string>
<string name="app_permission_button_allow" msgid="5808039516494774647">"ಅನುಮತಿಸಿ"</string>
<string name="app_permission_button_allow_all_files" msgid="1792232272599018825">"ಎಲ್ಲಾ ಫೈಲ್‌ಗಳ ನಿರ್ವಹಣೆಯನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"ಮಾಧ್ಯಮಕ್ಕೆ ಮಾತ್ರ ಪ್ರವೇಶಿಸಲು ಅನುಮತಿಸಿ"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ಆ್ಯಪ್‌ ಬಳಸದಿದ್ದರೆ ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"ಅನುಮತಿಗಳನ್ನು ತೆಗೆಯಿರಿ, ಸ್ಥಳ ಮುಕ್ತಗೊಳಿಸಿ"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"ಬಳಸದಿದ್ದರೆ, ಆ್ಯಪ್‌ನ ಚಟುವಟಿಕೆಯನ್ನು ವಿರಾಮಗೊಳಿಸಿ"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ಬಳಸದಿದ್ದರೆ ಆ್ಯಪ್ ಅನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಿ, ತಾತ್ಕಾಲಿಕ ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸಿ ಹಾಗೂ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿಲ್ಲಿಸಿ"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಿ, ತಾತ್ಕಾಲಿಕ ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸಿ, ನೋಟಿಫಿಕೇಶನ್‌ಗಳನ್ನು ನಿಲ್ಲಿಸಿ ಮತ್ತು ಆ್ಯಪ್ ಅನ್ನು ಆರ್ಕೈವ್ ಮಾಡಿ"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"ಆ್ಯಪ್ ಅನ್ನು ಕೆಲವು ತಿಂಗಳುಗಳ ಕಾಲ ಬಳಸದಿದ್ದರೆ, ನಿಮ್ಮ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ಈ ಆ್ಯಪ್‌ನ ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗುವುದು."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"ಆ್ಯಪ್ ಅನ್ನು ಕೆಲವು ತಿಂಗಳುಗಳ ಕಾಲ ಬಳಸದಿದ್ದರೆ, ನಿಮ್ಮ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು, ಈ ಕೆಳಗಿನ ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗುವುದು: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"ನಿಮ್ಮ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು, ಕೆಲವು ತಿಂಗಳುಗಳಿಂದ ನೀವು ಬಳಸದಿರುವ ಆ್ಯಪ್‌ಗಳಿಂದ ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ."</string>
@@ -241,7 +243,7 @@
<string name="permission_description_summary_storage" msgid="6575759089065303346">"ಈ ಅನುಮತಿಯ ಜೊತೆಗೆ ಆ್ಯಪ್‌ಗಳು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಬಹುದು"</string>
<string name="permission_description_summary_read_media_aural" msgid="3354728149930482199">"ಈ ಅನುಮತಿಯನ್ನು ಹೊಂದಿರುವ ಆ್ಯಪ್‌ಗಳು ಈ ಸಾಧನದಲ್ಲಿನ ಸಂಗೀತ ಮತ್ತು ಇತರ ಆಡಿಯೋ ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಬಹುದು"</string>
<string name="permission_description_summary_read_media_visual" msgid="4991801977881732641">"ಈ ಅನುಮತಿಯನ್ನು ಹೊಂದಿರುವ ಆ್ಯಪ್‌ಗಳು ಈ ಸಾಧನದಲ್ಲಿನ ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಪ್ರವೇಶಿಸಬಹುದು"</string>
- <string name="app_permission_most_recent_summary" msgid="4292074449384040590">"ಕೊನೆಯ ಪ್ರವೇಶ:<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="app_permission_most_recent_summary" msgid="4292074449384040590">"ಕೊನೆಯ ಆ್ಯಕ್ಸೆಸ್:<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"ಪ್ರಸ್ತುತ ನಿರಾಕರಿಸಿರುವುದು / ಕೊನೆಯದಾಗಿ ಪ್ರವೇಶಿಸಿರುವುದು: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"ಎಂದಿಗೂ ಪ್ರವೇಶಿಸಿಲ್ಲ"</string>
<string name="app_permission_never_accessed_denied_summary" msgid="6596000497490905146">"ನಿರಾಕರಿಸಲಾಗಿದೆ / ಎಂದಿಗೂ ಪ್ರವೇಶಿಸಲಾಗಿಲ್ಲ"</string>
@@ -282,13 +284,13 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"ನಿಮ್ಮ ಗೌಪ್ಯತೆಯನ್ನು ರಕ್ಷಿಸಲು ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ಹಿನ್ನಲೆಯಲ್ಲಿ ಪಡೆದುಕೊಂಡಿದೆ"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"ಈ ಆ್ಯಪ್‌ ಯಾವಾಗಲೂ ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳಿಗೆ ಪ್ರವೇಶ ಹೊಂದಿರುವ ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"ನಿಮ್ಮ ನೋಟಿಫಿಕೇಶನ್‌ಗಳಿಗೆ ಆ್ಯಕ್ಸೆಸ್ ಹೊಂದಿರುವ ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
<string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಜಾಗೊಳಿಸಬಹುದು, ಕ್ರಮ ಕೈಗೊಳ್ಳಬಹುದು ಹಾಗೂ ಅದರಲ್ಲಿರುವ ವಿಷಯವನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದು"</string>
<string name="notification_listener_warning_card_content" msgid="7840973324284115893">"ಈ ಆ್ಯಪ್ ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಜಾಗೊಳಿಸಬಹುದು, ಕ್ರಮ ಕೈಗೊಳ್ಳಬಹುದು ಹಾಗೂ ಅದರಲ್ಲಿರುವ ವಿಷಯವನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದು. ಕೆಲವು ಆ್ಯಪ್‌ಗಳು ಉದ್ದೇಶಿಸಿದಂತೆ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಅವುಗಳಿಗೆ ಈ ಆ್ಯಕ್ಸೆಸ್‌ನ ಅಗತ್ಯವಿದೆ."</string>
<string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"ಪ್ರವೇಶವನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
<string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"ಮತ್ತಷ್ಟು ಆಯ್ಕೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"ಪ್ರವೇಶವನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
- <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"ಪೂರ್ಣ ಸಾಧನ ಪ್ರವೇಶ ಹೊಂದಿರುವ ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"ಪೂರ್ಣ ಸಾಧನ ಆ್ಯಕ್ಸೆಸ್ ಹೊಂದಿರುವ ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
<string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> ಆ್ಯಪ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದು ಮತ್ತು ಸಾಧನದಲ್ಲಿ ಕ್ರಿಯೆಗಳನ್ನು ಮಾಡಬಹುದು. ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಆ್ಯಪ್‌ಗಳು ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಈ ರೀತಿಯ ಪ್ರವೇಶದ ಅಗತ್ಯವಿದೆ."</string>
<string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"ಈ ಆ್ಯಪ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದು ಮತ್ತು ಸಾಧನದಲ್ಲಿ ಕ್ರಿಯೆಗಳನ್ನು ಮಾಡಬಹುದು. ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಆ್ಯಪ್‌ಗಳು ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಈ ರೀತಿಯ ಪ್ರವೇಶದ ಅಗತ್ಯವಿದೆ, ಆದರೆ ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ ಮತ್ತು ನೀವು ಅದನ್ನು ನಂಬುತ್ತೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."</string>
<string name="accessibility_remove_access_button_label" msgid="44145801526711640">"ಪ್ರವೇಶವನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
@@ -398,12 +400,22 @@
<string name="role_app_streaming_description" msgid="7341638576226183992">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಆ್ಯಪ್‌ಗಳನ್ನು ಸಂಪರ್ಕಿತ ಸಾಧನಕ್ಕೆ ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"ಈ ಸೇವೆಯು ನಿಮ್ಮ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಹಾಗೂ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿಮ್ಮ ಫೋನ್‌ನಿಂದ ಇತರ ಸಾಧನಗಳ ಜೊತೆ ಹಂಚಿಕೊಳ್ಳುತ್ತದೆ."</string>
<string name="role_notes_label" msgid="7451627001058089536">"ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್"</string>
- <string name="role_notes_short_label" msgid="8796604147546125285">"ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್"</string>
+ <string name="role_notes_short_label" msgid="8796604147546125285">"ಟಿಪ್ಪಣಿಗಳು ಆ್ಯಪ್"</string>
<string name="role_notes_description" msgid="8496852798616883551">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಟಿಪ್ಪಣಿಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು ನಿಮಗೆ ಅನುಮತಿಸುವ ಆ್ಯಪ್‌ಗಳು"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ಟಿಪ್ಪಣಿಗಳು"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"ಪ್ರಸ್ತುತ ಡೀಫಾಲ್ಟ್"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"ಮತ್ತೆ ಕೇಳಬೇಡ"</string>
- <string name="request_role_set_as_default" msgid="4253949643984172880">"ಡೀಫಾಲ್ಟ್ ಆಗಿ ಹೊಂದಿಸಿ"</string>
+ <string name="request_role_set_as_default" msgid="4253949643984172880">"ಡೀಫಾಲ್ಟ್ ಆಗಿ ಸೆಟ್ ಮಾಡಿ"</string>
<string name="phone_call_uses_microphone" msgid="233569591461187177">"&lt;b&gt;ಫೋನ್ ಕರೆಯಲ್ಲಿ&lt;/b&gt; ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಬಳಸಲಾಗುತ್ತದೆ"</string>
<string name="phone_call_uses_microphone_and_camera" msgid="6291898755681748189">"&lt;b&gt;ವೀಡಿಯೋ ಕರೆಯಲ್ಲಿ&lt;/b&gt; ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಬಳಸಲಾಗುತ್ತದೆ"</string>
<string name="phone_call_uses_camera" msgid="2048417022147857418">"&lt;b&gt;ವೀಡಿಯೋ ಕರೆಯಲ್ಲಿ&lt;/b&gt; ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲಾಗುತ್ತದೆ"</string>
@@ -431,8 +443,8 @@
<string name="default_app_no_apps" msgid="115720991680586885">"ಯಾವುದೇ ಆ್ಯಪ್‌ಗಳು ಇಲ್ಲ"</string>
<string name="car_default_app_selected" msgid="5416420830430644174">"ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ"</string>
<string name="car_default_app_selected_with_info" msgid="1932204186080593500">"<xliff:g id="ADDITIONAL_INFO">%1$s</xliff:g> - ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ"</string>
- <string name="special_app_access_search_keyword" msgid="8032347212290774210">"ವಿಶೇಷ ಆ್ಯಪ್ ಪ್ರವೇಶ"</string>
- <string name="special_app_access" msgid="5019319067120213797">"ಆ್ಯಪ್‌ಗೆ ವಿಶೇಷ ಪ್ರವೇಶ"</string>
+ <string name="special_app_access_search_keyword" msgid="8032347212290774210">"ವಿಶೇಷ ಆ್ಯಪ್ ಆ್ಯಕ್ಸೆಸ್"</string>
+ <string name="special_app_access" msgid="5019319067120213797">"ಆ್ಯಪ್‌ಗೆ ವಿಶೇಷ ಆ್ಯಕ್ಸೆಸ್"</string>
<string name="no_special_app_access" msgid="6950277571805106247">"ಆ್ಯಪ್‌ಗೆ ವಿಶೇಷ ಪ್ರವೇಶವಿಲ್ಲ"</string>
<string name="special_app_access_no_apps" msgid="4102911722787886970">"ಯಾವುದೇ ಆ್ಯಪ್‌ಗಳು ಇಲ್ಲ"</string>
<string name="home_missing_work_profile_support" msgid="1756855847669387977">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"ಅಸಿಸ್ಟೆಂಟ್ ಮೈಕ್ರೋಫೋನ್ ಸಕ್ರಿಯವಾಗಿದೆ ಅಥವಾ ಇಲ್ಲವೇ ಎಂದು ತೋರಿಸಿ"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"ಧ್ವನಿ ಅಸಿಸ್ಟೆಂಟ್ ಸಕ್ರಿಯಗೊಳಿಸಲು ಮೈಕ್ರೊಫೋನ್ ಬಳಸಿದಾಗ ಸ್ಥಿತಿ ಬಾರ್‌ನಲ್ಲಿ ಐಕಾನ್ ಅನ್ನು ತೋರಿಸಿ"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿರುವ ಫೋಟೋಗಳು ಮತ್ತು ಮೀಡಿಯಾ ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_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="2270563860206654757">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_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="6641436550953715107">"ನಿಮ್ಮ &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="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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ನ ಸ್ಥಳವನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಬಳಸದಿರುವಾಗಲೂ ಸಹ, ಯಾವಾಗಲೂ ನಿಮ್ಮ ಸ್ಥಳಕ್ಕೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಲು ಆ್ಯಪ್ ಬಯಸಬಹುದು. "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅನುಮತಿಸಿ."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಆ್ಯಪ್‌ಗಾಗಿ ಸ್ಥಳ ಪ್ರವೇಶವನ್ನು ಬದಲಾಯಿಸಬೇಕೆ?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಬಳಸದಿರುವಾಗಲೂ ಸಹ, ಯಾವಾಗಲೂ ನಿಮ್ಮ ಸ್ಥಳಕ್ಕೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಲು ಆ್ಯಪ್ ಬಯಸುತ್ತದೆ. "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅನುಮತಿಸಿ."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"ಸಮೀಪದ ಸಾಧನಗಳನ್ನು ಹುಡುಕಲು, ಅವುಗಳಿಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ಮತ್ತು ಅವುಗಳ ಸಂಬಂಧಿತ ಸ್ಥಾನವನ್ನು ನಿರ್ಧರಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"ಸಮೀಪದ ಸಾಧನಗಳನ್ನು ಹುಡುಕಲು, ಅವುಗಳಿಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ಮತ್ತು ಅವುಗಳ ಸಂಬಂಧಿತ ಸ್ಥಾನವನ್ನು ನಿರ್ಧರಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ? "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅನುಮತಿಸಿ."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ನ ಸ್ಥಳ ಪ್ರವೇಶವನ್ನು ಅಂದಾಜಿನಿಂದ ನಿಖರತೆಗೆ ಬದಲಾಯಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ನಲ್ಲಿ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ನ ಸ್ಥಳ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು \'ಅಂದಾಜು\' ಎಂಬುದರಿಂದ \'ನಿಖರ\' ಎಂಬುದಕ್ಕೆ ಬದಲಾಯಿಸಬೇಕೆ?"</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="9001956706241104626">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_calendar" msgid="1493150855673603806">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$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; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ನಲ್ಲಿ SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಮತ್ತು ಅವುಗಳನ್ನು ನೋಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$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="872629037299467086">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_storage_q_to_s" msgid="8213701872983685505">"ಈ ಸಾಧನದಲ್ಲಿರುವ &lt;b&gt;ಫೋಟೋಗಳು, ವೀಡಿಯೊಗಳು, ಸಂಗೀತ, ಆಡಿಯೊವನ್ನು&lt;/b&gt; ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"ಈ ಸಾಧನದಲ್ಲಿರುವ &lt;b&gt;ಫೋಟೋಗಳು, ವೀಡಿಯೊಗಳು, ಸಂಗೀತ, ಆಡಿಯೋ, ಇತರ ಫೈಲ್‌ಗಳನ್ನು&lt;/b&gt; ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"ಈ ಸಾಧನದಲ್ಲಿರುವ ಸಂಗೀತ ಮತ್ತು ಆಡಿಯೊವನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_read_media_visual" msgid="5548780620779729975">"ಈ ಸಾಧನದಲ್ಲಿರುವ ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_more_photos" msgid="128933814654231321">"ಈ ಸಾಧನದಲ್ಲಿರುವ ಇನ್ನಷ್ಟು ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_microphone" msgid="2825208549114811299">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_microphone" msgid="8510456971528228861">"ನೀವು ಆ್ಯಪ್ ಬಳಸುತ್ತಿರುವಾಗ ಮಾತ್ರ ಆ್ಯಪ್‌ಗೆ ಆಡಿಯೋ ರೆಕಾರ್ಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಬಳಸದಿರುವಾಗಲೂ ಸಹ, ಈ ಆ್ಯಪ್ ಯಾವಾಗಲೂ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ಬಯಸಬಹುದು. "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅನುಮತಿಸಿ."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಆ್ಯಪ್‌ಗಾಗಿ ಮೈಕ್ರೋಫೋನ್ ಪ್ರವೇಶವನ್ನು ಬದಲಾಯಿಸಬೇಕೆ?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಬಳಸದಿರುವಾಗಲೂ ಸಹ, ಈ ಆ್ಯಪ್ ಯಾವಾಗಲೂ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ಬಯಸುತ್ತದೆ. "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅನುಮತಿಸಿ."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"ನಿಮ್ಮ ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ಕ್ಕೆ ಅನುಮತಿಸುವುದೇ?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_camera" msgid="5123097035410002594">"ಚಿತ್ರಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಮತ್ತು ವೀಡಿಯೊ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_camera" msgid="9085323239764667883">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಬಳಸುತ್ತಿರುವಾಗ ಮಾತ್ರ ಆ್ಯಪ್‌ಗೆ ಚಿತ್ರಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು ಮತ್ತು ವೀಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"ಚಿತ್ರಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಮತ್ತು ವೀಡಿಯೊ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ನೀವು ಈ ಆ್ಯಪ್ ಬಳಸದಿರುವಾಗಲೂ ಸಹ, ಈ ಆ್ಯಪ್ ಎಲ್ಲಾ ಸಮಯದಲ್ಲೂ ಚಿತ್ರಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು ಮತ್ತು ವೀಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ಬಯಸಬಹುದು. "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅನುಮತಿಸಿ."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಆ್ಯಪ್‌ಗಾಗಿ ಕ್ಯಾಮರಾ ಪ್ರವೇಶವನ್ನು ಬದಲಾಯಿಸಬೇಕೆ?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"ನೀವು ಈ ಆ್ಯಪ್ ಬಳಸದಿರುವಾಗಲೂ ಸಹ, ಈ ಆ್ಯಪ್ ಎಲ್ಲಾ ಸಮಯದಲ್ಲೂ ಚಿತ್ರಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು ಮತ್ತು ವೀಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ಬಯಸುತ್ತದೆ. "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅನುಮತಿಸಿ."</annotation></string>
- <string name="permgrouprequest_calllog" msgid="2065327180175371397">"ನಿಮ್ಮ ಫೋನ್‌ ಕರೆಯ ಲಾಗ್‌ಗಳಿಗೆ ಪ್ರವೇಶ ಪಡೆಯಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_calllog" msgid="2065327180175371397">"ನಿಮ್ಮ ಫೋನ್‌ ಕರೆಯ ಲಾಗ್‌ಗಳಿಗೆ ಆ್ಯಕ್ಸೆಸ್ ಪಡೆಯಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_phone" msgid="1829234136997316752">"ಫೋನ್ ಕರೆಗಳನ್ನು ಮಾಡಲು ಮತ್ತು ನಿರ್ವಹಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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_sensors" msgid="4397358316850652235">"ನಿಮ್ಮ ಮುಖ್ಯ ಲಕ್ಷಣಗಳ ಕುರಿತು ಸೆನ್ಸರ್ ಡೇಟಾವನ್ನು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"ನೀವು ಆ್ಯಪ್ ಬಳಸದಿರುವಾಗಲೂ ಸಹ, ನಿಮ್ಮ ಆರೋಗ್ಯ ಮಾಪನಗಳ ಕುರಿತು ಎಲ್ಲಾ ಸಮಯದಲ್ಲೂ ಸೆನ್ಸರ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಈ ಆ್ಯಪ್ ಬಯಸುತ್ತದೆ. ಈ ಬದಲಾವಣೆಯನ್ನು ಮಾಡಲು, "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"ನಿಮ್ಮ ಜೀವನಾಧಾರವಾಗಿರುವ ಲಕ್ಷಣಗಳ ಕುರಿತ ಸೆನ್ಸರ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಬಳಸದಿರುವಾಗಲೂ ಸಹ, ಎಲ್ಲಾ ಸಮಯದಲ್ಲೂ ದೇಹದ ಸೆನ್ಸರ್‌ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನುಮತಿಸಲು, "<annotation id="link">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ಆ್ಯಪ್ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ದೇಹದ ಸೆನ್ಸರ್‌ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸುತ್ತಿರಬೇಕೇ?"</string>
- <string name="permgrouprequest_notifications" msgid="6396739062335106181">"ನಿಮಗೆ ಅಧಿಸೂಚನೆಗಳನ್ನು ಕಳುಹಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="DEVICE">%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_notifications" msgid="6396739062335106181">"ನಿಮಗೆ ನೋಟಿಫಿಕೇಶನ್‌ಗಳನ್ನು ಕಳುಹಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"ನಿಮ್ಮ &lt;b&gt;<xliff:g id="DEVICE">%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="auto_granted_permissions" msgid="6009452264824455892">"ನಿಯಂತ್ರಿತ ಅನುಮತಿಗಳು"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಸ್ಥಳ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿದೆ"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"ಇತರ ಅನುಮತಿಗಳು"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"ಸಿಸ್ಟಂನಿಂದ ಬಳಸಲ್ಪಡುವ ಅನುಮತಿಗಳು"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"ಸಿಸ್ಟಂ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಂದ ಮಾತ್ರ ಬಳಸಲ್ಪಡುವ ಅನುಮತಿಗಳು."</string>
@@ -514,8 +551,8 @@
<string name="privdash_label_none" msgid="5991866260360484858">"ಯಾವುದೂ ಅಲ್ಲ"</string>
<string name="privdash_label_24h" msgid="1512532123865375319">"ಕಳೆದ\n24 ಗಂಟೆಗಳು"</string>
<string name="privdash_label_7d" msgid="5645301995348656931">"ಕಳೆದ\n7 ದಿನಗಳಲ್ಲಿ"</string>
- <string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು Android ನಿಂದ ರಕ್ಷಣೆ ಪಡೆದಿದೆ. ಈ ಸಾಧನದಲ್ಲಿ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲಾಗಿರುವುದರಿಂದ, ಈ ಆ್ಯಪ್‌ನ ಅನುಮತಿಯ ಬಳಕೆಯನ್ನು ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಅಥವಾ ನಿಮ್ಮ ಗೌಪ್ಯತಾ ಡ್ಯಾಶ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ತೋರಿಸಲಾಗುವುದಿಲ್ಲ."</string>
- <string name="exempt_info_label" msgid="6286190981253476699">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು Android ನಿಂದ ರಕ್ಷಣೆ ಪಡೆದಿದೆ. ಈ ಸಾಧನದಲ್ಲಿ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲಾಗಿರುವುದರಿಂದ, ಈ ಆ್ಯಪ್‌ನ ಅನುಮತಿಯ ಬಳಕೆಯನ್ನು ನಿಮ್ಮ ಗೌಪ್ಯತಾ ಡ್ಯಾಶ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ತೋರಿಸಲಾಗುವುದಿಲ್ಲ."</string>
+ <string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"<xliff:g id="APP_NAME">%1$s</xliff:g>, Android ನಿಂದ ರಕ್ಷಣೆ ಪಡೆದಿದೆ. ಈ ಸಾಧನದಲ್ಲಿ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲಾಗಿರುವುದರಿಂದ, ಈ ಆ್ಯಪ್‌ನ ಅನುಮತಿಯ ಬಳಕೆಯನ್ನು ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಅಥವಾ ನಿಮ್ಮ ಗೌಪ್ಯತಾ ಡ್ಯಾಶ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ತೋರಿಸಲಾಗುವುದಿಲ್ಲ."</string>
+ <string name="exempt_info_label" msgid="6286190981253476699">"<xliff:g id="APP_NAME">%1$s</xliff:g>, Android ನಿಂದ ರಕ್ಷಣೆ ಪಡೆದಿದೆ. ಈ ಸಾಧನದಲ್ಲಿ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲಾಗಿರುವುದರಿಂದ, ಈ ಆ್ಯಪ್‌ನ ಅನುಮತಿಯ ಬಳಕೆಯನ್ನು ನಿಮ್ಮ ಗೌಪ್ಯತಾ ಡ್ಯಾಶ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ತೋರಿಸಲಾಗುವುದಿಲ್ಲ."</string>
<string name="blocked_camera_title" msgid="1128510551791284384">"ಸಾಧನದ ಕ್ಯಾಮರಾವನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"ಸಾಧನದ ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"ಸಾಧನದ ಸ್ಥಳವು ಆಫ್ ಆಗಿದೆ"</string>
@@ -579,18 +616,19 @@
<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="camera_toggle_title" msgid="1251201397431837666">"ಕ್ಯಾಮರಾ ಪ್ರವೇಶ"</string>
- <string name="mic_toggle_title" msgid="2649991093496110162">"ಮೈಕ್ರೊಫೋನ್ ಪ್ರವೇಶ"</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>
<string name="mic_toggle_description" msgid="9163104307990677157">"ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಸೇವೆಗಳಿಗಾಗಿ. ಈ ಸೆಟ್ಟಿಂಗ್ ಆಫ್ ಆಗಿದ್ದರೆ, ನೀವು ತುರ್ತು ಸಂಖ್ಯೆಗೆ ಕರೆ ಮಾಡಿದಾಗ ಮೈಕ್ರೊಫೋನ್ ಡೇಟಾವನ್ನು ಆಗಲೂ ಹಂಚಿಕೊಳ್ಳಬಹುದು."</string>
- <string name="location_settings_subtitle" msgid="2328360561197430695">"ಸ್ಥಳಕ್ಕೆ ಪ್ರವೇಶ ಹೊಂದಿರುವ ಆ್ಯಪ್‌ಗಳು ಹಾಗೂ ಸೇವೆಗಳನ್ನು ನೋಡಿ"</string>
- <string name="show_clip_access_notification_title" msgid="5168467637351109096">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ಪ್ರವೇಶವನ್ನು ತೋರಿಸಿ"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"ನೀವು ನಕಲಿಸಿರುವ ಪಠ್ಯ, ಚಿತ್ರಗಳು ಅಥವಾ ಇತರ ವಿಷಯವನ್ನು ಆ್ಯಪ್‌ಗಳು ಪ್ರವೇಶಿಸಿದಾಗ ಸಂದೇಶವೊಂದನ್ನು ತೋರಿಸಿ"</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"ಸ್ಥಳಕ್ಕೆ ಆ್ಯಕ್ಸೆಸ್ ಹೊಂದಿರುವ ಆ್ಯಪ್‌ಗಳು ಹಾಗೂ ಸೇವೆಗಳನ್ನು ನೋಡಿ"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ತೋರಿಸಿ"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"ನೀವು ನಕಲಿಸಿರುವ ಪಠ್ಯ, ಚಿತ್ರಗಳು ಅಥವಾ ಇತರ ವಿಷಯವನ್ನು ಆ್ಯಪ್‌ಗಳು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಿದಾಗ ಸಂದೇಶವೊಂದನ್ನು ತೋರಿಸಿ"</string>
<string name="show_password_title" msgid="2877269286984684659">"ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="show_password_summary" msgid="1110166488865981610">"ನೀವು ಟೈಪ್ ಮಾಡಿದಂತೆ ಅಕ್ಷರಗಳನ್ನು ಸಂಕ್ಷಿಪ್ತವಾಗಿ ಪ್ರದರ್ಶಿಸಿ"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"ಈ ಆ್ಯಪ್ ಥರ್ಡ್ ಪಾರ್ಟಿಗಳೊಂದಿಗೆ ಸ್ಥಳ ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು ಎಂದು ಉಲ್ಲೇಖಿಸಿದೆ"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ಡೇಟಾ ಹಂಚಿಕೆ ಮತ್ತು ಸ್ಥಳ"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ಡೇಟಾ ಹಂಚಿಕೆಯ ಮಾಹಿತಿಯು ಎಲ್ಲಿಂದ ಬರುತ್ತದೆ"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ಈ ಆ್ಯಪ್ ಡೇಟಾವನ್ನು ಹೇಗೆ ಹಂಚಿಕೊಳ್ಳುತ್ತದೆ ಎಂಬುದರ ಕುರಿತು ಡೆವಲಪರ್ ಈ ಸಾಧನದ ತಯಾರಕರಿಗೆ ಮಾಹಿತಿಯನ್ನು ಒದಗಿಸಿದ್ದಾರೆ. ಡೆವಲಪರ್ ಕಾಲಕ್ರಮೇಣ ಈ ಮಾಹಿತಿಯನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡಬಹುದು."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ಈ ಆ್ಯಪ್, ಡೇಟಾವನ್ನು ಹೇಗೆ ಹಂಚಿಕೊಳ್ಳುತ್ತದೆ ಎಂಬುದರ ಕುರಿತು ಡೆವಲಪರ್ "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" ಗೆ ಮಾಹಿತಿ ಒದಗಿಸಿದ್ದಾರೆ. ಡೆವಲಪರ್ ಕಾಲಕ್ರಮೇಣ ಈ ಮಾಹಿತಿಯನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡಬಹುದು."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ಈ ಆ್ಯಪ್ ಇವುಗಳಿಗಾಗಿ ಸ್ಥಳ ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ಡೇಟಾ ಹಂಚಿಕೆ ಬದಲಾಗುತ್ತದೆ"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ಡೇಟಾ ಸುರಕ್ಷತೆ"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"ಸ್ಥಳ ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"ಈ ಆ್ಯಪ್, ಥರ್ಡ್-ಪಾರ್ಟಿಗಳೊಂದಿಗೆ ನಿಮ್ಮ ಸ್ಥಳ ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು ಎಂದು ತಿಳಿಸಿದೆ"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ಈ ಲಿಂಕ್ ತೆರೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"ಸ್ಥಳಕ್ಕಾಗಿ ಡೇಟಾ ಹಂಚಿಕೊಳ್ಳುವಿಕೆ ಕುರಿತ ಅಪ್‌ಡೇಟ್‌ಗಳು"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ನಿಮ್ಮ ಸ್ಥಳ ಡೇಟಾವನ್ನು ತಾವು ಹಂಚಿಕೊಳ್ಳಬಹುದಾದ ವಿಧಾನವನ್ನು ಬದಲಾಯಿಸಿದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"ನಿಮ್ಮ ಸ್ಥಳ ಡೇಟಾವನ್ನು ಈ ಆ್ಯಪ್‌ಗಳು ಹಂಚಿಕೊಳ್ಳಬಹುದಾದ ವಿಧಾನವನ್ನು ಅವು ಬದಲಾಯಿಸಿವೆ. ಇವು ಇದನ್ನು ಈ ಮೊದಲು ಹಂಚಿಕೊಂಡಿಲ್ಲದಿರಬಹುದು ಅಥವಾ ಈಗ ಅದನ್ನು ಜಾಹೀರಾತು ಅಥವಾ ಮಾರ್ಕೆಟಿಂಗ್ ಉದ್ದೇಶಗಳಿಗಾಗಿ ಹಂಚಿಕೊಳ್ಳುತ್ತಿರಬಹುದು."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ಡೇಟಾ ಹಂಚಿಕೆ ಅಪ್‌ಡೇಟ್‌ಗಳು"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"ಕೆಲವು ಆ್ಯಪ್‌ಗಳು, ನಿಮ್ಮ ಸ್ಥಳ ಡೇಟಾವನ್ನು ಅವು ಹಂಚಿಕೊಳ್ಳಬಹುದಾದ ವಿಧಾನವನ್ನು ಬದಲಾಯಿಸಿವೆ"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g> ಸಮಯಕ್ಕೆ ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"ನಿನ್ನೆ <xliff:g id="TIME_DATE">%1$s</xliff:g> ಸಮಯಕ್ಕೆ ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g> ಸಮಯಕ್ಕೆ ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲಾಗಿದೆ"</string>
</resources>
diff --git a/PermissionController/res/values-ko-v33/strings.xml b/PermissionController/res/values-ko-v33/strings.xml
index 5e7203b67..87bd343e9 100644
--- a/PermissionController/res/values-ko-v33/strings.xml
+++ b/PermissionController/res/values-ko-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"알림 더보기"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"닫은 알림"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{펼쳐서 알림 1개 더보기}other{펼쳐서 알림 #개 더보기}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"주의. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"작업 완료"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"기기 보안을 강화할 수 있는 설정 확인"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"보안 및 개인 정보 보호 빠른 설정"</string>
diff --git a/PermissionController/res/values-ko-v34/strings.xml b/PermissionController/res/values-ko-v34/strings.xml
index 93addd649..7b3091170 100644
--- a/PermissionController/res/values-ko-v34/strings.xml
+++ b/PermissionController/res/values-ko-v34/strings.xml
@@ -23,5 +23,5 @@
<string name="health_connect_summary" msgid="815473513776882296">"건강 데이터에 대한 앱 액세스 제어"</string>
<string name="location_settings" msgid="8863940440881290182">"위치 정보 액세스"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"앱 및 서비스에 적용됩니다. 설정이 꺼져 있어도 긴급 전화번호로 전화를 걸 때 마이크 데이터가 계속 공유될 수 있습니다."</string>
- <string name="location_settings_subtitle" msgid="6846532794702613851">"앱 및 서비스에 적용됩니다."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"앱 및 서비스에 적용"</string>
</resources>
diff --git a/PermissionController/res/values-ko/strings.xml b/PermissionController/res/values-ko/strings.xml
index 1e3e0db0c..0aeea908b 100644
--- a/PermissionController/res/values-ko/strings.xml
+++ b/PermissionController/res/values-ko/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"추가 정보"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"모두 허용"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"항상 모두 허용"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"제한된 액세스 허용"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"사진 및 동영상 선택"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"더보기 선택"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"추가 선택 안함"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"앱"</string>
<string name="app_permissions" msgid="3369917736607944781">"앱 권한"</string>
<string name="unused_apps" msgid="2058057455175955094">"사용하지 않는 앱"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"이 앱에서 액세스할 수 있는 사진 변경"</string>
<string name="no_unused_apps" msgid="12809387670415295">"사용하지 않는 앱 없음"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"사용하지 않는 앱 0개"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"최근 권한 결정"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"모든 권한"</string>
<string name="other_permissions" msgid="2901186127193849594">"다른 앱 기능"</string>
<string name="permission_request_title" msgid="8790310151025020126">"권한 요청"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear에서는 설치/제거 작업이 지원되지 않습니다"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 액세스하도록 허용할 항목 선택"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;이(가) 업데이트되었습니다. 이 앱에서 액세스하도록 허용할 항목을 선택하세요."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"취소"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"앱이 사용되지 않는 경우 권한 삭제"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"권한을 삭제하고 여유 공간 확보"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"사용하지 않을 때 앱 활동 일시중지"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"사용하지 않는 경우 앱 관리"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"권한 제거, 임시 파일 삭제, 알림 중지"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"권한 제거, 임시 파일 삭제, 알림 중지, 앱 보관처리"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"데이터 보호를 위해 몇 개월 동안 앱을 사용하지 않으면 앱의 권한이 삭제됩니다."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"데이터 보호를 위해 몇 개월 동안 앱을 사용하지 않으면 다음 권한이 삭제됩니다. <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"데이터 보호를 위해 몇 개월 동안 사용하지 않은 앱에서 권한이 삭제되었습니다."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"마지막 실행 날짜: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"모든 파일 관리를 허용하면 앱이 이 기기의 공통 저장용량 또는 연결된 저장장치에 있는 모든 파일에 액세스하거나 이러한 파일을 수정, 삭제할 수 있습니다. 앱이 사용자에게 요청하지 않고도 파일에 액세스할 수 있습니다."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"앱이 이 기기 또는 연결된 저장장치에 있는 파일에 액세스하거나 이러한 파일을 수정, 삭제하도록 허용하시겠습니까? 앱이 사용자에게 요청하지 않고도 파일에 액세스할 수 있습니다."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"이 권한이 있는 앱은 <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"이 권한이 있는 앱은 다음 작업을 할 수 있습니다: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"이 권한이 있는 앱은 걷기, 자전거 타기, 운전, 걸음 수 등 내 신체 활동 정보에 액세스할 수 있습니다."</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"이 권한이 있는 앱은 내 캘린더에 액세스할 수 있습니다."</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"이 권한이 있는 앱은 전화 통화 기록을 읽고 쓸 수 있습니다."</string>
@@ -349,7 +351,7 @@
<string name="accessibility_service_dialog_bottom_text_multiple" msgid="7009848932395519852">"이 앱이 내 화면, 작업, 입력 내용을 보고 작업을 실행하며 디스플레이를 제어할 수 있습니다."</string>
<string name="role_assistant_label" msgid="4727586018198208128">"기본 디지털 어시스턴트 앱"</string>
<string name="role_assistant_short_label" msgid="3369003713187703399">"디지털 어시스턴트 앱"</string>
- <string name="role_assistant_description" msgid="6622458130459922952">"지원 앱은 화면에 표시된 정보에 맞게 도움을 줄 수 있습니다. 일부 앱은 통합된 지원을 제공하기 위해 런처와 음성 입력 서비스를 모두 지원합니다."</string>
+ <string name="role_assistant_description" msgid="6622458130459922952">"지원 앱은 화면에 표시된 정보를 기반으로 도움을 줄 수 있습니다. 일부 앱은 통합된 지원을 제공하기 위해 런처와 음성 입력 서비스를 모두 지원합니다."</string>
<string name="role_browser_label" msgid="2877796144554070207">"기본 브라우저 앱"</string>
<string name="role_browser_short_label" msgid="6745009127123292296">"브라우저 앱"</string>
<string name="role_browser_description" msgid="3465253637499842671">"인터넷에 액세스하고 탭하는 링크를 표시하는 앱"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"메모 앱"</string>
<string name="role_notes_description" msgid="8496852798616883551">"이 기기에서 메모할 수 있게 해주는 앱"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"메모"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"현재 기본 앱"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"다시 묻지 않음"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"기본 앱으로 설정"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"지원 앱 트리거 감지 표시"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"음성 어시스턴트 활성화를 위해 마이크가 사용되면 상태 표시줄에 아이콘 표시"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 기기의 사진 및 미디어에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%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_location" msgid="6990232580121067883">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 내 기기의 위치 정보에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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>의 위치에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"앱을 사용하고 있지 않을 때도 앱에서 내 위치에 항상 액세스하려고 할 수 있습니다. "<annotation id="link">"설정에서 액세스를 허용"</annotation>"하세요."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;의 위치 액세스 권한을 변경하시겠습니까?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"앱을 사용하고 있지 않을 때도 앱에서 내 위치에 항상 액세스하려고 합니다. "<annotation id="link">"설정에서 액세스를 허용"</annotation>"하세요."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 근처에 있는 기기를 찾아 연결하고 기기 간 상대적 위치를 파악하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 근처 기기의 상대 위치를 찾고, 연결하고, 확인하도록 허용하시겠습니까?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 근처 기기를 찾아 연결하고 기기 간 상대적 위치를 파악하도록 허용하시겠습니까? "<annotation id="link">"설정에서 허용하세요."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>의 위치 정보 액세스 권한을 대략적인 위치에서 정확한 위치로 변경하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> 앱의 위치 액세스를 대략적인 위치에서 정확한 위치로 변경하시겠습니까?"</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 SMS 메시지를 전송하고 확인하도록 허용하시겠습니까?"</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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 사진, 미디어, 파일에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 기기의 &lt;b&gt;사진, 동영상, 음악, 오디오&lt;/b&gt;에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 기기의 &lt;b&gt;사진, 동영상, 음악, 오디오, 기타 파일&lt;/b&gt;에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 기기의 음악과 오디오에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 음악과 오디오에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 기기의 사진과 동영상에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 사진 및 동영상에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 기기에 있는 더 많은 사진과 동영상에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 더 많은 사진 및 동영상에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 오디오를 녹음하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 오디오를 녹음하도록 허용하시겠습니까?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"앱을 사용하고 있는 동안에만 앱에서 오디오를 녹음할 수 있습니다."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 오디오를 녹음하도록 허용하시겠습니까?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 오디오를 녹음하도록 허용하시겠습니까?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"앱을 사용하고 있지 않을 때도 앱에서 항상 오디오를 녹음하고자 할 수 있습니다. "<annotation id="link">"설정에서 액세스를 허용하세요"</annotation>"."</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;의 마이크 액세스 권한을 변경하시겠습니까?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"앱을 사용하고 있지 않을 때도 앱에서 항상 오디오를 녹음하려고 합니다. "<annotation id="link">"설정에서 액세스를 허용하세요"</annotation>"."</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 내 신체 활동 정보에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 신체 활동에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 사진을 촬영하고 동영상을 녹화하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 사진을 찍고 동영상을 녹화하도록 허용하시겠습니까?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"앱을 사용하고 있는 동안에만 앱에서 사진을 촬영하고 동영상을 녹화할 수 있습니다."</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 사진을 촬영하고 동영상을 녹화하도록 허용하시겠습니까?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 사진을 찍고 동영상을 녹화하도록 허용하시겠습니까?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"앱을 사용하고 있지 않을 때도 앱에서 항상 사진을 촬영하고 동영상을 녹화하고자 할 수 있습니다. "<annotation id="link">"설정에서 액세스를 허용하세요"</annotation>"."</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;의 카메라 액세스 권한을 변경하시겠습니까?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"앱을 사용하고 있지 않을 때도 앱에서 항상 사진을 촬영하고 동영상을 녹화하려고 합니다. "<annotation id="link">"설정에서 액세스를 허용하세요"</annotation>"."</string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 통화 기록에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 통화 기록에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 전화를 걸고 관리하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 전화를 걸고 관리하도록 허용하시겠습니까?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 생체 신호에 관한 센서 데이터에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 생체 신호에 관한 센서 데이터에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"앱이 사용되고 있지 않을 때도 항상 생체 신호 센서 데이터에 액세스하고자 합니다. 권한을 변경하려면 "<annotation id="link">"설정으로 이동"</annotation>"하세요."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 생체 신호에 관한 센서 데이터에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 생체 신호에 관한 센서 데이터에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"앱을 사용하지 않을 때도 앱이 항상 생체 신호 센서 데이터에 액세스하도록 허용하려면 "<annotation id="link">"설정으로 이동"</annotation>"하세요"</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱을 사용하는 중에만 생체 신호 센서 데이터에 액세스하도록 허용하는 설정을 유지하시겠습니까?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 사용 중일 때 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;의 생체 신호 센서에 액세스하도록 계속 허용하시겠습니까?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 알림을 보내도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 앱이 &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;에서 알림을 보내도록 허용하시겠습니까?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"관리 대상 권한"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱이 위치 액세스 권한을 보유함"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"조직에서 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱이 내 위치에 액세스하도록 허용했습니다."</string>
<string name="other_permissions_label" msgid="8986184335503271992">"기타 권한"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"시스템에서 사용하는 권한"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"시스템 애플리케이션에서만 사용하는 권한입니다."</string>
@@ -572,10 +609,10 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"앱이 최신 버전의 Android를 지원하지 않습니다. 앱이 음악 및 오디오 파일에 액세스할 수 없는 경우 사진 및 동영상에 대한 액세스도 허용되지 않습니다."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"앱이 최신 버전의 Android를 지원하지 않습니다. 앱이 사진 및 동영상에 액세스할 수 있는 경우 음악 및 오디오 파일에 대한 액세스도 허용됩니다."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"앱이 최신 버전의 Android를 지원하지 않습니다. 앱이 음악 및 오디오 파일에 액세스할 수 없는 경우 사진 및 동영상에 대한 액세스도 허용되지 않습니다."</string>
- <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"백그라운드 위치 액세스 권한이 있는 앱 검토하기"</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"백그라운드 위치 정보 액세스 권한이 있는 앱 검토하기"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> 앱은 닫혀 있는 동안에도 내 위치 정보에 항상 액세스할 수 있습니다."</string>
- <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"백그라운드 위치 액세스 권한이 있는 앱 검토하기"</string>
- <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"이 앱은 앱이 닫혀 있는 동안에도 내 위치 정보에 항상 액세스할 수 있습니다.\n\n일부 안전 및 긴급 대응 앱은 의도한 대로 작동하기 위해 백그라운드에서 내 위치 정보에 액세스하는 권한이 필요합니다."</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"백그라운드 위치 정보 액세스 권한이 있는 앱 검토하기"</string>
+ <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>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"앱에서 위치 데이터를 서드 파티와 공유할 수 있다고 명시했습니다."</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"데이터 공유 및 위치"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"데이터 공유 정보 출처"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"개발자가 이 기기의 제조업체에 이 앱의 데이터 공유 방법에 관한 정보를 제공했습니다. 시간이 지난 후 개발자가 이 정보를 업데이트할 수도 있습니다."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"개발자가 "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"에게 이 앱의 데이터 공유 방법에 관한 정보를 제공했습니다. 시간이 지난 후 개발자가 이 정보를 업데이트할 수도 있습니다."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"이 앱은 다음 목적으로 위치 데이터를 공유할 수 있습니다."</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"다양한 데이터 공유 방식"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"데이터 보안"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"위치 데이터가 공유될 수 있습니다."</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"앱에서 위치 데이터를 서드 파티와 공유할 수 있다고 명시했습니다."</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"링크를 열 수 없음"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"위치 데이터 공유 방법 업데이트"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"위치 데이터 공유 방법을 변경한 앱 검토"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"다음 앱에서 위치 데이터 공유 방법을 변경했습니다. 이전에 위치 데이터를 공유하지 않았던 앱이거나, 이제 광고 또는 마케팅 목적으로 데이터를 공유하는 앱일 수 있습니다."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"데이터 공유 업데이트"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"일부 앱에서 위치 데이터 공유 방법이 변경되었습니다."</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"설정"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g>에 액세스함"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"어제 <xliff:g id="TIME_DATE">%1$s</xliff:g>에 액세스함"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>에 액세스함"</string>
</resources>
diff --git a/PermissionController/res/values-ky-television/strings.xml b/PermissionController/res/values-ky-television/strings.xml
index 138b37a9c..2e98e1503 100644
--- a/PermissionController/res/values-ky-television/strings.xml
+++ b/PermissionController/res/values-ky-television/strings.xml
@@ -19,7 +19,7 @@
<string name="grant_dialog_button_deny_dont_ask_again" msgid="747769682501286250">"Баш тартам жана экинчи суралбасын"</string>
<string name="grant_dialog_how_to_change" msgid="997462845048160559">"Муну кийин Параметрлер &gt; Колдонмолордон өзгөртө аласыз"</string>
<string name="current_permission_template" msgid="6240787325714651204">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="preference_show_system_apps" msgid="4262140518693221093">"Тутум колдонмолорун көрсөтүү"</string>
+ <string name="preference_show_system_apps" msgid="4262140518693221093">"Система колдонмолорун көрсөтүү"</string>
<string name="app_permissions_decor_title" msgid="7438716722786036814">"Колдонмонун уруксаттары"</string>
<string name="manage_permissions_decor_title" msgid="4138423885439613577">"Колдонмонун уруксаттары"</string>
<string name="permission_apps_decor_title" msgid="2811550489429789828">"<xliff:g id="PERMISSION">%1$s</xliff:g> уруксаттары"</string>
diff --git a/PermissionController/res/values-ky-v33/strings.xml b/PermissionController/res/values-ky-v33/strings.xml
index 8f88e1c93..3f2e12a3d 100644
--- a/PermissionController/res/values-ky-v33/strings.xml
+++ b/PermissionController/res/values-ky-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Дагы эскертүүлөр"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Жабылган эскертүүлөр"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Дагы бир эскертүүнү көрүү үчүн жайып көрсөтүү}other{Дагы # эскертүүнү көрүү үчүн жайып көрсөтүү}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Эскертүү. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Аракет аткарылды"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Түзмөгүңүздүн коопсуздугун бекемдей турган параметрлерди текшериңиз"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Коопсуздук жана купуялык ыкчам параметрлери"</string>
diff --git a/PermissionController/res/values-ky-v34/strings.xml b/PermissionController/res/values-ky-v34/strings.xml
index c21edf61f..15fc8424e 100644
--- a/PermissionController/res/values-ky-v34/strings.xml
+++ b/PermissionController/res/values-ky-v34/strings.xml
@@ -20,8 +20,8 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Коопсуздук жана купуялык"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Башкаруу элементтери"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Колдонмонун ден соолук тууралуу маалыматка кирүү мүмкүнчүлүгүн тескөө"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Колдонмо үчүн ден соолукка байланыштуу нерселердин жеткиликтүүлүгүн тескейсиз"</string>
<string name="location_settings" msgid="8863940440881290182">"Жайгашкан жерди көрсөтүү"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Колдонмолор жана кызматтар үчүн. Эгер бул жөндөө өчүрүлсө, кырсыктаганда жардамга келчү кызматтын номерине чалганыңызда микрофондогу нерселер өткөрүлүшү мүмкүн"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Колдонмолор жана кызматтар үчүн. Бул параметр өчүп турса да, кырсыктаганда жардамга келчү кызматтын номерине чалганыңызда микрофондогу нерселер өткөрүлүшү мүмкүн."</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Колдонмолор жана кызматтар үчүн"</string>
</resources>
diff --git a/PermissionController/res/values-ky-watch/strings.xml b/PermissionController/res/values-ky-watch/strings.xml
index a40c90370..d6ca47fc1 100644
--- a/PermissionController/res/values-ky-watch/strings.xml
+++ b/PermissionController/res/values-ky-watch/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="grant_dialog_button_deny_dont_ask_again" msgid="5709879604352260492">"Баш тарам, экинчи суралбасын"</string>
<string name="current_permission_template" msgid="6634462553790549887">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="preference_show_system_apps" msgid="1055740303992024300">"Тутум колдонмолорун көрсөтүү"</string>
+ <string name="preference_show_system_apps" msgid="1055740303992024300">"Система колдонмолорун көрсөтүү"</string>
<string name="permission_summary_enforced_by_policy" msgid="2352478756952948019">"Өзгөртүүгө болбойт"</string>
<string name="generic_yes" msgid="2489207724988649846">"Ооба"</string>
<string name="generic_cancel" msgid="2631708607129269698">"Жок"</string>
diff --git a/PermissionController/res/values-ky/strings.xml b/PermissionController/res/values-ky/strings.xml
index 9372921a1..ee6806b95 100644
--- a/PermissionController/res/values-ky/strings.xml
+++ b/PermissionController/res/values-ky/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Дагы маалымат"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Баарына уруксат берүү"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Ар дайым баарына уруксат берүү"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Чектелген мүмкүнчүлүк берүү"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Сүрөттөрдү жана видеолорду тандаңыз"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Дагы тандоо"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Башка тандалбасын"</string>
@@ -47,7 +48,7 @@
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Тыюу салам жана экинчи суралбасын"</string>
<string name="permission_revoked_count" msgid="4785082705441547086">"<xliff:g id="COUNT">%1$d</xliff:g> өчүрүлгөн"</string>
<string name="permission_revoked_all" msgid="3397649017727222283">"баары өчүрүлгөн"</string>
- <string name="permission_revoked_none" msgid="9213345075484381180">"эч бири өчүрүлгөн жок"</string>
+ <string name="permission_revoked_none" msgid="9213345075484381180">"эч бири өчкөн жок"</string>
<string name="grant_dialog_button_allow" msgid="5314677880021102550">"Уруксат берүү"</string>
<string name="grant_dialog_button_allow_always" msgid="4485552579273565981">"Бардык учурда уруксат берилет"</string>
<string name="grant_dialog_button_allow_foreground" msgid="501896824973636533">"Колдонмо ачылып турганда"</string>
@@ -60,7 +61,8 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Колдонмолор"</string>
<string name="app_permissions" msgid="3369917736607944781">"Колдонмонун уруксаттары"</string>
<string name="unused_apps" msgid="2058057455175955094">"Колдонулбаган колдонмолор"</string>
- <string name="no_unused_apps" msgid="12809387670415295">"Бардык колдонмолор иштетилүүдө"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Бул колдонмого жеткиликтүү сүрөттөрдүн тизмесин өзгөртүү"</string>
+ <string name="no_unused_apps" msgid="12809387670415295">"Бардык колдонмолор колдонулууда"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Колдонулбаган колдонмолор: 0"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Уруксаттарга байланыштуу аракеттер"</string>
<string name="review_permission_decisions_view_all" msgid="90391040431566130">"Уруксаттар боюнча көрүлгөн соңку аракеттер"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Бардык уруксаттар"</string>
<string name="other_permissions" msgid="2901186127193849594">"Колдонмонун башка мүмкүнчүлүктөрү"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Уруксат суроо"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Орнотуу/чыгарып салуу аракеттери Android Wear\'де колдоого алынбайт."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосу үчүн уруксаттарды тандаңыз"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; жаңырды. Ал үчүн уруксаттарды тандаңыз."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Жок"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Эгер колдонмо пайдаланылбаса, уруксаттар өчүрүлсүн"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Уруксаттарды өчүрүп, орун бошотуу"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Колдонулбаган колдонмолордун ишин тындыруу"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Колдонмо колдонулбаса, аны тескеңиз"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Уруксаттар өчүрүлүп, убактылуу файлдар тазаланып, билдирмелер келбей калат"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Уруксаттарды алып салып, убактылуу файлдарды жок кылып, билдирмелерди токтотуңуз жана колдонмону архивдеңиз"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Эгер колдонмо бир нече ай пайдаланылбаса, жеке маалыматтарыңызды коргоо үчүн бул колдонмого берилген уруксаттар өчүрүлөт."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Эгер колдонмо бир нече ай пайдаланылбаса, жеке дайын-даректериңизди коргоо максатында төмөнкү уруксаттар өчүрүлөт: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Жеке дайын-даректериңизди коргоо максатында, бир нече айдан бери ачылбаган колдонмолордогу уруксаттар өчүрүлдү."</string>
@@ -273,7 +275,7 @@
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Унаа айдап баратканда <xliff:g id="APP">%1$s</xliff:g> колдонмосуна төмөнкүгө уруксат бердиңиз: <xliff:g id="PERMISSION_1">%2$s</xliff:g> жана <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_multi_permission" msgid="4080701771111456927">"Унаа айдап баратканда <xliff:g id="APP">%2$s</xliff:g> колдонмосуна <xliff:g id="COUNT">%1$d</xliff:g> уруксат бердиңиз"</string>
<string name="post_drive_permission_decision_reminder_summary_multi_apps" msgid="5253882771252863902">"{count,plural, =1{Унаа айдап баратканда <xliff:g id="APP_0">%1$s</xliff:g> жана дагы # колдонмого уруксат бердиңиз}other{Унаа айдап баратканда <xliff:g id="APP_1">%1$s</xliff:g> жана дагы # колдонмого уруксат бердиңиз}}"</string>
- <string name="go_to_settings" msgid="1053735612211228335">"Жөндөөлөргө өтүү"</string>
+ <string name="go_to_settings" msgid="1053735612211228335">"Параметрлерге өтүү"</string>
<string name="auto_revoke_setting_subtitle" msgid="8631720570723050460">"Айрым колдонмолор бир нече ай иштетилген жок"</string>
<string name="permissions_removed_category_title" msgid="1064754271178447643">"Өчүрүлгөн уруксаттар"</string>
<string name="permission_removed_page_title" msgid="2627436155091001209">"Уруксаттар өчүрүлдү"</string>
@@ -351,9 +353,9 @@
<string name="role_assistant_short_label" msgid="3369003713187703399">"Санариптик жардамчы колдонмосу"</string>
<string name="role_assistant_description" msgid="6622458130459922952">"Көмөкчү колдонмолор экранда көргөн маалыматыңыздын негизинде сизге жардам бере алат. Айрым колдонмолор жүргүзгүчтү жана айтып киргизүү функциясын да колдоого алат."</string>
<string name="role_browser_label" msgid="2877796144554070207">"Демейки серепчи"</string>
- <string name="role_browser_short_label" msgid="6745009127123292296">"\"Серепчи\" колдонмосу"</string>
+ <string name="role_browser_short_label" msgid="6745009127123292296">"Серепчи колдонмосу"</string>
<string name="role_browser_description" msgid="3465253637499842671">"Сайттарга кирип, шилтемелер боюнча өткөнгө мүмкүнчүлүк берген колдонмолор."</string>
- <string name="role_browser_request_title" msgid="2895200507835937192">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосун демейки \"серепчи\" колдонмосу катары коёсузбу?"</string>
+ <string name="role_browser_request_title" msgid="2895200507835937192">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосун демейки серепчи колдонмосу катары коёсузбу?"</string>
<string name="role_browser_request_description" msgid="5888803407905985941">"Уруксаттардын кереги жок"</string>
<string name="role_dialer_label" msgid="1100224146343237968">"Демейки телефон колдонмосу"</string>
<string name="role_dialer_short_label" msgid="7186888549465352489">"\"Телефон\" колдонмосу"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Кыска жазуулар колдонмосу"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Түзмөгүңүздө кыска жазууларды терүү мүмкүнчүлүгүн берген колдонмолор"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"кыска жазуулар"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Учурдагы демейки колдонмо"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Экинчи суралбасын"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Демейки катары коюу"</string>
@@ -442,68 +454,93 @@
<string name="incident_report_notification_title" msgid="4635984625656519773">"Мүчүлүштүктөрдү аныктоо дайындары бөлүшүлсүнбү?"</string>
<string name="incident_report_notification_text" msgid="3376480583513587923">"<xliff:g id="APP_NAME">%1$s</xliff:g> мүчүлүштүктөрдү оңдоо маалыматын жүктөп бергиси келет."</string>
<string name="incident_report_dialog_title" msgid="669104389325204095">"Мүчүлүштүктөр тууралуу кабарлансынбы?"</string>
- <string name="incident_report_dialog_intro" msgid="5897733669850951832">"Тутум бир мүчүлүштүктү аныктады."</string>
+ <string name="incident_report_dialog_intro" msgid="5897733669850951832">"Система бир мүчүлүштүктү аныктады."</string>
<string name="incident_report_dialog_text" msgid="5675553296891757523">"\"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" колдонмосу ушул түзмөктөн <xliff:g id="DATE">%2$s</xliff:g>, саат <xliff:g id="TIME">%3$s</xliff:g> түзүлгөн мүчүлүштүктөр тууралуу отчетту жүктөп берүүнү сурап жатат. Отчетто колдонуучулардын аттары, жүргөн жерлери, түзмөктүн идентификаторлору жана тармактын дайын-даректери сыяктуу түзмөгүңүздөгү же колдонмолоруңуздагы жеке маалымат камтылышы мүмкүн. Андыктан мүчүлүштүктөр тууралуу отчетту ишенимдүү адамдар жана колдонмолор менен гана бөлүшүңүз. \"<xliff:g id="APP_NAME_1">%4$s</xliff:g>\" колдонмосуна мүчүлүштүк тууралуу отчетту жүктөөгө уруксат бересизби?"</string>
<string name="incident_report_error_dialog_text" msgid="4189647113387092272">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы мүчүлүштүк тууралуу кабарды иштетүүдө ката кетти. Мүчүлүштүктөрдү аныктоо тууралуу кеңири маалыматтарды бөлүшүү сурамы четке кагылды. Ыңгайсыздык үчүн кечирим сурайбыз."</string>
<string name="incident_report_dialog_allow_label" msgid="2970242967721155239">"Уруксат берүү"</string>
<string name="incident_report_dialog_deny_label" msgid="3535314290677579383">"Тыюу салынат"</string>
<string name="adjust_user_sensitive_title" msgid="4196724451314280527">"Өркүндөтүлгөн жөндөөлөр"</string>
<string name="menu_adjust_user_sensitive" msgid="6497923610654425780">"Өркүндөтүлгөн жөндөөлөр"</string>
- <string name="adjust_user_sensitive_globally_title" msgid="8649190949066029174">"Тутум колдонмолорунун колдонгондугун көрсөтүү"</string>
+ <string name="adjust_user_sensitive_globally_title" msgid="8649190949066029174">"Система колдонмолорунун колдонгондугун көрсөтүү"</string>
<string name="adjust_user_sensitive_globally_summary" msgid="129467818433773912">"Системанын уруксаттарды колдонгондугу абал тилкесинде, куралдар тактасында жана башка жерде көрүнөт"</string>
<string name="adjust_user_sensitive_per_app_header" msgid="4543506440989005648">"Тандалган колдонмолорду көрсөтүү"</string>
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Үн жардамчысынын иштегенин чагылдырган сүрөтчөнү көрсөтүү"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Үн жардамчысын иштетүү үчүн микрофон колдонулганда, абал тилкесинде сүрөтчө көрүнөт"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосу үчүн түзмөгүңүздөгү сүрөттөр менен мультимедиа файлдарын иштетесизби?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>
- <string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Бул колдонмо кайда жүргөнүңүздү ар дайым, колдонмону пайдаланбай турганда да, көрүүгө уруксат сурашы мүмкүн. "<annotation id="link">"Жөндөөлөрдөн уруксат бериңиз."</annotation></string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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> түзмөгүңүздүн турган жерин көрүүгө уруксат бересизби?"</string>
+ <string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Бул колдонмо кайда жүргөнүңүздү ар дайым, колдонмону пайдаланбай турганда да, көрүүгө уруксат сурашы мүмкүн. "<annotation id="link">"Параметрлерден уруксат бериңиз."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосу үчүн түзмөктүн жайгашкан жерин пайдалануу мүмкүнчүлүгү өзгөртүлсүнбү?"</string>
- <string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Бул колдонмо кайда жүргөнүңүздү ар дайым, колдонмону пайдаланбай турганда да, көрүүгө уруксат сурап жатат. "<annotation id="link">"Жөндөөлөрдөн уруксат бериңиз."</annotation></string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; үчүн &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздүн турган жерин көрүү мүмкүнчүлүгүн өзгөртөсүзбү?"</string>
+ <string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Бул колдонмо кайда жүргөнүңүздү ар дайым, колдонмону пайдаланбай турганда да, көрүүгө уруксат сурап жатат. "<annotation id="link">"Параметрлерден уруксат бериңиз."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; жакын жердеги түзмөктөрдү таап, аларга туташып жана абалын аныктай берсинби?"</string>
- <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; жакын жердеги түзмөктөрдү таап, аларга туташып жана абалын аныктай алсынбы? "<annotation id="link">"Жөндөөлөрдөн уруксат берүү."</annotation></string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө жакын жердеги түзмөктөрдү таап, туташып, абалын аныктай алсынбы?"</string>
+ <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; жакын жердеги түзмөктөрдү таап, аларга туташып жана абалын аныктай алсынбы? "<annotation id="link">"Параметрлерден уруксат берүү."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> колдонмосунда жайгашкан жер болжолдуу эмес, так аныкталсынбы?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө SMS билдирүүлөрдү көрүп жана жөнөтүүгө мүмкүнчүлүк алсынбы?"</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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздөгү сүрөттөр, мультимедиа жана файлдарга мүмкүнчүлүк алсынбы?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна ушул түзмөктөгү &lt;b&gt;сүрөттөрдү, видеолорду, ырларды жана аудио файлдарды&lt;/b&gt; жеткиликтүү кыласызбы?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна ушул түзмөктөгү &lt;b&gt;сүрөттөрдү, видеолорду, ырларды, аудио файлдарды жана башка нерселерди&lt;/b&gt; жеткиликтүү кыласызбы?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна ушул түзмөктөгү ырлар менен аудио файлдарды жеткиликтүү кыласызбы?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздөгү ырлар менен аудио файлдарга мүмкүнчүлүк алсынбы?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна ушул түзмөктөгү сүрөттөр менен видеолорду жеткиликтүү кыласызбы?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздөгү сүрөттөр менен видеолорго мүмкүнчүлүк алсынбы?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна ушул түзмөктөгү дагы башка сүрөттөр менен видеолорду жеткиликтүү кыласызбы?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө башка сүрөт жана видеолорду көрүүгө уруксат бересизби?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна аудио файлдарды жаздырганга уруксат бересизби?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө аудио жаздырууга уруксат бересизби?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Колдонмону колдонуп жатканда гана, ал аудио жаздыра алат"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна аудио файлдарды жаздырууга уруксат бересизби?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө аудио жаздырууга уруксат бересизби?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Бул колдонмону колдонбой турсаңыз деле, ал такай аудио жаздыра берет. "<annotation id="link">"Ага жөндөөлөрдөн уруксат бериңиз."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосу үчүн микрофонду пайдалануу мүмкүнчүлүгүн өзгөртөсүзбү?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; үчүн &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө микрофонду пайдалануу мүмкүнчүлүгүн өзгөртөсүзбү?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Бул колдонмону колдонбой турсаңыз деле, ал такай аудио жаздыра берет. "<annotation id="link">"Ага жөндөөлөрдөн уруксат бериңиз."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна кыймыл-аракеттериңизге көз салып турганга мүмкүнчүлүк бересизби?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө кыймыл-аракеттериңизди көрүүгө уруксат бересизби?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна сүрөттөр менен видеолорду тартканга уруксат бересизби?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө сүрөт менен видео тартууга уруксат бересизби?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Колдонмону колдонуп жатканда гана, ал сүрөт жана видео тарта алат"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна сүрөт менен видео тартууга уруксат бересизби?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө сүрөт менен видео тартууга уруксат бересизби?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Бул колдонмону колдонбой турсаңыз деле, ал такай сүрөт жана видео тарта берет. "<annotation id="link">"Ага жөндөөлөрдөн уруксат бериңиз."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосу үчүн камераны пайдалануу мүмкүнчүлүгүн өзгөртөсүзбү?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; үчүн &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө камераны пайдалануу мүмкүнчүлүгүн өзгөртөсүзбү?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Бул колдонмону колдонбой турсаңыз деле, ал такай сүрөт жана видео тарта берет. "<annotation id="link">"Ага жөндөөлөрдөн уруксат бериңиз."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна телефондогу чалуулар тизмесин пайдаланууга уруксат бересизби?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө телефон чалуулардын тизмесин көрүүгө мүмкүнчүлүк алсынбы?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна телефон чалууга жана чалууларды башкарууга уруксат бересизби?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө телефон чалып жана чалууларды башкара алсынбы?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна организмдин абалына көз салган сенсордун көрсөткүчтөрүн көрүүгө уруксат бересизби?"</string>
- <string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Бул колдонмону иштетпей турсаңыз деле, ал такай организмдин негизги көрсөткүчтөрү тууралуу cенсордун дайындарын жаздыра алат. Муну өзгөртүү үчүн "<annotation id="link">"жөндөөлөргө өтүңүз."</annotation></string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздөгү дене-бой сенсорлорунун маалыматына мүмкүнчүлүк алсынбы?"</string>
+ <string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Бул колдонмону иштетпей турсаңыз деле, ал такай организмдин негизги көрсөткүчтөрү тууралуу cенсордун дайындарын жаздыра алат. Муну өзгөртүү үчүн "<annotation id="link">"параметрлерге өтүңүз."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна дене-бой сенсорлорунун көрсөткүчтөрүн көрүүгө уруксат бересизби?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө дене-бой сенсорлорунун маалыматын көрүүгө мүмкүнчүлүк алсынбы?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Бул колдонмого дене сенсорлорунун көрсөткүчтөрүн көрүү мүмкүнчүлүгүн берүү үчүн (колдонмо колдонулбай турганда да) "<annotation id="link">"параметрлерди өзгөртүңүз."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосу колдонулуп жатканда дене бой сенсорлорунун көрсөткүчтөрүн көрүү мүмкүнчүлүгүн бересизби?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Колдонулуп жатканда &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дене сенсорлорунун маалыматына кире берсинби?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна сизге билдирмелерди жөнөтүүгө уруксат бересизби?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; түзмөгүңүздө сизге билдирмелерди жөнөтүүгө уруксат бересизби?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Көзөмөлдөнгөн уруксаттар"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> жүргөн жериңизди аныктай алат"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Уюмуңуз <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна жүргөн жериңизди аныктоого уруксат берет"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Башка уруксаттар"</string>
- <string name="not_used_permissions_label" msgid="3939839426115141264">"Тутум пайдаланган уруксат"</string>
+ <string name="not_used_permissions_label" msgid="3939839426115141264">"Система пайдаланган уруксат"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Системанын колдонмолору гана пайдаланган уруксаттар."</string>
<string name="additional_permissions_label" msgid="7693557637462569046">"Кошумча уруксаттар"</string>
<string name="additional_permissions_description" msgid="2186611950890732112">"Колдонмолор аныктаган уруксаттар."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Бул колдонмо жайгашкан жер тууралуу маалыматты үчүнчү тараптар менен бөлүшүүгө уруксат сурап жатат"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Маалыматты бөлүшүү жана турган жер"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Бөлүшүп жаткан нерселер кайдан алынат"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Иштеп чыгуучу бул колдонмо маалыматтарды кантип бөлүшкөнүн түзмөктүн өндүрүүчүсүнө билдирди. Иштеп чыгуучу бул маалыматты кийинчерээк жаңыртып турушу мүмкүн."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Иштеп чыгуучу бул колдонмо маалыматтарды кантип бөлүшкөнүн төмөнкүгө билдирди: "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". Иштеп чыгуучу бул маалыматты жаңыртып турушу мүмкүн."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Бул колдонмо турган жериңиз тууралуу маалыматты төмөнкүлөр үчүн бөлүшүшү мүмкүн:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Маалымат ар кандай жолдор менен бөлүшүлөт"</string>
@@ -608,12 +646,10 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Маалыматтардын коопсуздугу"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Турган жериңиз тууралуу маалымат бөлүшүлүп жатышы мүмкүн"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Бул колдонмо турган жериңиз тууралуу маалыматты үчүнчү тараптар менен бөлүшүүсү мүмкүн"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Бул шилтемени ачууга болбойт"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Турган жериңизди билдирүү ыкмасын жаңыртуу"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Жүргөн жериңизди көрсөткөн ыкманы өзгөрткөн колдонмолорду карап чыксаңыз болот"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Бул колдонмолор жүргөн жериңиз тууралуу маалыматты бөлүшүү ыкмасын өзгөрттү. Алар бул маалыматты мурда бөлүшпөй же азыр жарнамалоо же маркетинг максаттарында бөлүшүшү мүмкүн."</string>
- <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Бул колдонмолорду иштеп чыгуучулар дайын-даректерди бөлүшүү тууралуу маалыматты колдонмолор дүкөнүнө беришти. Алар бул маалыматты жаңыртып турушу мүмкүн.\n\nМаалыматтарды бөлүшүү ыкмасы колдонмонун версиясына, колдонулушуна, регионго жана курагыңызга жараша айырмаланышы мүмкүн."</string>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Бул колдонмолорду иштеп чыгуучулар нерселерди бөлүшүү тууралуу маалыматты колдонмолор дүкөнүнө беришти. Алар бул маалыматты жаңыртып турушу мүмкүн.\n\nМаалыматтарды бөлүшүү ыкмасы колдонмонун версиясына, колдонулушуна, регионго жана курагыңызга жараша айырмаланышы мүмкүн."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Маалыматтарды бөлүшүү жөнүндө кеңири маалымат"</string>
<string name="shares_location_with_third_parties" msgid="2278051743742057767">"Жүргөн жериңиз тууралуу маалымат үчүнчү тараптар менен бөлүшүлүп жатат"</string>
<string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Жүргөн жериңизди үчүнчү тараптар жарнамалоо же маркетинг максатында билип турушат"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Маалыматты бөлүшүү жаңыртуулары"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Айрым колдонмолор турган жериңизди билдирүү ыкмасын өзгөрттү"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Параметрлер"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Cаат <xliff:g id="TIME_DATE">%1$s</xliff:g> колдонулду"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Кечээ саат <xliff:g id="TIME_DATE">%1$s</xliff:g> колдонулду"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> саат <xliff:g id="TIME_DATE_1">%2$s</xliff:g> колдонулду"</string>
</resources>
diff --git a/PermissionController/res/values-lo-v33/strings.xml b/PermissionController/res/values-lo-v33/strings.xml
index 50beda6aa..743a5bec9 100644
--- a/PermissionController/res/values-lo-v33/strings.xml
+++ b/PermissionController/res/values-lo-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"ແຈ້ງເຕືອນເພີ່ມເຕີມ"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"ປິດການແຈ້ງເຕືອນແລ້ວ"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{ຂະຫຍາຍ ແລະ ເບິ່ງແຈ້ງເຕືອນເພີ່ມອີກ 1 ລາຍການ}other{ຂະຫຍາຍ ແລະ ເບິ່ງແຈ້ງເຕືອນເພີ່ມອີກ # ລາຍການ}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"ແຈ້ງເຕືອນ. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"ຄຳສັ່ງສຳເລັດ"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"ກວດເບິ່ງການຕັ້ງຄ່າທີ່ສາມາດເພີ່ມການປ້ອງກັນໃຫ້ກັບອຸປະກອນຂອງທ່ານ"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"ການຕັ້ງຄ່າດ່ວນຄວາມປອດໄພ ແລະ ຄວາມເປັນສ່ວນຕົວ"</string>
diff --git a/PermissionController/res/values-lo/strings.xml b/PermissionController/res/values-lo/strings.xml
index 083819bf5..cd4e13133 100644
--- a/PermissionController/res/values-lo/strings.xml
+++ b/PermissionController/res/values-lo/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"ຂໍ້ມູນເພີ່ມເຕີມ"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"ອະນຸຍາດທັງໝົດ"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"ອະນຸຍາດທັງໝົດຕະຫຼອດ"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"ອະນຸຍາດສິດເຂົ້າເຖິງແບບຈຳກັດ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ເລືອກຮູບພາບ ແລະ ວິດີໂອ"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"ເລືອກເພີ່ມເຕີມ"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ຢ່າເລືອກເພີ່ມເຕີມ"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ແອັບ"</string>
<string name="app_permissions" msgid="3369917736607944781">"ສິດອະນຸຍາດແອັບ"</string>
<string name="unused_apps" msgid="2058057455175955094">"ແອັບທີ່ບໍ່ໄດ້ໃຊ້"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ແກ້ໄຂຮູບພາບທີ່ເລືອກໄວ້ສຳລັບແອັບນີ້"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ບໍ່ມີແອັບທີ່ບໍ່ໄດ້ໃຊ້"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ແອັບທີ່ບໍ່ໄດ້ໃຊ້"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"ການຕັດສິນໃຈການອະນຸຍາດຫຼ້າສຸດ"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"ທຸກການອະນຸຍາດ"</string>
<string name="other_permissions" msgid="2901186127193849594">"ຄວາມສາມາດອື່ນຂອງແອັບ"</string>
<string name="permission_request_title" msgid="8790310151025020126">"ການຮ້ອງຂໍການອະນຸຍາດ"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"ຕິດຕັ້ງ/ຖອນການຕິດຕັ້ງ ຄຳສັ່ງທີ່ບໍ່ຮອງຮັບຢູ່ Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"ເລືອກວ່າຈະອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຫຍັງໄດ້ແດ່"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"ອັບເດດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ແລ້ວ. ກະລຸນາເລືອກວ່າຈະໃຫ້ແອັບນີ້ເຂົ້າເຖິງຫຍັງໄດ້ແດ່."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"ຍົກເລີກ"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ລຶບສິດອະນຸຍາດຫາກບໍ່ໄດ້ໃຊ້ແອັບ"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"ລຶບການອະນຸຍາດອອກ ແລະ ສ້າງພື້ນທີ່ຫວ່າງ"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"ຢຸດການເຄື່ອນໄຫວແອັບຊົ່ວຄາວຫາກບໍ່ໄດ້ໃຊ້"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ຈັດການແອັບຫາກບໍ່ໄດ້ໃຊ້"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ລຶບການອະນຸຍາດອອກ, ລຶບໄຟລ໌ຊົ່ວຄາວ ແລະ ຢຸດການແຈ້ງເຕືອນ"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ລຶບການອະນຸຍາດອອກ, ລຶບໄຟລ໌ຊົ່ວຄາວ, ຢຸດການແຈ້ງເຕືອນ ແລະ ເກັບແອັບໄວ້ໃນແຟ້ມ"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"ເພື່ອປົກປ້ອງຂໍ້ມູນຂອງທ່ານ, ສິດອະນຸຍາດສຳລັບແອັບນີ້ຈະຖືກລຶບອອກຫາກບໍ່ໄດ້ໃຊ້ແອັບສອງສາມເດືອນ."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"ເພື່ອປົກປ້ອງຂໍ້ມູນຂອງທ່ານ, ຫາກບໍ່ໄດ້ໃຊ້ແອັບສອງສາມເດືອນ, ສິດອະນຸຍາດຕໍ່ໄປນີ້ຈະຖືກລຶບອອກ: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"ເພື່ອປົກປ້ອງຂໍ້ມູນຂອງທ່ານ, ລະບົບໄດ້ລຶບສິດອະນຸຍາດອອກຈາກແອັບຕ່າງໆທີ່ທ່ານບໍ່ໄດ້ໃຊ້ສອງສາມເດືອນແລ້ວ."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"ແອັບຂຽນບັນທຶກ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"ແອັບທີ່ອະນຸຍາດໃຫ້ທ່ານຈົດບັນທຶກຢູ່ອຸປະກອນຂອງທ່ານ"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ບັນທຶກ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"ຄ່າເລີ່ມຕົ້ນປັດຈຸບັນ"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"ບໍ່ຕ້ອງຖາມອີກ"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ຕັ້ງເປັນຄ່າເລີ່ມຕົ້ນ"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"ສະແດງການກວດຫາຕົວເປີດຜູ້ຊ່ວຍ"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"ສະແດງໄອຄອນໃນແຖບສະຖານະເມື່ອໃຊ້ໄມໂຄຣໂຟນເພື່ອເປີດໃຊ້ຜູ້ຊ່ວຍແບບສຽງ"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ເຂົ້າເຖິງຮູບພາບ ແລະ ມີເດຍຢູ່ອຸປະກອນຂອງທ່ານບໍ?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຮູບພາບ ແລະ ສື່ຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງລາຍຊື່ຜູ້ຕິດຕໍ່ຂອງທ່ານຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"ອະນຸຍາດໃຫ້ &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"ອະນຸຍາດໃຫ້ &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> ຂອງທ່ານບໍ?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ແອັບນີ້ອາດຕ້ອງການເຂົ້າເຖິງສະຖານທີ່ຂອງທ່ານຕະຫຼອດເວລາ, ເຖິງແມ່ນວ່າທ່ານຈະບໍ່ໄດ້ໃຊ້ແອັບຢູ່ກໍຕາມ. "<annotation id="link">"ອະນຸຍາດໃນການຕັ້ງຄ່າ."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"ປ່ຽນສິດອະນຸຍາດເຂົ້າເຖິງສຳລັບ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ບໍ?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"ປ່ຽນແປງສິດເຂົ້າເຖິງສະຖານທີ່ຂອງ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"ແອັບນີ້ຕ້ອງການເຂົ້າເຖິງສະຖານທີ່ຂອງທ່ານຕະຫຼອດເວລາ, ເຖິງແມ່ນວ່າທ່ານຈະບໍ່ໄດ້ໃຊ້ແອັບຢູ່ກໍຕາມ. "<annotation id="link">"ອະນຸຍາດໃນການຕັ້ງຄ່າ."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ຊອກຫາ, ເຊື່ອມຕໍ່ຫາ ແລະ ກຳນົດຕຳແໜ່ງທີ່ກ່ຽວຂ້ອງກັນຂອງອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງບໍ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ຊອກຫາ, ເຊື່ອມຕໍ່ ແລະ ລະບຸສະຖານທີ່ທີ່ກ່ຽວຂ້ອງກັນຂອງອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ຊອກຫາ, ເຊື່ອມຕໍ່ຫາ ແລະ ກຳນົດຕຳແໜ່ງທີ່ກ່ຽວຂ້ອງກັນຂອງອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງບໍ? "<annotation id="link">"ອະນຸຍາດໃນການຕັ້ງຄ່າ."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"ປ່ຽນການເຂົ້າເຖິງສະຖານທີ່ຂອງ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ຈາກໂດຍປະມານເປັນແບບລະອຽດບໍ?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"ປ່ຽນສິດເຂົ້າເຖິງສະຖານທີ່ຂອງ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງສະຖານທີ່ໂດຍປະມານຂອງ &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງປະຕິທິນຂອງທ່ານຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ສົ່ງ ແລະ ເບິ່ງຂໍ້ຄວາມ SMS ຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຮູບພາບ, ສື່ ແລະ ໄຟລ໌ຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງ &lt;b&gt;ຮູບພາບ, ວິດີໂອ, ເພງ ແລະ ສຽງ&lt;/b&gt; ຢູ່ອຸປະກອນນີ້ບໍ?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງ &lt;b&gt;ຮູບພາບ, ວິດີໂອ, ເພງ, ສຽງ ແລະ ໄຟລ໌ອື່ນໆ&lt;/b&gt; ຢູ່ອຸປະກອນນີ້ບໍ?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງເພງ ແລະ ສຽງຢູ່ອຸປະກອນນີ້ບໍ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງເພງ ແລະ ສຽງຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຮູບພາບ ແລະ ວິດີໂອຢູ່ອຸປະກອນນີ້ບໍ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຮູບພາບ ແລະ ວິດີໂອຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຮູບພາບ ແລະ ວິດີໂອເພີ່ມເຕີມຢູ່ອຸປະກອນນີ້ບໍ?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຮູບພາບ ແລະ ວິດີໂອເພີ່ມເຕີມຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ບັນທຶກສຽງບໍ?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ບັນທຶກສຽງຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"ແອັບນີ້ສາມາດບັນທຶກສຽງໃນຂະນະທີ່ທ່ານກຳລັງໃຊ້ແອັບເທົ່ານັ້ນ"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ບັນທຶກສຽງບໍ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ບັນທຶກສຽງຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ແອັບນີ້ອາດຕ້ອງການບັນທຶກສຽງຕະຫຼອດເວລາ, ເຖິງແມ່ນວ່າທ່ານຈະບໍ່ໄດ້ໃຊ້ແອັບຢູ່ກໍຕາມ. "<annotation id="link">"ອະນຸຍາດໃນການຕັ້ງຄ່າ."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"ປ່ຽນສິດເຂົ້າເຖິງໄມໂຄຣໂຟນສຳລັບ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ບໍ?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"ປ່ຽນແປງສິດເຂົ້າເຖິງໄມໂຄຣໂຟນຂອງ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"ແອັບນີ້ຕ້ອງການບັນທຶກສຽງຕະຫຼອດເວລາ, ເຖິງແມ່ນວ່າທ່ານຈະບໍ່ໄດ້ໃຊ້ແອັບຢູ່ກໍຕາມ. "<annotation id="link">"ອະນຸຍາດໃນການຕັ້ງຄ່າ."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງກິດຈະກຳທາງກາຍະພາບຂອງທ່ານບໍ?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງກິດຈະກຳທາງກາຍະພາບຂອງທ່ານຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອບໍ?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"ແອັບຈະສາມາດຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອໄດ້ສະເພາະໃນເວລາທີ່ທ່ານກຳລັງໃຊ້ແອັບເທົ່ານັ້ນ"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອບໍ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ແອັບນີ້ອາດຕ້ອງການຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອຕະຫຼອດເວລາ, ເຖິງແມ່ນວ່າທ່ານຈະບໍ່ໄດ້ໃຊ້ແອັບຢູ່ກໍຕາມ. "<annotation id="link">"ອະນຸຍາດໃນການຕັ້ງຄ່າ."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"ປ່ຽນສິດເຂົ້າເຖິງກ້ອງສຳລັບ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ບໍ?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"ປ່ຽນແປງສິດເຂົ້າເຖິງກ້ອງຂອງ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"ແອັບອາດຕ້ອງການຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອຕະຫຼອດເວລາ, ເຖິງແມ່ນວ່າທ່ານຈະບໍ່ໄດ້ໃຊ້ແອັບຢູ່ກໍຕາມ. "<annotation id="link">"ອະນຸຍາດໃນການຕັ້ງຄ່າ."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງບັນທຶກການໂທທັງໝົດຂອງທ່ານໄດ້ບໍ?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງບັນທຶກການໂທໃນໂທລະສັບຂອງທ່ານຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ໂທ ແລະ ຈັດການການໂທບໍ?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໂທ ແລະ ຈັດການການໂທຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີກ່ຽວກັບສັນຍານຊີບຂອງທ່ານບໍ?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີກ່ຽວກັບສັນຍານຊີບຂອງທ່ານຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"ແອັບນີ້ຕ້ອງການເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີກ່ຽວກັບສັນຍານຊີບຂອງທ່ານຕະຫຼອດເວລາ, ເຖິງແມ່ນວ່າທ່ານຈະບໍ່ໄດ້ກຳລັງໃຊ້ແອັບຢູ່ກໍຕາມ. ເພື່ອປ່ຽນແປງສິ່ງນີ້, "<annotation id="link">"ໃຫ້ເຂົ້າໄປການຕັ້ງຄ່າ."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີກ່ຽວກັບສັນຍານຊີບຂອງທ່ານບໍ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີກ່ຽວກັບສັນຍານຊີບຂອງທ່ານຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"ເພື່ອເຮັດໃຫ້ແອັບນີ້ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີຮ່າງກາຍໄດ້ຕະຫຼອດເວລາ, ເຖິງແມ່ນວ່າທ່ານຈະບໍ່ໄດ້ກຳລັງໃຊ້ແອັບຢູ່ກໍຕາມ, "<annotation id="link">"ໃຫ້ເຂົ້າໄປການຕັ້ງຄ່າ."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ສືບຕໍ່ອະນຸຍາດ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີຮ່າງກາຍໃນຂະນະທີ່ກຳລັງໃຊ້ແອັບຢູ່ບໍ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"ສືບຕໍ່ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີຮ່າງກາຍຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານໃນລະຫວ່າງທີ່ໃຊ້ແອັບບໍ?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ສົ່ງການແຈ້ງເຕືອນຫາທ່ານບໍ?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"ອະນຸຍາດໃຫ້ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ສົ່ງການແຈ້ງເຕືອນຫາທ່ານຢູ່ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ຂອງທ່ານບໍ?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"ສິດອະນຸຍາດທີ່ມີການຄວບຄຸມ"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ມີສິດເຂົ້າເຖິງສະຖານທີ່"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"ອົງກອນຂອງທ່ານອະນຸຍາດ <xliff:g id="APP_NAME">%1$s</xliff:g> ໃຫ້ເຂົ້າເຖິງສະຖານທີ່ຂອງທ່ານ"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"ການອະນຸຍາດອື່ນໆ"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"ການອະນຸຍາດທີ່ໃຊ້ໂດຍລະບົບ"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"ການອະນຸຍາດທີ່ໃຊ້ໂດຍແອັບພລິເຄຊັນລະບົບເທົ່ານັ້ນ."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"ແອັບນີ້ລະບຸວ່າມັນອາດແບ່ງປັນຂໍ້ມູນສະຖານທີ່ກັບພາກສ່ວນທີສາມ"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ການແບ່ງປັນຂໍ້ມູນ ແລະ ສະຖານທີ່"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ແຫຼ່ງທີ່ມາຂອງລາຍລະອຽດການແບ່ງປັນຂໍ້ມູນ"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ນັກພັດທະນາແອັບໄດ້ໃຫ້ຂໍ້ມູນກັບຜູ້ຜະລິດອຸປະກອນນີ້ກ່ຽວກັບວິທີທີ່ແອັບນີ້ແບ່ງປັນຂໍ້ມູນ. ນັກພັດທະນາແອັບອາດອັບເດດຂໍ້ມູນນີ້ເມື່ອເວລາຜ່ານໄປ."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ນັກພັດທະນາແອັບໄດ້ໃຫ້ຂໍ້ມູນໄວ້ໃນ "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" ກ່ຽວກັບວິທີທີ່ແອັບນີ້ແບ່ງປັນຂໍ້ມູນ. ນັກພັດທະນາອາດອັບເດດຂໍ້ມູນນີ້ເມື່ອເວລາຜ່ານໄປ."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ແອັບນີ້ອາດແບ່ງປັນຂໍ້ມູນສະຖານທີ່ຍ້ອນ:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ການແບ່ງປັນຂໍ້ມູນອາດແຕກຕ່າງກັນໄປ"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ຄວາມປອດໄພຂອງຂໍ້ມູນ"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"ອາດມີການແບ່ງປັນຂໍ້ມູນສະຖານທີ່"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"ແອັບນີ້ລະບຸວ່າມັນອາດແບ່ງປັນຂໍ້ມູນສະຖານທີ່ກັບພາກສ່ວນທີສາມ"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ບໍ່ສາມາດເປີດລິ້ງນີ້ໄດ້"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"ການອັບເດດການແບ່ງປັນຂໍ້ມູນສະຖານທີ່"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ກວດສອບແອັບທີ່ປ່ຽນແປງວິທີທີ່ແອັບອາດແບ່ງປັນຂໍ້ມູນສະຖານທີ່ຂອງທ່ານ"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"ແອັບເຫຼົ່ານີ້ໄດ້ປ່ຽນແປງວິທີທີ່ແອັບອາດແບ່ງປັນຂໍ້ມູນສະຖານທີ່ຂອງທ່ານແລ້ວ. ແອັບເຫຼົ່ານີ້ອາດບໍ່ເຄີຍແບ່ງປັນຂໍ້ມູນມາກ່ອນ ຫຼື ອາດແບ່ງປັນຂໍ້ມູນເພື່ອຈຸດປະສົງໃນການໂຄສະນາ ຫຼື ການຕະຫຼາດ."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ການອັບເດດການແບ່ງປັນຂໍ້ມູນ"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"ບາງແອັບໄດ້ປ່ຽນແປງວິທີທີ່ແອັບອາດແບ່ງປັນຂໍ້ມູນສະຖານທີ່ຂອງທ່ານແລ້ວ"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ການຕັ້ງຄ່າ"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"ເຂົ້າເຖິງເມື່ອ <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"ເຂົ້າເຖິງມື້ວານນີ້ເມື່ອ <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"ເຂົ້າເຖິງເມື່ອ <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-lt-v33/strings.xml b/PermissionController/res/values-lt-v33/strings.xml
index b4cfa2a91..41c3bdc9f 100644
--- a/PermissionController/res/values-lt-v33/strings.xml
+++ b/PermissionController/res/values-lt-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Daugiau įspėjimų"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Atsisakyta įspėjimų"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Išskleiskite ir peržiūrėkite dar vieną įspėjimą}one{Išskleiskite ir peržiūrėkite dar # įspėjimą}few{Išskleiskite ir peržiūrėkite dar # įspėjimus}many{Išskleiskite ir peržiūrėkite dar # įspėjimo}other{Išskleiskite ir peržiūrėkite dar # įspėjimų}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Įspėjimas. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Veiksmas atliktas"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Patikrinkite nustatymus, kuriuos taikant galima užtikrinti papildomą įrenginio apsaugą"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Spartieji saugos ir privatumo nustatymai"</string>
diff --git a/PermissionController/res/values-lt/strings.xml b/PermissionController/res/values-lt/strings.xml
index 81f670ff3..7e637b415 100644
--- a/PermissionController/res/values-lt/strings.xml
+++ b/PermissionController/res/values-lt/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Daugiau inform."</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Leisti viską"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Visada leisti viską"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Suteikti ribotą prieigą"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Pasirinkti nuotraukas ir vaizdo įrašus"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Pasirinkti daugiau"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nesirinkti daugiau"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Programos"</string>
<string name="app_permissions" msgid="3369917736607944781">"Programų leidimai"</string>
<string name="unused_apps" msgid="2058057455175955094">"Nenaudojamos programos"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Redaguoti pasirinktas šios programos nuotraukas"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nėra nenaudojamų programų"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Nenaudojamų programų: 0"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nauj. sprendimai dėl leidimų"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Visi leidimai"</string>
<string name="other_permissions" msgid="2901186127193849594">"Kitos programos galimybės"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Leidimo užklausa"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Diegimo / pašalinimo veiksmai nepalaikomi sistemoje „Wear“."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Pasirinkite, ką norite leisti programai &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Programa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; buvo atnaujinta. Pasirinkite, ką norite leisti šiai programai pasiekti."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Atšaukti"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Pašalinti leidimus, jei programa nenaudojama"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Pašalinti leidimus ir atlaisvinti vietos"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pristabdyti nenaudojamų programų veiklą"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Tvarkyti programą, jei nenaudojama"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Pašalinkite leidimus, ištrinkite laikinus failus ir sustabdykite pranešimus"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Pašalinti leidimus, ištrinti laikinus failus, sustabdyti pranešimus ir archyvuoti programą"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Siekiant apsaugoti duomenis, šios programos leidimai bus pašalinti, jei programos nenaudosite kelis mėnesius."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Siekiant apsaugoti duomenis, jei programos nenaudosite kelis mėnesius, bus pašalinti nurodyti leidimai: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Siekiant apsaugoti duomenis, leidimai buvo pašalinti iš programų, kurių nenaudojote kelis mėnesius"</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Paskutinį kartą atidaryta <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Jei leisite valdyti visus failus, ši programa galės pasiekti, keisti ir ištrinti bet kuriuos failus, esančius šio įrenginio bendroje saugykloje arba susietų saugyklų įrenginiuose. Programa gali pasiekti failus nepaklaususi."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Leisti šiai programai pasiekti, keisti ir ištrinti failus, esančius šiame įrenginyje ar bet kuriuose susietų saugyklų įrenginiuose? Ši programa gali pasiekti failus nepaklaususi."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Programos, kurioms suteiktas šis leidimas, gali <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Programos, kurioms suteiktas šis leidimas, gali: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Programos, kurioms suteiktas šis leidimas, gali pasiekti jūsų fizinę veiklą, pvz., ėjimą, važiavimą dviračiu, vairavimą, žingsnių skaičių ir daugiau"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Programos, kurioms suteiktas šis leidimas, gali pasiekti jūsų kalendorių"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Programos, kurioms suteiktas šis leidimas, gali skaityti ir rašyti telefono skambučių žurnalą"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Užrašų programa"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Programos, leidžiančios rašyti užrašus jūsų įrenginyje"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"užrašai"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Dabartinė numatytoji"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Daugiau neklausti"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Nustatyti numatytąja"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Rodyti padėjėjo aktyviklio aptikimą"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Rodyti piktogramą būsenos juostoje, kai naudojant mikrofoną aktyvinama pagalba balsu"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Suteikti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; galimybę pasiekti įrenginio nuotraukas ir mediją?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti įrenginio nuotraukas ir mediją jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti kontaktus?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti kontaktus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Leisti programai &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti įrenginio vietovę?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti jūsų &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt; vietovės informaciją?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Programa galės pasiekti vietovę, tik kai ją naudosite"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Leisti programai &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti įrenginio vietovę?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti jūsų &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> vietovės informaciją?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Ši programa gali norėti pasiekti jūsų vietovę visą laiką, net kai programos nenaudojate. "<annotation id="link">"Leiskite skiltyje „Nustatymai“."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Pakeisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prieigą prie vietovės duomenų?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Keisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prieigą prie vietovės jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Ši programa nori pasiekti jūsų vietovę visą laiką, net kai programos nenaudojate. "<annotation id="link">"Leiskite skiltyje „Nustatymai“."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; rasti netoliese esančius įrenginius, prisijungti prie jų ir nustatyti apytikslį atstumą?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; rasti apytikslę įrenginių netoliese poziciją, aptikti juos ir prisijungti jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; rasti netoliese esančius įrenginius, prisijungti prie jų ir nustatyti apytikslį atstumą? "<annotation id="link">"Leiskite nustatymuose."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Pakeisti <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> vietovės pasiekiamumą iš apytikslės į tikslią?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Leisti „<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>“ prieigą prie vietovės informacijos jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; iš apytikslės į tikslią?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti apytikslę šio įrenginio vietovę?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; apytikslę vietovę?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Tiksli"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Apytikslė"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Suteikti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; galimybę pasiekti kalendorių?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti kalendorių jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; siųsti ir peržiūrėti SMS pranešimus?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; siųsti ir peržiūrėti SMS pranešimus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Suteikti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; galimybę pasiekti įrenginio nuotraukas, mediją ir failus?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti nuotraukas, mediją ir failus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti &lt;b&gt;nuotraukas, vaizdo, garso įrašus ir muziką&lt;/b&gt; šiame įrenginyje?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti &lt;b&gt;nuotrauk., vaizdo, garso įrašus, muziką, kitus failus&lt;/b&gt; įrenginyje?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti muziką ir garso failus šiame įrenginyje?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti muziką ir garso failus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti nuotraukas ir vaizdo įrašus šiame įrenginyje?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti nuotraukas ir vaizdo įrašus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Leisti programai &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti nuotraukas ir vaizdo įrašus šiame įrenginyje?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti daugiau nuotraukų ir vaizdo įrašų jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; įrašyti garsą?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; įrašyti garsą jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Programa galės įrašyti garsą, tik kai ją naudosite"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; įrašyti garsą?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; įrašyti garsą jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Ši programa gali norėti įrašyti garsą visą laiką, net kai programos nenaudojate. "<annotation id="link">"Leiskite skiltyje „Nustatymai“."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Pakeisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prieigą prie mikrofono?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Keisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prieigą prie mikrofono jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Ši programa nori įrašyti garsą visą laiką, net kai programos nenaudojate. "<annotation id="link">"Leiskite skiltyje „Nustatymai“."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Leisti programai &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti fizinės veiklos duomenis?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti fizinės veiklos duomenis jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotografuoti ir įrašyti vaizdo įrašus?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotografuoti ir įrašyti vaizdo įrašus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Programa galės fotografuoti ir įrašyti vaizdo įrašų, tik kai ją naudosite"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotografuoti ir įrašyti vaizdo įrašus?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotografuoti ir įrašyti vaizdo įrašus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Ši programa gali norėti fotografuoti ir įrašyti vaizdo įrašų visą laiką, net kai programos nenaudojate. "<annotation id="link">"Leiskite skiltyje „Nustatymai“."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Pakeisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prieigą prie fotoaparato?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Keisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prieigą prie fotoaparato jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Ši programa nori fotografuoti ir įrašyti vaizdo įrašų visą laiką, net kai programos nenaudojate. "<annotation id="link">"Leiskite skiltyje „Nustatymai“."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti jūsų telefono skambučių žurnalus?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti telefonų skambučių žurnalus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; skambinti ir tvarkyti telefono skambučius?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; skambinti ir tvarkyti telefonų skambučius jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Suteikti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; galimybę pasiekti jutiklių duomenis apie gyvybinius ženklus?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti jutiklių duomenis apie gyvybinių funkcijų rodiklius jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Ši programa nori pasiekti jutiklių duomenis apie jūsų gyvybinių funkcijų rodiklius visą laiką, net kai programos nenaudojate. Kad atliktumėte šį pakeitimą, "<annotation id="link">"eikite į skiltį „Nustatymai“."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Suteikti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; galimybę pasiekti jutiklių duomenis apie gyvybinių funkcijų rodiklius?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti jutiklių duomenis apie gyvybinių funkcijų rodiklius jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Jei norite leisti šiai programai pasiekti kūno jutiklių duomenis visą laiką, net kai nenaudojate programos, "<annotation id="link">"eikite į „Nustatymų“ skiltį"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Toliau leisti programai &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti kūno jutiklių duomenis, kai programa naudojama?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Toliau leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pasiekti kūno jutiklių duomenis jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;, kai programa naudojama?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; siųsti jums pranešimus?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Leisti &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; siųsti jums pranešimus jūsų &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Valdomi leidimai"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ gali pasiekti vietovę"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Jūsų organizacija leidžia programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“ pasiekti jūsų vietovę"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Kiti leidimai"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Leidimai, kuriuos naudoja sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Leidimai, kuriuos naudoja tik sistemos programos."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Ši programa nurodė, kad gali bendrinti vietovės duomenis su trečiosiomis šalimis"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Duomenų bendrinimas ir vietovė"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Iš kur gaunama duomenų bendrinimo informacija"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Kūrėjas pateikė informacijos šio įrenginio gamintojui apie tai, kaip ši programa bendrina duomenis. Bėgant laikui kūrėjas gali atnaujinti šią informaciją."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Kūrėjas pateikė informacijos "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" apie duomenų bendrinimą šioje programoje. Bėgant laikui kūrėjas gali atnaujinti šią informaciją."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Ši programa gali bendrinti vietovės duomenis dėl:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Duomenų bendrinimas skiriasi"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Duomenų sauga"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Vietovės duomenys gali būti bendrinami"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Ši programa nurodė, kad gali bendrinti vietovės duomenis su trečiosiomis šalimis"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Šios nuorodos atidaryti nepavyko"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Duomenų bendrinimo atnaujinimai pagal vietovę"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Peržiūrėkite programas, kuriose pakeisti vietovės duomenų bendrinimo metodai"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Šiose programose pakeisti vietovės duomenų bendrinimo metodai Gali būti, kad anksčiau jie nebuvo bendrinami, arba dabar jie gali būti bendrinami reklamavimo ar rinkodaros tikslais."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Duomenų bendrinimo naujiniai"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Kai kuriose programose pakeisti vietovės duomenų bendrinimo metodai"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Nustatymai"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Pasiekta <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Pasiekta vakar <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Pasiekta <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-lv-v33/strings.xml b/PermissionController/res/values-lv-v33/strings.xml
index c935b9cee..825ac7aec 100644
--- a/PermissionController/res/values-lv-v33/strings.xml
+++ b/PermissionController/res/values-lv-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Citi brīdinājumi"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Noraidītie brīdinājumi"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Izvērsiet un skatiet vēl vienu brīdinājumu.}zero{Izvērsiet un skatiet vēl # brīdinājumus.}one{Izvērsiet un skatiet vēl # brīdinājumu.}other{Izvērsiet un skatiet vēl # brīdinājumus.}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Brīdinājums. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Darbība ir pabeigta"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Pārbaudiet iestatījumus, kas var uzlabot ierīces aizsardzību"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Drošības un konfidencialitātes ātrie iestatījumi"</string>
diff --git a/PermissionController/res/values-lv/strings.xml b/PermissionController/res/values-lv/strings.xml
index 90cb29e3b..cb4b274cc 100644
--- a/PermissionController/res/values-lv/strings.xml
+++ b/PermissionController/res/values-lv/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Informācija"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Atļaut visu"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Vienmēr atļaut visu"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Atļaut ierobežotu piekļuvi"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Atlasīt fotoattēlus un video"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Atlasīt citus"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Neatlasīt vairāk"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Lietotnes"</string>
<string name="app_permissions" msgid="3369917736607944781">"Lietotņu atļaujas"</string>
<string name="unused_apps" msgid="2058057455175955094">"Neizmantotās lietotnes"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Rediģēt fotoattēlu atlasi šai lietotnei"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nav neizmantotu lietotņu"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 neizmantotu lietotņu"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nesenās darbības ar atļaujām"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Visas atļaujas"</string>
<string name="other_permissions" msgid="2901186127193849594">"Citas lietotnes atļaujas"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Atļaujas pieprasījums"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear ierīcē netiek atbalstīta instalēšana/atinstalēšana"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Izvēlieties, kādas piekļuves atļaujas piešķirt lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Lietotne &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ir atjaunināta. Izvēlieties, kādas piekļuves atļaujas tai piešķirt."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Atcelt"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Noņemt atļaujas, ja lietotne netiek izmantota"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Noņemt atļaujas un atbrīvot vietu"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Apturēt lietotni, ja tā netiek izmantota"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Pārvaldīt lietotni, ja tā netiek lietota"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Atsaukt atļaujas, dzēst pagaidu failus un izslēgt paziņojumus"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Noņemt atļaujas, dzēst pagaidu failus, apturēt paziņojumus un arhivēt lietotni"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Ja lietotni dažus mēnešus neizmantosiet, tai tiks noņemtas tālāk norādītās atļaujas, lai aizsargātu jūsu datus."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Ja lietotni dažus mēnešus neizmantosiet, tai tiks noņemtas tālāk norādītās atļaujas, lai aizsargātu jūsu datus: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Lai aizsargātu jūsu datus, tika atsauktas atļaujas tām lietotnēm, kas nav izmantotas vairākus mēnešus."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Piezīmju lietotne"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Lietotnes, kas ļauj ierīcē veikt piezīmes"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"piezīmes"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Pašreizējais noklusējums"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Nejautāt atkārtoti"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Iest. kā noklusējumu"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Rādīt asistenta aktivizētāja noteikšanu"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Rādīt ikonu statusa joslā, kad mikrofons tiek izmantots balss palīga aktivizēšanai"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt fotoattēliem un multivides saturam jūsu ierīcē?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt fotoattēliem un multivides saturam jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt jūsu kontaktpersonām?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt kontaktpersonām jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt šīs ierīces atrašanās vietai?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt jūsu ierīces (&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;) atrašanās vietai?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Lietotne varēs piekļūt atrašanās vietai tikai tad, kad izmantosiet šo lietotni"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt šīs ierīces atrašanās vietai?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt jūsu ierīces (&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) atrašanās vietai?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Iespējams, šī lietotne vēlēsies piekļūt jūsu atrašanās vietai vienmēr, pat ja neizmantojat lietotni. "<annotation id="link">"Atļauju varat piešķirt iestatījumos"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Vai mainīt lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļuvi atrašanās vietai?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Vai mainīt atrašanās vietas piekļuves atļauju lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Šī lietotne vēlas piekļūt jūsu atrašanās vietai vienmēr, pat ja neizmantojat lietotni. "<annotation id="link">"Atļauju varat piešķirt iestatījumos"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Vai atļaut &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; atrast tuvumā esošas ierīces, veidot savienojumus ar tām un noteikt to relatīvo atrašanās vietu?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) atrast tuvumā esošas ierīces, veidot savienojumus ar tām un noteikt to relatīvo atrašanās vietu?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Vai atļaut &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; atrast tuvumā esošas ierīces, veidot savienojumus ar tām un noteikt to relatīvo atrašanās vietu? "<annotation id="link">"Varat to atļaut iestatījumos."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Vai mainīt lietotnes <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> piekļuvi atrašanās vietai no aptuvenās uz precīzo?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Vai mainīt lietotnes <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> atrašanās vietas piekļuves atļauju jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) no aptuvenas uz precīzu?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt aptuvenai šīs ierīces atrašanās vietai?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt jūsu ierīces (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;) aptuvenajai atrašanās vietai?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Precīza"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aptuvena"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt jūsu kalendāram?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt kalendāram jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sūtīt un skatīt īsziņas?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sūtīt un skatīt īsziņas jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt fotoattēliem, multivides saturam un failiem jūsu ierīcē?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt fotoattēliem, multivides saturam un failiem jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt &lt;b&gt;foto, video, mūzikai un audio failiem&lt;/b&gt; šajā ierīcē?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt &lt;b&gt;foto, video, mūzikai, audio u.c. failiem&lt;/b&gt; ierīcē?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt mūzikai un audio failiem šajā ierīcē?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt mūzikai un audio jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt fotoattēliem un video šajā ierīcē?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt fotoattēliem un video jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt citiem fotoattēliem un video šajā ierīcē?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt citiem fotoattēliem un video jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ierakstīt audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ierakstīt audio jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Lietotne varēs ierakstīt audio tikai tad, kad izmantosiet lietotni."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ierakstīt audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ierakstīt audio jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Iespējams, šī lietotne vēlēsies ierakstīt audio vienmēr, pat ja neizmantojat lietotni. "<annotation id="link">"Atļauju varat piešķirt iestatījumos."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Vai mainīt lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļuvi mikrofonam?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Vai mainīt mikrofona piekļuves atļauju lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Šī lietotne vēlas ierakstīt audio vienmēr, pat ja neizmantojat lietotni. "<annotation id="link">"Atļauju varat piešķirt iestatījumos."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt jūsu fiziskajām aktivitātēm?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt fizisko aktivitāšu datiem jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uzņemt fotoattēlus un ierakstīt videoklipus?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uzņemt attēlus un ierakstīt video jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Lietotne varēs uzņemt attēlus un ierakstīt videoklipus tikai tad, kad izmantosiet lietotni."</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uzņemt fotoattēlus un ierakstīt videoklipus?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uzņemt attēlus un ierakstīt video jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Iespējams, šī lietotne vēlēsies uzņemt attēlus un ierakstīt videoklipus vienmēr, pat ja neizmantojat lietotni. "<annotation id="link">"Atļauju varat piešķirt iestatījumos."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Vai mainīt lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļuvi kamerai?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Vai mainīt kameras piekļuves atļauju lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Šī lietotne vēlas uzņemt attēlus un ierakstīt videoklipus vienmēr, pat ja neizmantojat lietotni. "<annotation id="link">"Atļauju varat piešķirt iestatījumos."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt jūsu tālruņa zvanu žurnāliem?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt tālruņa zvanu žurnāliem jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; veikt un pārvaldīt tālruņa zvanus?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; veikt un pārvaldīt tālruņa zvanus jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt sensoru uztvertajiem veselības rādījumiem?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt sensoru datiem par veselības rādījumiem jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Lietotne pieprasa atļauju piekļūt veselības rādījumu sensoru datiem vienmēr, pat ja neizmantojat lietotni. Lai veiktu šīs izmaiņas, "<annotation id="link">"pārejiet uz iestatījumiem"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt veselības rādītāju sensoru datiem?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt sensoru datiem par veselības rādījumiem jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Lai atļautu šai lietotnei piekļūt ķermeņa sensoru datiem vienmēr (pat tad, kad neizmantojat lietotni), "<annotation id="link">"pārejiet uz iestatījumiem"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Vai joprojām atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt ķermeņa sensoru datiem, kad izmantojat lietotni?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Vai joprojām atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; piekļūt ķermeņa sensoru datiem jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;), kad izmantojat lietotni?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sūtīt jums paziņojumus?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Vai atļaut lietotnei &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nosūtīt jums paziņojumus jūsu ierīcē (&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;)?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontrolētās atļaujas"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> ir piekļuve atrašanās vietai"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Jūsu organizācija ļauj lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> piekļūt jūsu atrašanās vietai."</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Citas atļaujas"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Sistēmas izmantotās atļaujas"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Atļaujas, kas tiek izmantotas tikai sistēmas lietojumprogrammās."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Lietotne norādīja, ka tā var kopīgot atrašanās vietas datus ar trešajām pusēm."</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Datu kopīgošana un atrašanās vieta"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Datu kopīgošanas informācijas avots"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Izstrādātājs sniedza ierīces ražotājam informāciju par to, kā šajā lietotnē tiek kopīgoti dati. Laika gaitā izstrādātājs var šo informāciju atjaunināt."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Izstrādātājs sniedza lietotņu veikalam "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" informāciju par to, kā šajā lietotnē tiek kopīgoti dati. Laika gaitā izstrādātājs var šo informāciju atjaunināt."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Atrašanās vietas datu kopīgošanas nolūki lietotnē"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datu kopīgošana var atšķirties"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Datu drošība"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Atrašanās vietas dati var tikt kopīgoti"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Lietotne norādīja, ka tā var kopīgot atrašanās vietas datus ar trešajām pusēm."</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Nevar atvērt šo saiti"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Atjauninājumi atrašanās vietas datu kopīgošanā"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Pārskatiet lietotnes, kurās ir mainīti atrašanās vietas datu kopīgošanas veidi."</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Šajās lietotnēs ir mainīti atrašanās vietas datu kopīgošanas veidi. Varbūt tās iepriekš nekopīgoja šādus datus, bet varbūt tagad tos kopīgo reklamēšanas vai mārketinga nolūkos."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Datu kopīgošanas atjauninājumi"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Dažās lietotnēs tika mainīti atrašanās vietas datu kopīgošanas veidi."</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Iestatījumi"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Pēdējā piekļuves reize: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Pēdējā piekļuves reize vakar: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Pēdējā piekļuves reize: <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-mk-v33/strings.xml b/PermissionController/res/values-mk-v33/strings.xml
index deb8f25e7..95896fb8e 100644
--- a/PermissionController/res/values-mk-v33/strings.xml
+++ b/PermissionController/res/values-mk-v33/strings.xml
@@ -30,10 +30,9 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Повеќе предупредувања"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Отфрлени известувања"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Проширете и видете уште едно предупредување}one{Проширете и видете уште # предупредување}other{Проширете и видете уште # предупредувањa}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Предупредување. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Дејството е завршено"</string>
- <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Брзи поставки што може да додадат заштита на вашиот уред"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Прегледајте ги поставките со кои може дополнително да го заштитите уредот"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Брзи поставки за безбедност и приватност"</string>
<string name="safety_center_qs_close_button" msgid="1352313308176244599">"Затвори"</string>
<string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Прошири и прикажи ги опциите"</string>
diff --git a/PermissionController/res/values-mk-v34/strings.xml b/PermissionController/res/values-mk-v34/strings.xml
index d3483f90e..e8f9afc25 100644
--- a/PermissionController/res/values-mk-v34/strings.xml
+++ b/PermissionController/res/values-mk-v34/strings.xml
@@ -20,8 +20,8 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Безбедност и приватност"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Контроли"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Управувајте со пристапот на апликацијата до здравствените податоци"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Управувајте со пристапот на апликациите до здравствените податоци"</string>
<string name="location_settings" msgid="8863940440881290182">"Пристап до локацијата"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"За апликации и услуги. Ако поставкава е исклучена, податоците за микрофонот може сепак да се споделат кога ќе се јавите на број за итни случаи"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"За апликации и услуги. Ако поставкава е исклучена, податоците од микрофонот може сепак да се споделат кога ќе се јавите на број за итни случаи"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"За апликации и услуги"</string>
</resources>
diff --git a/PermissionController/res/values-mk/strings.xml b/PermissionController/res/values-mk/strings.xml
index ed2153549..2b633f026 100644
--- a/PermissionController/res/values-mk/strings.xml
+++ b/PermissionController/res/values-mk/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="6098036489833144040">"Permission controller"</string>
+ <string name="app_name" msgid="6098036489833144040">"Управувач со дозволи"</string>
<string name="ok" msgid="1936281769725676272">"Во ред"</string>
<string name="permission_search_keyword" msgid="1214451577494730543">"дозволи"</string>
<string name="cancel" msgid="8943320028373963831">"Откажи"</string>
@@ -32,9 +32,10 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Задржи ја „Додека се користи апликацијата“"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Задржи „Само овој пат“"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Уште информации"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Дозволи ги сите"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Дозволи за сите"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Секогаш дозволувај ги сите"</string>
- <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Изберете фотографии и видеа"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Дозволи ограничен пристап"</string>
+ <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Одредени фотографии и видеа"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Изберете повеќе"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Не избирајте повеќе"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Сепак не дозволувај"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Апликации"</string>
<string name="app_permissions" msgid="3369917736607944781">"Дозволи за апликации"</string>
<string name="unused_apps" msgid="2058057455175955094">"Некористени апликации"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Изберете ги фотографиите до кои ќе има пристап апликацијава"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Нема некористени апликации"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 некористени апликации"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Неодамнешни одлуки за дозволи"</string>
@@ -84,7 +86,7 @@
<string name="app_permissions_group_summary" msgid="8788419008958284002">"Апликации со дозвола: <xliff:g id="COUNT_0">%1$d</xliff:g> од <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
<string name="app_permissions_group_summary2" msgid="4329922444840521150">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g> дозволени апликации"</string>
<string name="menu_show_system" msgid="4254021607027872504">"Прикажи го системот"</string>
- <string name="menu_hide_system" msgid="3855390843744028465">"Сокриј го системот"</string>
+ <string name="menu_hide_system" msgid="3855390843744028465">"Скриј го системот"</string>
<string name="menu_show_7_days_data" msgid="8979611198508523706">"Прикажи 7 дена"</string>
<string name="menu_show_24_hours_data" msgid="8228054833323380780">"Прикажи 24 часа"</string>
<string name="manage_permission" msgid="2895385393037061964">"Управувајте со дозволата"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Сите дозволи"</string>
<string name="other_permissions" msgid="2901186127193849594">"Други можности на апликацијата"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Барање за дозвола"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Дејствата „Инсталирај/деинсталирај“ не се поддржани на Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Изберете до што може да пристапува &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; е ажурирана. Изберете до што може да пристапува апликацијава."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Откажи"</string>
@@ -129,7 +129,7 @@
<string name="permission_group_usage_title" msgid="2595013198075285173">"Користење <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Видете други дозволи"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
- <string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> и уште <xliff:g id="NUM">%3$s</xliff:g> други"</string>
+ <string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> и уште <xliff:g id="NUM">%3$s</xliff:g>"</string>
<string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"Кога ја користеле апликациите дозволата за <xliff:g id="PERMGROUP">%1$s</xliff:g> во минатите 24 часа"</string>
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Кога ја користеле апликациите дозволата за <xliff:g id="PERMGROUP">%1$s</xliff:g> во минатите 7 дена"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Кога апликацијава ја користела дозволата за <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Отстрани ги дозволите ако апликацијата не се користи"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Отстранувај дозволи и ослободувај простор"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Паузирај некористени апликации"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Управува со апликацијата при некористење"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Отстранува дозволи, брише привремени датотеки и запира известувања"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Отстранува дозволи, брише привремени датотеки, сопира известувања и ја архивира апликацијата"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"За да се заштитат вашите податоци, дозволите за апликацијава ќе се отстранат ако апликацијата не се користи неколку месеци."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Ако апликацијата не се користи неколку месеци, заради заштита на податоците, ќе се отстранат следниве дозволи: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"За заштита на податоците, отстранети се дозволите од апликациите што не сте ги користеле неколку месеци."</string>
@@ -219,7 +221,7 @@
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Дозволите за „<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g>“ и „<xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>“ се отстранети"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Дозволата за „<xliff:g id="PERMISSION_NAME">%1$s</xliff:g>“ и уште <xliff:g id="NUMBER">%2$s</xliff:g> други дозволи се отстранети"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Некористени апликации"</string>
- <string name="unused_apps_page_summary" msgid="1867593913217272155">"Ако некоја апликација не се користи неколку месеци:\n\n• дозволите се отстрануваат за да се заштитат вашите податоци\n• известувањата се стопираат за да се заштеди батерија\n• привремените датотеки се отстрануваат за да се ослободи простор\n\nЗа да повторно се овозможат дозволите и известувањата, отворете ја апликацијата."</string>
+ <string name="unused_apps_page_summary" msgid="1867593913217272155">"Ако некоја апликација не се користи неколку месеци:\n\n• дозволите се отстрануваат за да се заштитат вашите податоци\n• известувањата се стопираат за да се заштеди батерија\n• привремените датотеки се отстрануваат за да се ослободи простор\n\nЗа повторно да се овозможат дозволите и известувањата, отворете ја апликацијата."</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ако некоја апликација не се користи еден месец:\n\n• дозволите се отстрануваат за да се заштитат вашите податоци\n• привремените датотеки се отстрануваат за да се ослободи простор\n\nЗа да ги овозможите дозволите повторно, отворете ја апликацијата."</string>
<string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Последно отворени пред повеќе од # месец}one{Последно отворени пред повеќе од # месец}other{Последно отворени пред повеќе од # месеци}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Последно отворање на апликацијата: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -273,7 +275,7 @@
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Додека возевте, дадовте пристап на <xliff:g id="APP">%1$s</xliff:g> за <xliff:g id="PERMISSION_1">%2$s</xliff:g> и <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_multi_permission" msgid="4080701771111456927">"Додека возевте, дадовте <xliff:g id="COUNT">%1$d</xliff:g> дозволи на <xliff:g id="APP">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_multi_apps" msgid="5253882771252863902">"{count,plural, =1{Додека возевте, дадовте пристап на <xliff:g id="APP_0">%1$s</xliff:g> и # друга апликација}one{Додека возевте, дадовте пристап на <xliff:g id="APP_1">%1$s</xliff:g> и # друга апликација}other{Додека возевте, дадовте пристап на <xliff:g id="APP_1">%1$s</xliff:g> и # други апликации}}"</string>
- <string name="go_to_settings" msgid="1053735612211228335">"Одете во „Поставки“"</string>
+ <string name="go_to_settings" msgid="1053735612211228335">"Отворете „Поставки“"</string>
<string name="auto_revoke_setting_subtitle" msgid="8631720570723050460">"Некои апликации не се користени неколку месеци"</string>
<string name="permissions_removed_category_title" msgid="1064754271178447643">"Одземени дозволи"</string>
<string name="permission_removed_page_title" msgid="2627436155091001209">"Отстранети дозволи"</string>
@@ -306,7 +308,7 @@
<string name="unused_apps_subtitle_after" msgid="2034267519506357898">"Дозволите се отстранети од"</string>
<string name="unused_apps_subtitle_before" msgid="5233302577076132427">"Дозволите ќе се отстранат од"</string>
<string name="unused_permissions_subtitle_two" msgid="2207266295008423015">"<xliff:g id="PERM_NAME_0">%1$s</xliff:g> и <xliff:g id="PERM_NAME_1">%2$s</xliff:g>"</string>
- <string name="unused_permissions_subtitle_many" msgid="4387289202207450238">"<xliff:g id="PERM_NAME_0">%1$s</xliff:g>, <xliff:g id="PERM_NAME_1">%2$s</xliff:g> и уште <xliff:g id="NUMBER_OF_PERMISSIONS">%3$s</xliff:g> други"</string>
+ <string name="unused_permissions_subtitle_many" msgid="4387289202207450238">"<xliff:g id="PERM_NAME_0">%1$s</xliff:g>, <xliff:g id="PERM_NAME_1">%2$s</xliff:g> и уште <xliff:g id="NUMBER_OF_PERMISSIONS">%3$s</xliff:g>"</string>
<string name="unused_app_permissions_removed_summary" msgid="6779039455326071033">"За заштита на податоците, отстранети се дозволите од апликациите што не сте ги користеле неколку месеци"</string>
<string name="unused_app_permissions_removed_summary_some" msgid="5080490037831563441">"За заштита на податоците, отстранети се дозволите од некои апликации што не сте ги користеле неколку месеци."</string>
<string name="one_unused_app_summary" msgid="7831913934488881991">"1 апликација не е користена неколку месеци"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Апликација за белешки"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Апликации што ви овозможуваат да запишувате белешки на вашиот уред"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"белешки"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Стандардна апликација сега"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Не прашувај повторно"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Нека биде стандардна"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Прикажувај го откривањето за активирање на помошникот"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Прикажувај икона во статусната лента кога микрофонот се користи за активирање на гласовниот помошник"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до фотографии и аудиовизуелни содржини на уредот?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до фотогр. и аудиовизуелните содржини на вашиот &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до контактите на вашиот &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"Да се дозволи &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Да се дозволи &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>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Апликацијава можеби ќе сака да пристапува до вашата локација цело време, дури и кога не ја користите. "<annotation id="link">"Дозволете во поставките."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Да се промени пристапот до локацијата за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Да се промени пристапот до локацијата за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Апликацијава сака да пристапува до вашата локација цело време, дури и кога не ја користите. "<annotation id="link">"Дозволете во поставките."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да наоѓа и да се поврзува со уреди во близина и да ја утврдува нивната релативна положба?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Да се доз. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да ги наоѓа, да се поврзува со и да ја утврдува рел. позиција на уредите во близ. на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да наоѓа и да се поврзува со уреди во близина и да ја утврдува нивната релативна положба? "<annotation id="link">"Дозволете во „Поставки“."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Да се промени пристапот до локацијата на <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> од приближна на прецизна?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Да се промени пристапот до локацијата на <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до приближната локација на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до календарот на вашиот &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да испраќа и прегледува SMS-пораки на вашиот &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до фотогр., аудиовизуел. содржини и датотеките на lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до &lt;b&gt;фотографии, видеа, музика и аудио&lt;/b&gt; на уредов?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до &lt;b&gt;фотографии, видеа, музика, аудио и други датотеки&lt;/b&gt; на уредов?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до музика и аудиодатотеки на уредов?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до музиката и аудиото на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до фотографии и видеа на уредов?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до фотографиите и видеата на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до повеќе фотографии и видеа на уредов?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до повеќе фотографии и видеа на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да снима аудио?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да снима аудио на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Апликацијава ќе може да снима аудио само додека ја користите"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да снима аудио?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да снима аудио на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Апликацијава можеби ќе сака да снима аудио цело време, дури и кога не ја користите. "<annotation id="link">"Дозволете во „Поставки“."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Да се промени пристапот до микрофонот за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Да се промени пристапот до микрофонот за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Апликацијава сака да снима аудио цело време, дури и кога не ја користите. "<annotation id="link">"Дозволете во „Поставки“."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Дозволувате ли &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до вашата физичка активност?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до физичката активност на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да фотографира и да снима видео?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да фотографира и да снима видео на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Апликацијава ќе може да снима слики и видеа само додека ја користите"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да фотографира и да снима видео?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да фотографира и да снима видео на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Апликацијава можеби ќе сака да снима слики и видеа цело време, дури и кога не ја користите. "<annotation id="link">"Дозволете во „Поставки“."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Да се промени пристапот до камерата за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Да се промени пристапот за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Апликацијава сака да снима слики и видеа цело време, дури и кога не ја користите. "<annotation id="link">"Дозволете во „Поставки“."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до евиденцијата на повици?"</string>
- <string name="permgrouprequest_phone" msgid="1829234136997316752">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да повикува и да управува со телефонските повици?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до евиденцијата на повици на телефонот на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_phone" msgid="1829234136997316752">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да упатува телефонски повици и да управува со нив?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да упатува и да управува со телефонските повици на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до податоците на сензорот за витални знаци?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до податоците од сензорите за виталните знаци на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Апликацијава сака да пристапува до податоците од сензорите за вашите витални знаци цело време, дури и кога не се користи. За да го промените ова, "<annotation id="link">"одете во „Поставки“."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Дали да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до податоците од сензорите за витални знаци?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да пристапува до податоците од сензорите за виталните знаци на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"За да дозволите апликацијава да пристапува до податоци од телесните сензори цело време, дури и кога не ја користите, "<annotation id="link">"одете во „Поставки“."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"И понатаму да се дозволи пристап на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до податоци од телесните сензори додека се користи апликацијата?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Да се продолжи со дозв. прис. на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; до под. од тел. сенз. на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дури се користи апл.?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да ви испраќа известувања?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Да се дозволи &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; да ви испраќа известувања на вашиот &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Контролирани дозволи"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> има пристап до локацијата"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Вашата организација дозволува <xliff:g id="APP_NAME">%1$s</xliff:g> да пристапува до вашата локација"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Други дозволи"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Дозволи што ги користи системот"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Дозволи што ги користат само системските апликации."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Апликацијава изјави дека можеби ќе споделува податоци за локацијата со трети страни"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Споделување податоци и локација"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Од каде доаѓаат информациите за споделувањето податоци"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Програмерот доставил информации до производителот на уредов за начинот на кој апликацијава споделува податоци. Програмерот може да ги ажурира информацииве со текот на времето."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Програмерот доставил информации до "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" за начинот на кој апликацијава споделува податоци. Програмерот може да ги ажурира податоциве со текот на времето."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Апл. може да споделува податоци за локацијата за:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Споделувањето податоци варира"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Безбедност на податоците"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Можно е да се споделуваат податоците за локација"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Апликацијава наведе дека можеби ќе ги споделува вашите податоци за локацијата со трети страни"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Не може да се отвори линков"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Промени во споделувањето на податоците за локација"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Прегледајте ги апликациите што го промениле начинот на кој може да ги споделуваат вашите податоци за локација"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Овие апликации го промениле начинот на кој може да ги споделуваат вашите податоци за локација. Претходно можеби не ги споделувале или можеби сега ги споделуваат во рекламни или маркетиншки цели."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Промени во споделувањето податоци"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Некои апликации го сменија начинот на кој ја споделуваат вашата локација"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Поставки"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Пристапено: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Пристапено вчера: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Пристапено: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-ml/strings.xml b/PermissionController/res/values-ml/strings.xml
index 581ff9938..68fb04698 100644
--- a/PermissionController/res/values-ml/strings.xml
+++ b/PermissionController/res/values-ml/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"കൂടുതൽ വിവരങ്ങൾ"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"എല്ലാം അനുവദിക്കുക"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"എപ്പോഴും എല്ലാം അനുവദിക്കുക"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"പരിമിതമായ ആക്‌സസ് അനുവദിക്കുക"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ഫോട്ടോകളും വീഡിയോകളും തിരഞ്ഞെടുക്കുക"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"കൂടുതൽ തിരഞ്ഞെടുക്കുക"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"കൂടുതൽ തിരഞ്ഞെടുക്കരുത്"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ആപ്പുകൾ"</string>
<string name="app_permissions" msgid="3369917736607944781">"ആപ്പ് അനുമതികൾ"</string>
<string name="unused_apps" msgid="2058057455175955094">"ഉപയോഗിക്കാത്ത ആപ്പുകൾ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ഈ ആപ്പിനായി തിരഞ്ഞെടുത്ത ഫോട്ടോകൾ എഡിറ്റ് ചെയ്യുക"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ഉപയോഗിക്കാത്ത ആപ്പുകൾ ഇല്ല"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"ഉപയോഗിക്കാത്ത 0 ആപ്പുകൾ"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"സമീപകാല അനുമതി തീരുമാനങ്ങൾ"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"എല്ലാ അനുമതികളും"</string>
<string name="other_permissions" msgid="2901186127193849594">"മറ്റ് ആപ്പ് ശേഷികൾ"</string>
<string name="permission_request_title" msgid="8790310151025020126">"അനുമതി അഭ്യർത്ഥന"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"ഇൻസ്‌റ്റാൾ/അൺഇൻസ്‌റ്റാൾ ചെയ്യുന്നതിന് Wear-ൽ പിന്തുണയില്ല."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"എന്തൊക്കെ ആക്‌സസ് ചെയ്യാനാണ് &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കേണ്ടതെന്ന് തിരഞ്ഞെടുക്കുക"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; അപ്‌ഡേറ്റ് ചെയ്‌തിരിക്കുന്നു. എന്തൊക്കെ ആക്‌സസ് ചെയ്യാൻ ഈ ആപ്പിനെ അനുവദിക്കണമെന്ന് തിരഞ്ഞെടുക്കുക."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"റദ്ദാക്കുക"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ഉപയോഗിക്കാത്ത ആപ്പാണെങ്കിൽ അനുമതികൾ നീക്കം ചെയ്യുക"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"അനുമതികൾ നീക്കം ചെയ്‌ത് ഇടം സൃഷ്‌ടിക്കുക"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"ഉപയോഗിച്ചിട്ടില്ലെങ്കിൽ ആപ്പ് ആക്റ്റിവിറ്റി പോസ് ചെയ്യുക"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ഉപയോഗിക്കാത്തപ്പോൾ ആപ്പ് മാനേജ് ചെയ്യൂ"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"അനുമതികൾ നീക്കം ചെയ്യുക, താൽക്കാലിക ഫയലുകൾ ഇല്ലാതാക്കുക, അറിയിപ്പുകൾ നിർത്തുക"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"അനുമതികൾ നീക്കം ചെയ്യുക, താൽക്കാലിക ഫയലുകൾ ഇല്ലാതാക്കുക, അറിയിപ്പുകൾ നിർത്തുക, ആപ്പ് ആർക്കൈവ് ചെയ്യുക"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"മാസങ്ങളായി ഈ ആപ്പ് ഉപയോഗിക്കുന്നില്ലെങ്കിൽ നിങ്ങളുടെ ഡാറ്റ സംരക്ഷിക്കുന്നതിന്, ഈ ആപ്പിനുള്ള അനുമതികൾ നീക്കം ചെയ്യുന്നതായിരിക്കും."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"കുറച്ച് മാസം ആപ്പ് ഉപയോഗിച്ചില്ലെങ്കിൽ, നിങ്ങളുടെ ഡാറ്റ സംരക്ഷിക്കുന്നതിന്, ഇനിപ്പറയുന്ന അനുമതികൾ നീക്കം ചെയ്യുന്നതായിരിക്കും: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"നിങ്ങളുടെ ഡാറ്റ സംരക്ഷിക്കുന്നതിന്, കുറച്ച് മാസങ്ങളായി ഉപയോഗിക്കാത്ത ആപ്പുകളിൽ നിന്ന് അനുമതികൾ നീക്കം ചെയ്തിരിക്കുന്നു."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"കുറിപ്പ് ആപ്പ്"</string>
<string name="role_notes_description" msgid="8496852798616883551">"നിങ്ങളുടെ ഉപകരണത്തിൽ കുറിപ്പുകൾ രേഖപ്പെടുത്താൻ അനുവദിക്കുന്ന ആപ്പുകൾ"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"കുറിപ്പുകൾ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"നിലവിലെ ഡിഫോൾട്ട്"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"വീണ്ടും ആവശ്യപ്പെടരുത്"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ഡിഫോൾട്ടായി സജ്ജമാക്കൂ"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"അസിസ്‌റ്റന്റ് ട്രിഗർ കണ്ടെത്തൽ കാണിക്കുക"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"ശബ്‌ദ സഹായം സജീവമാക്കാൻ മൈക്രോഫോൺ ഉപയോഗിക്കുമ്പോൾ സ്റ്റാറ്റസ് ബാറിൽ ഐക്കൺ കാണിക്കുക"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"നിങ്ങളുടെ ഉപകരണത്തിലെ ഫോട്ടോകളും മീഡിയയും ഫയലുകളും ആക്‌സസ് ചെയ്യാൻ &lt;b&gt; <xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="DEVICE">%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_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="2270563860206654757">"&lt;b&gt;<xliff:g id="DEVICE">%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_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="6641436550953715107">"നിങ്ങളുടെ &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="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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്നതിന്റെ ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ആപ്പ് ഉപയോഗിക്കാത്തപ്പോൾ പോലും, എല്ലാ സമയത്തും ഈ ആപ്പിന് നിങ്ങളുടെ ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യേണ്ടതുണ്ട്. "<annotation id="link">"ക്രമീകരണത്തിൽ"</annotation>" അനുവദിക്കുക."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിന്റെ ലൊക്കേഷൻ ആക്സസ് മാറ്റണോ?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"ആപ്പ് നിങ്ങൾ ഉപയോഗിക്കാത്തപ്പോഴടക്കം, എല്ലാ സമയത്തും ഈ ആപ്പ് നിങ്ങളുടെ ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യാൻ ആഗ്രഹിക്കുന്നു. "<annotation id="link">"ക്രമീകരണത്തിൽ അനുവദിക്കുക."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"സമീപത്തെ ഉപകരണങ്ങൾ കണ്ടെത്താനും കണക്റ്റ് ചെയ്യാനും ആപേക്ഷിക സ്ഥാനം നിർണ്ണയിക്കാനും &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"സമീപത്തെ ഉപകരണങ്ങൾ കണ്ടെത്തി കണക്റ്റ് ചെയ്ത് ആപേക്ഷിക സ്ഥാനം നിർണ്ണയിക്കാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ? "<annotation id="link">"ക്രമീകരണത്തിൽ അനുവദിക്കുക."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> എന്നതിന്റെ ലൊക്കേഷൻ ആക്‌സസ് \'ഏകദേശം\' എന്നതിൽ നിന്ന് \'കൃത്യമായത്\' എന്നതിലേക്ക് മാറ്റണോ?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; എന്നതിൽ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ആപ്പിന്റെ ലൊക്കേഷൻ ആക്‌സസ്, ഏകദേശം എന്നതിൽ നിന്ന് കൃത്യം എന്നതായി മാറ്റണോ?"</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="9001956706241104626">"&lt;b&gt;<xliff:g id="DEVICE">%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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="DEVICE">%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>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; എന്നതിൽ SMS സന്ദേശങ്ങൾ അയയ്ക്കാനും കാണാനും &lt;b&gt;<xliff:g id="APP_NAME">%1$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="872629037299467086">"&lt;b&gt;<xliff:g id="DEVICE">%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_storage_q_to_s" msgid="8213701872983685505">"ഇതിലെ &lt;/b&gt;ഫോട്ടോകൾ, വീഡിയോ, സംഗീതം, ഓഡിയോ&lt;/b&gt; എന്നിവ ആക്സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;ഫോട്ടോ, വീഡിയോ, സംഗീതം, ഓഡിയോ, മറ്റ് ഫയലുകൾ&lt;/b&gt; എന്നിവയിലേക്ക് &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിന് ആക്സസ് നൽകണോ?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"ഈ ഉപകരണത്തിലെ സംഗീതവും ഓഡിയോയും ആക്സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%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_read_media_visual" msgid="5548780620779729975">"ഈ ഉപകരണത്തിലെ ഫോട്ടോകളും വീഡിയോകളും ആക്‌സസ് ചെയ്യാൻ &lt;b&gt; <xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="DEVICE">%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_more_photos" msgid="128933814654231321">"ഈ ഉപകരണത്തിലെ കൂടുതൽ ഫോട്ടോകളും വീഡിയോകളും ആക്‌സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="DEVICE">%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_microphone" msgid="2825208549114811299">"ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_microphone" msgid="8510456971528228861">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കുമ്പോൾ മാത്രമേ അതിന് ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ കഴിയൂ"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കാത്തപ്പോൾ പോലും ഈ ആപ്പിന് എപ്പോഴും ഓഡിയോ റെക്കോർഡ് ചെയ്യേണ്ടതുണ്ട്. "<annotation id="link">"ക്രമീകരണത്തിൽ അനുവദിക്കുക."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനുള്ള മൈക്രോഫോൺ ആക്സസ് മാറ്റണോ?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കാത്തപ്പോൾ പോലും ഈ ആപ്പിന് എപ്പോഴും ഓഡിയോ റെക്കോർഡ് ചെയ്യണം. "<annotation id="link">"ക്രമീകരണത്തിൽ അനുവദിക്കുക."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ നിങ്ങളുടെ കായിക പ്രവർത്തനം ആക്‌സസ് ചെയ്യാൻ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="DEVICE">%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_camera" msgid="5123097035410002594">"ചിത്രം എടുക്കാനും വീഡിയോ റെക്കോർഡ് ചെയ്യാനും &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_camera" msgid="9085323239764667883">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കുമ്പോൾ മാത്രമേ അതിന് ചിത്രങ്ങളെടുക്കാനും വീഡിയോ റെക്കോർഡ് ചെയ്യാൻ കഴിയൂ"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"ചിത്രം എടുക്കാനും വീഡിയോ റെക്കോർഡ് ചെയ്യാനും &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കാത്തപ്പോൾ പോലും, ഈ ആപ്പിന് വീഡിയോ റെക്കോർഡ് ചെയ്യുക, ചിത്രമെടുക്കുക എന്നിവ ചെയ്യേണ്ടതുണ്ട്. "<annotation id="link">"ക്രമീകരണത്തിൽ അനുവദിക്കുക."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനുള്ള ക്യാമറാ ആക്സസ് മാറ്റണോ?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കാത്തപ്പോൾ പോലും, ഈ ആപ്പിന് വീഡിയോ റെക്കോർഡ് ചെയ്യുക, ചിത്രമെടുക്കുക എന്നിവ ചെയ്യണം. "<annotation id="link">"ക്രമീകരണത്തിൽ അനുവദിക്കുക."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"നിങ്ങളുടെ ഫോൺ കോൾ ലോഗുകൾ ആക്സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="DEVICE">%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_phone" msgid="1829234136997316752">"ഫോൺ കോളുകൾ ചെയ്യാനും അവ മാനേജ് ചെയ്യാനും &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"നിങ്ങളുടെ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; എന്നതിൽ ഫോൺ കോളുകൾ ചെയ്യാനും അവ മാനേജ് ചെയ്യാനും <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ആപ്പിനെ അനുവദിക്കണോ?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"നിങ്ങളുടെ പ്രധാന ആരോഗ്യ വിവരങ്ങളുടെ സെൻസർ ഡാറ്റ ആക്‌സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"ആപ്പ് ഉപയോഗിക്കാത്തപ്പോൾ പോലും, നിങ്ങളുടെ പ്രധാന ആരോഗ്യ വിവര സൂചനകൾ സംബന്ധിച്ച സെൻസർ ഡാറ്റ ഈ ആപ്പിന് എപ്പോഴും ആക്‌സസ് ചെയ്യേണ്ടി വന്നേക്കാം. ഇത് മാറ്റാൻ, "<annotation id="link">"ക്രമീകരണത്തിലേക്ക് പോകുക"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"നിങ്ങളുടെ പ്രധാന ആരോഗ്യ വിവരങ്ങളുടെ സെൻസർ ഡാറ്റ ആക്സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കാത്ത സമയത്ത് ഉൾപ്പെടെ, എല്ലായ്‌പ്പോഴും ബോഡി സെൻസർ ഡാറ്റ ആക്‌സസ് ചെയ്യാൻ ഈ ആപ്പിനെ അനുവദിക്കുന്നതിന് "<annotation id="link">"ക്രമീകരണത്തിലേക്ക് പോകുക."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ആപ്പ് ഉപയോഗിക്കുമ്പോഴും ബോഡി സെൻസർ ഡാറ്റ ആക്‌സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കുന്നത് തുടരണോ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="DEVICE">%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_notifications" msgid="6396739062335106181">"നിങ്ങൾക്ക് അറിയിപ്പുകൾ അയയ്ക്കാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="DEVICE">%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="auto_granted_permissions" msgid="6009452264824455892">"നിയന്ത്രിത അനുമതികൾ"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിന് ലൊക്കേഷൻ ആക്‌സസ് ഉണ്ട്"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"നിങ്ങളുടെ ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യാൻ നിങ്ങളുടെ സ്ഥാപനം <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കുന്നു"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"മൂന്നാം കക്ഷികളുമായി ലൊക്കേഷൻ ഡാറ്റ പങ്കിട്ടേക്കാമെന്ന് ഈ ആപ്പ് പ്രസ്താവിക്കുന്നു"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ഡാറ്റ പങ്കിടലും ലൊക്കേഷനും"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ഡാറ്റ പങ്കിടുന്നതിനെ കുറിച്ചുള്ള വിവരങ്ങൾ ലഭിക്കുന്നത് എവിടെ നിന്നാണ്"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ഈ ആപ്പ് എങ്ങനെയാണ് ഡാറ്റ പങ്കിടുന്നത് എന്നതിനെ കുറിച്ചുള്ള വിവരങ്ങൾ ഡെവലപ്പർ ഈ ഉപകരണത്തിന്റെ നിർമ്മാതാവിന് നൽകിയിട്ടുണ്ട്. കാലക്രമേണ ഡെവലപ്പർ ഈ വിവരങ്ങൾ അപ്ഡേറ്റ് ചെയ്തേക്കാം."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ഈ ആപ്പ് എങ്ങനെയാണ് ഡാറ്റ പങ്കിടുന്നത് എന്നതിനെ കുറിച്ച് ഡെവലപ്പർ "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" എന്നതിൽ വിവരങ്ങൾ നൽകിയിട്ടുണ്ട്. കാലക്രമേണ ഡെവലപ്പർ ഈ വിവരങ്ങൾ അപ്ഡേറ്റ് ചെയ്തേക്കാം."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ഇവയ്ക്ക് ഈ ആപ്പ് ലൊക്കേഷൻ ഡാറ്റ പങ്കിട്ടേക്കാം:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ഡാറ്റ പങ്കിടുന്നത് വ്യത്യാസപ്പെടുന്നു"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ഡാറ്റാ സുരക്ഷ"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"ലൊക്കേഷൻ ഡാറ്റ പങ്കിട്ടേക്കാം"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"മൂന്നാം കക്ഷികളുമായി നിങ്ങളുടെ ലൊക്കേഷൻ ഡാറ്റ പങ്കിട്ടേക്കാമെന്ന് ഈ ആപ്പ് വ്യക്തമാക്കിയിട്ടുണ്ട്"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ഈ ലിങ്ക് തുറക്കാനാകുന്നില്ല"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"ലൊക്കേഷൻ ഡാറ്റ പങ്കിടുന്നതിനുള്ള അപ്‌ഡേറ്റുകൾ"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"നിങ്ങളുടെ ലൊക്കേഷൻ ഡാറ്റ പങ്കിടുന്ന രീതി മാറ്റിയ ആപ്പുകൾ അവലോകനം ചെയ്യുക"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"നിങ്ങളുടെ ലൊക്കേഷൻ ഡാറ്റ പങ്കിടുന്ന രീതി ഈ ആപ്പുകൾ മാറ്റി. അവ ഇത് മുമ്പ് പങ്കിട്ടിട്ടുണ്ടാകില്ല, അല്ലെങ്കിൽ ഇപ്പോൾ പരസ്യം ചെയ്യൽ, മാർക്കറ്റിംഗ് എന്നിവയുമായി ബന്ധപ്പെട്ട ആവശ്യങ്ങൾക്ക് പങ്കിട്ടേക്കാം."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ഡാറ്റ പങ്കിടുന്നത് സംബന്ധിച്ച അപ്‌ഡേറ്റുകൾ"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"നിങ്ങളുടെ ലൊക്കേഷൻ ഡാറ്റ പങ്കിടുന്ന രീതി ചില ആപ്പുകൾ മാറ്റി"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ക്രമീകരണം"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g>-ന് ആക്‌സസ് ചെയ്തു"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"ഇന്നലെ <xliff:g id="TIME_DATE">%1$s</xliff:g>-ന് ആക്‌സസ് ചെയ്തു"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>-ന് ആക്‌സസ് ചെയ്തു"</string>
</resources>
diff --git a/PermissionController/res/values-mn-v33/strings.xml b/PermissionController/res/values-mn-v33/strings.xml
index 1da8f5e62..327723433 100644
--- a/PermissionController/res/values-mn-v33/strings.xml
+++ b/PermissionController/res/values-mn-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Бусад сэрэмжлүүлэг"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Сэрэмжлүүлгийг хаасан"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Дэлгээд дахин нэг анхааруулга харах}other{Дэлгээд дахин # анхааруулга харах}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Сэрэмжлүүлэг. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Үйлдэл дууссан"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Таны төхөөрөмжид хамгаалалт нэмэх боломжтой тохиргоог шалгана уу"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Аюулгүй байдал болон нууцлалын шуурхай тохиргоо"</string>
diff --git a/PermissionController/res/values-mn/strings.xml b/PermissionController/res/values-mn/strings.xml
index c9448962e..477eb06e2 100644
--- a/PermissionController/res/values-mn/strings.xml
+++ b/PermissionController/res/values-mn/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Дэлгэрэнгүй мэдээлэл"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Бүгдийг зөвшөөрөх"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Бүгдийг үргэлж зөвшөөрөх"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Хязгаарлагдмал хандалтыг зөвшөөрөх"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Зураг болон видеонуудыг сонгох"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Илүү ихийг сонгох"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Нэмж өгөгдөл сонгохгүй"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Аппууд"</string>
<string name="app_permissions" msgid="3369917736607944781">"Аппын зөвшөөрөл"</string>
<string name="unused_apps" msgid="2058057455175955094">"Ашиглаагүй аппууд"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Энэ аппад сонгосон зургуудыг засна уу"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Ашиглаагүй апп байхгүй байна"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ашиглаагүй апп"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Саяхны зөвшөөрлийн шийдвэр"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Бүх зөвшөөрөл"</string>
<string name="other_permissions" msgid="2901186127193849594">"Аппын бусад чадамж"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Зөвшөөрлийн хүсэлт"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Андройд Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear-д суулгах/устгах үйлдлийг дэмждэггүй."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-н хандаж болох зүйлсийг сонгоно уу"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-г шинэчилсэн. Энэ аппын хандаж болох зүйлсийг сонгоно уу."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Цуцлах"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Аппыг ашигладаггүй бол зөвшөөрлийг нь хасах"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Зөвшөөрлийг хасаж, сул зай гаргах"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Ашиглаагүй бол аппын үйл ажиллагааг түр зогсоох"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Хэрэв ашиглаагүй бол аппыг удирдах"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Зөвшөөрлийг хасаж, түр зуурын файлыг устгаж мөн мэдэгдлийг зогсооно"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Зөвшөөрлийг хасаж, түр зуурын файлыг устгаж, мэдэгдлийг зогсоож мөн аппыг архивлана"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Таны өгөгдлийг хамгаалах үүднээс энэ аппыг хэдэн сарын турш ашиглахгүй бол зөвшөөрлийг нь хасах болно."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Таны өгөгдлийг хамгаалах үүднээс аппыг хэдэн сарын турш ашиглахгүй бол дараах зөвшөөрлүүдийг хасах болно: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Таны өгөгдлийг хамгаалах үүднээс таны хэдэн сарын турш ашиглаагүй аппуудын зөвшөөрлийг нь хассан."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Тэмдэглэлийн апп"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Таныг төхөөрөмж дээрээ тэмдэглэл хөтлөх боломж олгодог аппууд"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"тэмдэглэл"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Одоогийн өгөгдмөл апп"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Дахиж бүү асуу"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Өгөгдмөлөөр тохируулах"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Туслахын өдөөгч илрүүлэлтийг харуулах"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Дуут туслахыг идэвхжүүлэхийн тулд микрофоныг ашиглах үед статус самбарт дүрс тэмдэг харуулах"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д төхөөрөмжийнхөө зураг болон медиад хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>’s&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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>-н байршилд хандахыг зөвшөөрөх үү?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Энэ апп нь таныг апп ашиглаагүй байх үед ч таны байршилд үргэлж хандах хүcэлтэй байж болзошгүй. "<annotation id="link">"Тохиргоо хэсгээс зөвшөөрнө үү."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д зориулж байршлын хандалтыг өөрчлөх үү?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-н таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх байршлын хандалтыг өөрчлөх үү?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Энэ апп нь таныг апп ашиглаагүй байх үед ч таны байршилд үргэлж хандах хүcэлтэй байна. "<annotation id="link">"Тохиргоо хэсгээс зөвшөөрнө үү."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д ойр төхөөрөмжүүдийг илрүүлж, тэдгээрт холбогдож, харгалзах байршлыг нь тодорхойлохыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх ойролцоох төхөөрөмжүүдийн хамааралтай байршлыг олох, үүнд холбогдох болон үүнийг тодорхойлохыг зөвшөөрөх үү?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д ойр төхөөрөмжүүдийг илрүүлж, тэдгээрт холбогдож, харгалзах байршлыг нь тодорхойлохыг зөвшөөрөх үү? "<annotation id="link">"Тохиргоо хэсэгт зөвшөөрнө үү."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>-н байршлын хандалтыг барагцаалснаас нарийвчилсан болгож өөрчлөх үү?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>-н таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээр SMS мессеж илгээх болон харахыг зөвшөөрөх үү?"</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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх зураг, медиа болон файлд хандахыг зөвшөөрөх үү?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д энэ төхөөрөмж дээрх &lt;b&gt;зураг, видео, хөгжим болон аудионд&lt;/b&gt; хандахыг зөвшөөрөх үү?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д энэ төхөөрөмжийн &lt;b&gt;зураг, видео, хөгжим, аудио, бусад файлд&lt;/b&gt; хандахыг зөвшөөрөх үү?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д энэ төхөөрөмж дээрх хөгжим болон аудионд хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх хөгжим болон аудионд хандахыг зөвшөөрөх үү?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д энэ төхөөрөмж дээрх зураг болон видеонд хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх зураг болон видеонд хандахыг зөвшөөрөх үү?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д энэ төхөөрөмж дээрх бусад зураг болон видеонд хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх бусад зураг, видеонд хандахыг зөвшөөрөх үү?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д аудио бичихийг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээр аудио бичихийг зөвшөөрөх үү?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Энэ апп зөвхөн таныг ашиглаж байх үед л аудио бичих боломжтой болно"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д аудио бичихийг зөвшөөрөх үү?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээр аудио бичихийг зөвшөөрөх үү?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Та аппыг ашиглаагүй үед ч энэ апп үргэлж аудио бичихийг хүсэж болзошгүй. "<annotation id="link">"Тохиргоонд зөвшөөрнө үү."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-н микрофоны хандалтыг өөрчлөх үү?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-н таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх микрофоны хандалтыг өөрчлөх үү?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Та аппыг ашиглаагүй үед ч энэ апп үргэлж аудио бичихийг хүснэ. "<annotation id="link">"Тохиргоонд зөвшөөрнө үү."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны биеийн дасгал хөдөлгөөнд хандахыг зөвшөөрөх үү?"</string>
- <string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д зураг авах, видео хийхийг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх биеийн дасгал, хөдөлгөөнд хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д зураг авах, видео бичихийг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээр зураг авч, видео бичихийг зөвшөөрөх үү?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Энэ апп зөвхөн таныг ашиглаж байх үед л зураг авж, видео бичих боломжтой болно"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д зураг авах, видео бичихийг зөвшөөрөх үү?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээр зураг авч, видео бичихийг зөвшөөрөх үү?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Та аппыг ашиглаагүй үед ч энэ апп үргэлж зураг авж, видео бичихийг хүсэж болзошгүй. "<annotation id="link">"Тохиргоонд зөвшөөрнө үү."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-н камерын хандалтыг өөрчлөх үү?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-н таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх камерын хандалтыг өөрчлөх үү?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Та аппыг ашиглаагүй үед ч энэ апп үргэлж зураг авж, видео бичихийг хүснэ. "<annotation id="link">"Тохиргоонд зөвшөөрнө үү."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны утасны дуудлагын жагсаалтад хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх утасны дуудлагын жагсаалтад хандахыг зөвшөөрөх үү?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д утасны дуудлага хийх, дуудлага удирдахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээр утасны дуудлага хийх болон дуудлагыг удирдахыг зөвшөөрөх үү?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны биеийн ерөнхий байдлын үзүүлэлтүүдийн мэдрэгчийн өгөгдөлд хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх биеийн ерөнхий үзүүлэлтийн мэдрэгчийн өгөгдөлд хандахыг зөвшөөрөх үү?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Аппыг ашиглаагүй үед ч энэ нь таны биеийн ерөнхий байдлын үзүүлэлтүүдийн талаарх мэдрэгчийн өгөгдөлд үргэлж хандахыг хүсэж байна. Энэ өөрчлөлтийг хийхийн тулд "<annotation id="link">"тохиргоо руу очно уу."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны биеийн ерөнхий байдлын үзүүлэлтүүдийн талаарх мэдрэгчийн өгөгдөлд хандахыг зөвшөөрөх үү?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх биеийн ерөнхий үзүүлэлтийн мэдрэгчийн өгөгдөлд хандахыг зөвшөөрөх үү?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Та аппыг ашиглаагүй байсан ч ямар ч үед энэ аппын биеийн мэдрэгчийн өгөгдөлд хандахыг зөвшөөрөх бол "<annotation id="link">"тохиргоо руу очно уу."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Аппыг ашиглаж байх үедээ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-г биеийн мэдрэгчийн өгөгдөлд хандахыг үргэлжлүүлэн зөвшөөрөх үү?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Аппыг ашиглаж байх үед &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээрх биеийн мэдрэгчийн өгөгдөлд хандахыг үргэлжлүүлэн зөвшөөрөх үү?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-&lt;/b&gt;-д танд мэдэгдэл илгээхийг зөвшөөрөх үү?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-д таны &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; дээр мэдэгдэл илгээхийг зөвшөөрөх үү?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Хяналттай зөвшөөрөл"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> байршилд хандах эрхтэй байна"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Танай байгууллага <xliff:g id="APP_NAME">%1$s</xliff:g>-д байршилд тань хандахыг зөвшөөрдөг"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Бусад зөвшөөрөл"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Системийн ашигласан зөвшөөрөл"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Зөвхөн системийн аппликэйшний ашигласан зөвшөөрөл."</string>
@@ -533,7 +570,7 @@
<string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Аюулгүй байдал болон нууцлалын төлөв. <xliff:g id="OVERALL_SAFETY_STATUS">%1$s</xliff:g>. <xliff:g id="SUMMARY_OF_DEVICE_STATUS">%2$s</xliff:g>"</string>
<string name="security_settings" msgid="3808106921175271317">"Аюулгүй байдлын тохиргоо"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"Зөвшөөрөл"</string>
- <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Аюулгүй байдал &amp; нууцлал"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Аюулгүй байдал ба нууцлал"</string>
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Төлөвийг шалгах"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Таны нууцлалын тохиргоо"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Бусад тохиргоо"</string>
@@ -587,10 +624,11 @@
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Түр санах ойн хандалтыг харуулах"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Аппууд таны хуулсан текст, зураг эсвэл бусад контентод хандах үед мессеж харуулах"</string>
<string name="show_password_title" msgid="2877269286984684659">"Нууц үгнүүдийг харуулах"</string>
- <string name="show_password_summary" msgid="1110166488865981610">"Таныг бичиж явцад тэмдэгтүүдийг түр үзүүлэх"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Бичих явцад тэмдэгтийг товчхон харуулах"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Энэ апп байршлын өгөгдлийг гуравдагч талуудтай хуваалцаж болохыг мэдэгдсэн"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Өгөгдөл хуваалцах болон байршил"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Өгөгдөл хуваалцах мэдээллийг хаанаас авдаг вэ?"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Хөгжүүлэгч энэ төхөөрөмжийн үйлдвэрлэгчид уг апп хэрхэн өгөгдөл хуваалцдаг талаарх мэдээллийг өгсөн. Хөгжүүлэгч энэ мэдээллийг яваандаа шинэчилж магадгүй."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Хөгжүүлэгч энэ апп өгөгдөл хэрхэн хуваалцдаг талаарх мэдээллийг "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s-д"</annotation></annotation>" өгсөн. Хөгжүүлэгч энэ мэдээллийг цагийн аясаар шинэчилж магадгүй."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Апп байршлын өгөгдөл дараах зорилгоор хуваалцана:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Өгөгдөл хуваалцах нь ялгаатай"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Өгөгдлийн аюулгүй байдал"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Байршлын өгөгдлийг хуваалцаж магадгүй"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Энэ апп таны байршлын өгөгдлийг гуравдагч талуудтай хуваалцаж магадгүйг мэдэгдсэн"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Энэ холбоосыг нээх боломжгүй"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Байршлын өгөгдөл хуваалцах шинэчлэлтүүд"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Таны байршлын өгөгдлийг хуваалцдаг аргаа өөрчилсөн аппуудыг шалгана уу"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Эдгээр апп таны байршлын өгөгдлийг хуваалцдаг аргаа өөрчилсөн. Тэд үүнийг өмнө нь хуваалцаагүй байж магадгүй эсвэл одоо үүнийг сурталчилгаа, маркетингийн зорилгоор хуваалцаж болзошгүй."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Өгөгдөл хуваалцах тухай шинэчлэлт"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Зарим апп таны байршлын өгөгдлийг хуваалцдаг аргаа өөрчилсөн"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Тохиргоо"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g>-д хандсан"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Өчигдөр <xliff:g id="TIME_DATE">%1$s</xliff:g>-д хандсан"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>-д хандсан"</string>
</resources>
diff --git a/PermissionController/res/values-mr-v33/strings.xml b/PermissionController/res/values-mr-v33/strings.xml
index f9de83102..cea91a4b2 100644
--- a/PermissionController/res/values-mr-v33/strings.xml
+++ b/PermissionController/res/values-mr-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"आणखी सूचना"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"डिसमिस केलेल्या सूचना"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{विस्तार करा आणि आणखी एक सूचना पहा}other{विस्तार करा आणि आणखी # सूचना पहा}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"इशारा. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"कृती पूर्ण झाली आहे"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"तुमच्या डिव्हाइसला संरक्षण जोडू शकतील अशी सेटिंग्ज तपासा"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"सुरक्षा आणि गोपनीयता क्विक सेटिंग्ज"</string>
diff --git a/PermissionController/res/values-mr-v34/strings.xml b/PermissionController/res/values-mr-v34/strings.xml
index 1785fd7f2..8c9152379 100644
--- a/PermissionController/res/values-mr-v34/strings.xml
+++ b/PermissionController/res/values-mr-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"सुरक्षा आणि गोपनीयता"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"नियंत्रणे"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"आरोग्यविषयक डेटासंबंधित अ‍ॅपचा अ‍ॅक्सेस नियंत्रित करा"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"आरोग्यविषयक डेटासंबंधित अ‍ॅपचा अ‍ॅक्सेस व्यवस्थापित करा"</string>
<string name="location_settings" msgid="8863940440881290182">"स्थान अ‍ॅक्सेस"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"ॲप्स आणि सेवांसाठी. हे सेटिंग बंद असल्यास, तुम्ही आणीबाणी नंबरवर कॉल करता, तेव्हा मायक्रोफोन डेटा तरीही शेअर केला जाऊ शकतो"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"ॲप्स आणि सेवांसाठी"</string>
diff --git a/PermissionController/res/values-mr/strings.xml b/PermissionController/res/values-mr/strings.xml
index 1dfffc9d3..8e8eaa56b 100644
--- a/PermissionController/res/values-mr/strings.xml
+++ b/PermissionController/res/values-mr/strings.xml
@@ -20,7 +20,7 @@
<string name="ok" msgid="1936281769725676272">"ओके"</string>
<string name="permission_search_keyword" msgid="1214451577494730543">"परवानग्या"</string>
<string name="cancel" msgid="8943320028373963831">"रद्द करा"</string>
- <string name="back" msgid="6249950659061523680">"परत"</string>
+ <string name="back" msgid="6249950659061523680">"मागे जा"</string>
<string name="available" msgid="6007778121920339498">"उपलब्ध आहे"</string>
<string name="blocked" msgid="9195547604866033708">"ब्लॉक केला आहे"</string>
<string name="on" msgid="280241003226755921">"सुरू आहे"</string>
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"अधिक माहिती"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"सर्वांना अनुमती द्या"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"नेहमी सर्वांना अनुमती द्या"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"मर्यादित अ‍ॅक्सेसची अनुमती द्या"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"फोटो आणि व्हिडिओ निवडा"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"आणखी निवडा"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"आणखी निवडू नका"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"अ‍ॅप्स"</string>
<string name="app_permissions" msgid="3369917736607944781">"अ‍ॅप परवानग्या"</string>
<string name="unused_apps" msgid="2058057455175955094">"न वापरलेली अ‍ॅप्स"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"या अ‍ॅपसाठी निवडलेले फोटो संपादित करा"</string>
<string name="no_unused_apps" msgid="12809387670415295">"न वापरलेली कोणतीही ॲप्स नाहीत"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"न वापरलेली शून्य अ‍ॅप्स"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"अलीकडील परवानगीसंबंधित निर्णय"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"सर्व परवानग्या"</string>
<string name="other_permissions" msgid="2901186127193849594">"अन्य अ‍ॅप क्षमता"</string>
<string name="permission_request_title" msgid="8790310151025020126">"परवानगीची विनंती"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"इंस्टॉल करा/अनइंस्टॉल करा क्रिया Wear वर सपोर्ट करत नाहीत."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला काय अ‍ॅक्सेस करण्‍याची परवानगी द्यावी ते निवडा"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; अपडेट केले गेले आहे. या ॲपला काय अ‍ॅक्सेस करण्‍याची परवानगी द्यावी ते निवडा."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"रद्द करा"</string>
@@ -196,7 +196,7 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"अचूक स्थान वापरा"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"अचूक स्थान बंद असते, तेव्हा ॲप्स तुमचे अंदाजे स्थान अ‍ॅक्सेस करू शकतात"</string>
<string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g> परवानगी"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"या अ‍ॅपसाठी <xliff:g id="PERM">%1$s</xliff:g> चा अ‍ॅक्सेस द्या"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"या अ‍ॅपसाठी <xliff:g id="PERM">%1$s</xliff:g> अ‍ॅक्सेस द्या"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"सर्व <xliff:g id="APP">%1$s</xliff:g> परवानग्या पहा"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"ही परवानगी असलेली सर्व अ‍ॅप्स पहा"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Assistant ने मायक्रोफोनचा केलेला वापर दाखवा"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"अ‍ॅप वापरले नसल्यास, परवानग्या काढून टाका"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"परवानग्या काढा आणि जागा मोकळी करा"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"न वापरल्यास अ‍ॅप अ‍ॅक्टिव्हिटी थांबवा"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"वापरले नसल्यास ॲप व्यवस्थापित करा"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"परवानग्या काढून टाका, तात्पुरत्या फाइल हटवा आणि सूचना थांबवा"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"परवानग्या काढून टाका, तात्पुरत्या फाइल हटवा, सूचना थांबवा आणि ॲप संग्रहित करा"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"तुमच्या डेटाचे संरक्षण करण्यासाठी, अ‍ॅप काही महिन्यांत वापरले गेले नसल्यास, या अ‍ॅपच्या परवानग्या काढल्या जातील."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"तुमच्या डेटाचे संरक्षण करण्यासाठी, अ‍ॅप काही महिन्यांत वापरले गेले नसल्यास, पुढील परवानग्या काढल्या जातील: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"तुमच्या डेटाचे संरक्षण करण्यासाठी, तुम्ही काही महिन्यांत न वापरलेल्या ॲप्समधून परवानग्या काढल्या गेल्या आहेत."</string>
@@ -397,10 +399,20 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि कनेक्‍ट केलेल्या डिव्हाइसवर तुमची ॲप्स स्ट्रीम करण्याची अनुमती दिली जाईल."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"ही सेवा तुमचे फोटो, मीडिया आणि सूचना तुमच्या फोनवरून दुसऱ्या डिव्हाइसवर शेअर करते."</string>
- <string name="role_notes_label" msgid="7451627001058089536">"डीफॉल्ट टीपांचे अ‍ॅप"</string>
- <string name="role_notes_short_label" msgid="8796604147546125285">"टीपांचे अ‍ॅप"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"टिपांसाठी डीफॉल्ट अ‍ॅप"</string>
+ <string name="role_notes_short_label" msgid="8796604147546125285">"टिपांचे अ‍ॅप"</string>
<string name="role_notes_description" msgid="8496852798616883551">"तुमच्या डिव्हाइसवर तुम्हाला टिपा घेण्याची अनुमती देणारी अ‍ॅप्स"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"टिपा"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"सद्य डीफॉल्ट"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"पुन्हा विचारू नका"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"डीफॉल्ट सेट करा"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"असिस्टंट ट्रिगर डिटेक्शन दाखवा"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"व्हॉइस असिस्टंट अ‍ॅक्टिव्हेट करण्यासाठी मायक्रोफोन वापरला जाईल तेव्हा स्टेटस बारमध्ये आयकन दाखवा"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या डिव्हाइसवरील फोटो आणि मीडिया अ‍ॅक्सेस करू द्यायचा?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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> चे स्थान अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"तुम्ही अ‍ॅप वापरत नसतानादेखील कदाचित या ॲपला नेहमी तुमचे स्थान ॲक्सेस करायचे आहे."<annotation id="link">"सेटिंग्जमधून अनुमती द्या."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; चा स्थान ॲक्सेस बदलायचा आहे का?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"तुम्ही अ‍ॅप वापरत नसतानादेखील या ॲपला नेहमी तुमचे स्थान ॲक्सेस करायचे आहे. "<annotation id="link">"सेटिंग्जमधून अनुमती द्या."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला जवळील डिव्हाइस शोधण्याची, त्यांच्याशी कनेक्ट व त्यांचे संबंधित स्थान निर्धारित करण्याची अनुमती द्यायची का?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर जवळची डिव्हाइस शोधू, त्यांच्याशी कनेक्ट करू व त्यांचे संबंधित स्थान ठरवू द्यायचे?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला जवळील डिव्हाइस शोधण्याची, त्यांच्याशी कनेक्ट व त्यांचे संबंधित स्थान निर्धारित करण्याची अनुमती द्यायची का? "<annotation id="link">"सेटिंग्जमध्ये अनुमती द्या."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> च्या स्थानाचा अ‍ॅक्सेस अंदाजेवरून अचूकवर बदलायचा आहे का?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> च्या स्थानाचा अ‍ॅक्सेस अंदाजे यावरून अचूक यावर बदलायचा आहे का?"</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%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; ला एसएमएस पाठवू आणि पाहू द्यायचे?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर फोटो, मीडिया आणि व्हिडिओ अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला या डिव्हाइसवरील &lt;b&gt;फोटो, व्हिडिओ, संगीत आणि ऑडिओ&lt;/b&gt; अ‍ॅक्सेस करू द्यायचा आहे का?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला या डिव्हाइसवरील &lt;b&gt;फोटो, व्हिडिओ, संगीत, ऑडिओ व इतर फाइल&lt;/b&gt; अ‍ॅक्सेस करू द्यायच्या?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला या डिव्हाइसवरील संगीत आणि ऑडिओ अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर संगीत आणि ऑडिओ अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला या डिव्हाइसवरील फोटो आणि व्हिडिओ अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर फोटो आणि व्हिडिओ अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला या डिव्हाइसवरील अधिक फोटो आणि व्हिडिओ अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर आणखी फोटो आणि व्हिडिओ अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला ऑडिओ रेकॉर्ड करू द्यायचा?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर ऑडिओ रेकॉर्ड करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"ॲप फक्त तुम्ही ॲप वापरत असतानाच ऑडिओ रेकॉर्ड करू शकते"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला ऑडिओ रेकॉर्ड करायची अनुमती द्यायची?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर ऑडिओ रेकॉर्ड करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"हे ॲप तुम्ही ॲप वापरत नसतानादेखील ऑडिओ नेहमी रेकॉर्ड करू शकते. "<annotation id="link">"सेटिंग्जमध्ये अनुमती द्या."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; चा मायक्रोफोनचा ॲक्सेस बदलायचा?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"हे ॲप तुम्ही ॲप वापरत नसतानादेखील नेहमी ऑडिओ रेकॉर्ड करू शकते. "<annotation id="link">"सेटिंग्जमध्ये अनुमती द्या."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमची शारीरिक अ‍ॅक्टिव्हिटी अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर तुमची शारीरिक अ‍ॅक्टिव्हिटी अ‍ॅक्सेस करू द्यायची आहे का?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला फोटो काढू आणि व्हिडिओ रेकॉर्ड करू द्यायचे?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर फोटो घेण्याची आणि व्हिडिओ रेकॉर्ड करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"ॲप फक्त तुम्ही ॲप वापरत असतानाच फोटो काढू शकते आणि व्हिडिओ रेकॉर्ड करू शकते"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला फोटो काढायची आणि व्हिडिओ रेकॉर्ड करायची अनुमती द्यायची?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर फोटो घेण्याची आणि व्हिडिओ रेकॉर्ड करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"हे ॲप तुम्ही ॲप वापरत नसतानादेखील नेहमी फोटो काढू शकते आणि व्हिडिओ रेकॉर्ड करू शकते."<annotation id="link">"सेटिंग्जमध्ये अनुमती द्या."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; चा कॅमेऱ्याचा अ‍ॅक्सेस बदलायचा?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"हे ॲप तुम्ही ॲप वापरत नसतानादेखील नेहमी फोटो काढू शकते आणि व्हिडिओ रेकॉर्ड करू शकते. "<annotation id="link">"सेटिंग्जमध्ये अनुमती द्या."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमचे फोन कॉल लॉग अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर तुमच्या फोनचा कॉल लॉग अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला फोन कॉल करू आणि ते व्यवस्थापित करू द्यायचे?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर फोन कॉल करू आणि ते व्यवस्थापित करू द्यायचे आहेत का?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या महत्त्वाच्या लक्षणांविषयीचा सेन्सर डेटा अ‍ॅक्सेस करू द्यायचे?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर महत्त्वाच्या परिमाणांचा सेन्सर डेटा अ‍ॅक्सेस करू द्यायचा आहे का?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"तुम्ही अ‍ॅप वापरत नसतानादेखील या ॲपला तुमच्या महत्त्वाच्या परिमाणांबद्दलचा सेन्सर डेटा पूर्णवेळ ॲक्सेस करायचा आहे. हा बदल करण्यासाठी, "<annotation id="link">" सेटिंग्जवर जा."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या महत्त्वाच्या परिमाणांसंबंधित सेन्सर डेटा अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर महत्त्वाच्या परिमाणांचा सेन्सर डेटा अ‍ॅक्सेस करू द्यायचा आहे का?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"तुम्ही ॲप वापरत नसतानादेखील या ॲपला शरीर सेन्सर डेटा नेहमी अ‍ॅक्सेस करू देण्यासाठी, "<annotation id="link">"सेटिंग्जवर जा."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ॲप वापरात असताना &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला शरीर सेन्सर डेटा अ‍ॅक्सेस करण्याची अनुमती देणे सुरू ठेवायचे आहे का?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"ॲप वापरात असताना &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर महत्त्वाच्या परिमाणांचा सेन्सर डेटा अ‍ॅक्सेस करू देणे सुरू ठेवायचे?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुम्हाला सूचना पाठवू द्यायचे का?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ला तुमच्या &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; वर सूचना पाठवण्याची अनुमती द्यायची आहे का?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"नियंत्रित परवानग्या"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> कडे स्थान अ‍ॅक्सेस आहे"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"तुमची संस्था <xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमचे स्थान अ‍ॅक्सेस करण्याची अनुमती देते"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"इतर परवानग्या"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"सिस्टमद्वारे वापरल्या जाणाऱ्या परवानग्या"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"फक्त सिस्टम ॲप्लिकेशनद्वारे वापरल्या जाणाऱ्या परवानग्या."</string>
@@ -585,12 +622,13 @@
<string name="mic_toggle_description" msgid="9163104307990677157">"ॲप्स आणि सेवांसाठी. हे सेटिंग बंद असल्यास, तुम्ही आणीबाणी नंबरवर कॉल करता तेव्हा, मायक्रोफोन डेटा तरीही कदाचित शेअर केला जाईल."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"स्थानाचा अ‍ॅक्सेस असलेली अ‍ॅप्स आणि सेवा पहा"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"क्लिपबोर्डचा अ‍ॅक्सेस दाखवा"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"तुम्ही कॉपी केलेला मजकूर, इमेज किंवा इतर आशय ॲप्स अ‍ॅक्सेस करतात तेव्हा, मेसेज दाखवा"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"तुम्ही कॉपी केलेला मजकूर, इमेज किंवा इतर आशय ॲप्स अ‍ॅक्सेस करतात, तेव्हा मेसेज दाखवा"</string>
<string name="show_password_title" msgid="2877269286984684659">"पासवर्ड दाखवा"</string>
<string name="show_password_summary" msgid="1110166488865981610">"तुम्ही टाइप कराल त्‍याप्रमाणे वर्ण थोडक्‍यात डिस्प्ले करा"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"हे अ‍ॅप तृतीय पक्षांसोबत स्थान डेटा शेअर करू शकते असे या अ‍ॅपने नमूद केले आहे"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"डेटा शेअरिंग आणि स्थान"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"डेटा शेअरिंग माहिती कुठून मिळते"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"हे ॲप डेटा कसे शेअर करते याबद्दल डेव्हलपरने या डिव्हाइसच्या उत्पादकाला माहिती पुरवली आहे. डेव्हलपर कालांतराने ही माहिती अपडेट करू शकतो."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"हे अ‍ॅप डेटा कसे शेअर करते याबद्दल डेव्हलपरने "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" यांना माहिती पुरवली. डेव्हलपर कालांतराने ही माहिती अपडेट करू शकतो."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"अ‍ॅप पुढील गोष्टींसाठी स्‍थान डेटा शेअर करू शकते:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"डेटा शेअरिंग बदलते"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"डेटासंबंधित सुरक्षितता"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"स्‍थान डेटा शेअर केला जाऊ शकतो"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"हे अ‍ॅप तृतीय पक्षांसोबत तुमचा स्थान डेटा शेअर करू शकते असे या अ‍ॅपने नमूद केले आहे"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ही लिंक उघडू शकत नाही"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"स्थानासाठी डेटा शेअरिंगसंबंधित अपडेट"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ज्या अ‍ॅप्सनी तुमचा स्थान डेटा शेअर करण्याची त्यांची पद्धत बदलली अशा अ‍ॅप्सचे पुनरावलोकन करा"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"या अ‍ॅप्सनी तुमचा स्थान डेटा शेअर करण्याची त्यांची पद्धत बदलली आहे. त्यांनी तो पूर्वी शेअर केलेला नसू शकतो किंवा आता जाहिरात करणे अथवा मार्केटिंग उद्देशांसाठी शेअर करू शकतात."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"डेटा शेअरिंगचे अपडेट"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"काही अ‍ॅप्सनी तुमचा स्थान डेटा शेअर करण्याची त्यांची पद्धत बदलली"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"सेटिंग्ज"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g> वाजता ॲक्सेस केले"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"काल <xliff:g id="TIME_DATE">%1$s</xliff:g> वाजता ॲक्सेस केले"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> ला <xliff:g id="TIME_DATE_1">%2$s</xliff:g> वाजता ॲक्सेस केले"</string>
</resources>
diff --git a/PermissionController/res/values-ms-v33/strings.xml b/PermissionController/res/values-ms-v33/strings.xml
index 95643d003..d5540a429 100644
--- a/PermissionController/res/values-ms-v33/strings.xml
+++ b/PermissionController/res/values-ms-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Lagi makluman"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Makluman yang diketepikan"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Kembangkan dan lihat satu makluman lagi}other{Kembangkan dan lihat # makluman lagi}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Amaran. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Tindakan selesai"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Semak tetapan yang boleh menambah perlindungan pada peranti anda"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Tetapan pantas keselamatan dan privasi"</string>
diff --git a/PermissionController/res/values-ms/strings.xml b/PermissionController/res/values-ms/strings.xml
index f08513a18..0a4fe2d68 100644
--- a/PermissionController/res/values-ms/strings.xml
+++ b/PermissionController/res/values-ms/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Lagi maklumat"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Benarkan semua"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Sentiasa benarkan semua"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Benarkan akses terhad"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Pilih foto dan video"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Pilih lagi"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Jangan pilih lagi"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apl"</string>
<string name="app_permissions" msgid="3369917736607944781">"Kebenaran apl"</string>
<string name="unused_apps" msgid="2058057455175955094">"Apl yang tidak digunakan"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edit foto yang dipilih untuk apl ini"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Tiada apl yang tidak digunakan"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 apl yang tidak digunakan"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Keputusan kebenaran terbaharu"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Semua kebenaran"</string>
<string name="other_permissions" msgid="2901186127193849594">"Keupayaan apl lain"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Permintaan kebenaran"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Tindakan pasang/nyahpasang tidak disokong pada Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Pilih perkara yang boleh diakses oleh &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; telah dikemas kini. Pilih perkara yang boleh diakses oleh apl ini."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Batal"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Alih keluar kebenaran jika apl tidak digunakan"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Alih keluar kebenaran dan kosongkan ruang"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Jeda aktiviti apl jika tidak digunakan"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Urus apl jika tidak digunakan"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Alih keluar kebenaran, padamkan fail sementara dan hentikan pemberitahuan"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Alih keluar kebenaran, padamkan fail sementara, hentikan pemberitahuan dan arkibkan apl tersebut"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Untuk melindungi data anda, kebenaran apl ini akan dialih keluar jika apl tidak digunakan selama beberapa bulan."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Untuk melindungi data anda, jika apl tidak digunakan selama beberapa bulan, kebenaran berikut akan dialih keluar: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Untuk melindungi data anda, kebenaran telah dialih keluar daripada apl yang tidak anda gunakan selama beberapa bulan."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Apl nota"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apl yang membolehkan anda mengambil nota pada peranti anda"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"nota"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Lalai semasa"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Jangan tanya lagi"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Tetapkan sbg lalai"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Tunjukkan pengesanan cetusan pembantu"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Tunjukkan ikon dalam bar status apabila mikrofon digunakan untuk mengaktifkan pembantu suara"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan media pada peranti anda?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan media pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses kenalan anda?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses kenalan anda pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi peranti ini?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>s&lt;/b&gt; anda?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Apl ini hanya dapat mengakses lokasi semasa anda menggunakan apl tersebut"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi peranti ini?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> anda?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Apl ini mungkin mahu mengakses lokasi anda pada sepanjang masa, meskipun apabila anda tidak menggunakan apl itu. "<annotation id="link">"Benarkan dalam tetapan."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Tukar akses lokasi untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Tukar akses lokasi untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Apl ini mahu mengakses lokasi anda pada sepanjang masa, meskipun apabila anda tidak menggunakan apl itu. "<annotation id="link">"Benarkan dalam tetapan."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; untuk mencari, menyambung kepada dan menentukan penempatan relatif peranti berdekatan?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mencari, menyambung &amp; menentukan kedudukan relatif peranti berdekatan pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; untuk mencari, menyambung kepada dan menentukan penempatan relatif peranti berdekatan? "<annotation id="link">"Benarkan dalam tetapan."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Tukar akses lokasi <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> daripada anggaran kepada tepat?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Tukar akses lokasi <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda daripada lokasi anggaran kepada lokasi tepat?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi anggaran peranti ini?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lokasi anggaran &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Tepat"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Anggaran"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses kalendar anda?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses kalendar anda pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; menghantar dan melihat mesej SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; menghantar dan melihat mesej SMS pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto, media dan fail pada peranti anda?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto, media dan fail pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses &lt;b&gt;foto, video, muzik dan audio&lt;/b&gt; pada peranti ini?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses &lt;b&gt;foto, video, muzik, audio dan fail lain&lt;/b&gt; pada peranti ini?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses muzik dan audio pada peranti ini?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses muzik dan audio pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan video pada peranti ini?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses foto dan video pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lebih banyak foto dan video pada peranti ini?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses lebih banyak foto dan video pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merakam audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merakam audio pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Apl hanya boleh merakam audio semasa anda menggunakan apl tersebut"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merakam audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merakam audio pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Apl ini mungkin mahu merakam audio pada sepanjang masa, meskipun apabila anda tidak menggunakan apl itu. "<annotation id="link">"Benarkan dalam tetapan."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Tukar akses mikrofon untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Tukar akses mikrofon untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Apl ini mahu merakam audio pada sepanjang masa, meskipun apabila anda tidak menggunakan apl itu. "<annotation id="link">"Benarkan dalam tetapan."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses aktiviti fizikal anda?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses aktiviti fizikal anda pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengambil gambar dan merakam video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengambil gambar dan merakam video pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Apl hanya boleh mengambil gambar dan merakam video semasa anda menggunakan apl tersebut"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengambil gambar dan merakam video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengambil gambar dan merakam video pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Apl ini mungkin mahu mengambil gambar dan merakam video pada sepanjang masa, meskipun apabila anda tidak menggunakan apl itu. "<annotation id="link">"Benarkan dalam tetapan."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Tukar akses kamera untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Tukar akses kamera untuk &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Apl ini mahu mengambil gambar dan merakam video pada sepanjang masa, meskipun apabila anda tidak menggunakan apl itu. "<annotation id="link">"Benarkan dalam tetapan."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses log panggilan telefon anda?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses log panggilan telefon anda pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; membuat dan mengurus panggilan telefon?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; membuat dan mengurus panggilan telefon pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data penderia tentang tanda vital anda?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data penderia tentang tanda vital pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Apl ini mahu mengakses data penderia tentang tanda vital anda pada setiap masa, meskipun apabila anda tidak menggunakan apl. Untuk membuat perubahan ini, "<annotation id="link">"pergi ke tetapan."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data penderia tentang tanda vital anda?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data penderia tentang tanda vital pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Untuk membenarkan apl ini mengakses data penderia tubuh pada setiap masa, termasuk apabila anda tidak menggunakan apl, "<annotation id="link">"pergi ke tetapan."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Terus membenarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data penderia tubuh semasa apl digunakan?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Terus membenarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; mengakses data penderia tubuh pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda semasa apl digunakan?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; menghantar pemberitahuan kepada anda?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; menghantar pemberitahuan kepada anda pada &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; anda?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kebenaran terkawal"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> memiliki akses lokasi"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Organisasi anda membenarkan <xliff:g id="APP_NAME">%1$s</xliff:g> untuk mengakses lokasi anda"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Kebenaran lain"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Kebenaran digunakan oleh sistem"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Kebenaran digunakan hanya oleh aplikasi sistem"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Apl ini menyatakan bahawa data lokasi mungkin dikongsi dengan pihak ketiga"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Perkongsian data dan lokasi"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Sumber maklumat perkongsian data"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Pembangun menyediakan maklumat kepada pengilang peranti ini tentang cara apl ini berkongsi data. Pembangun boleh mengemaskinikan maklumat ini dari semasa ke semasa."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Pembangun menyediakan maklumat kepada "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" tentang cara apl ini berkongsi data. Pembangun mungkin mengemaskinikan maklumat ini dari semasa ke semasa."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Apl ini mungkin berkongsi data lokasi untuk:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Perkongsian data berbeza-beza"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Keselamatan data"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Data lokasi mungkin dikongsi"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Apl ini menyatakan bahawa data lokasi anda mungkin dikongsi dengan pihak ketiga"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Tidak dapat membuka pautan ini"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Kemaskinian perkongsian data untuk lokasi"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Semak apl yang mengubah cara apl itu boleh berkongsi data lokasi anda"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Apl ini telah mengubah cara apl boleh berkongsi data lokasi anda. Apl mungkin tidak berkongsi data lokasi sebelum ini atau mungkin berkongsi data lokasi sekarang untuk tujuan pengiklanan atau pemasaran."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Kemaskinian perkongsian data"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Sesetengah apl mengubah cara apl itu boleh berkongsi data lokasi anda"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Tetapan"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Diakses <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Diakses semalam <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Diakses <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-my-v33/strings.xml b/PermissionController/res/values-my-v33/strings.xml
index cb3ca6f69..33237070b 100644
--- a/PermissionController/res/values-my-v33/strings.xml
+++ b/PermissionController/res/values-my-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"နောက်ထပ် သတိပေးချက်များ"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"ပယ်ထားသော သတိပေးချက်များ"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{ချဲ့ပြီး သတိပေးချက်နောက်တစ်ခု ကြည့်ရန်}other{ချဲ့ပြီး သတိပေးချက်နောက် # ခု ကြည့်ရန်}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"သတိပေးချက်။ <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"လုပ်ဆောင်ချက် ပြီးပြီ"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"သင့်စက်တွင် အကာအကွယ်ထည့်သွင်းနိုင်သည့် ဆက်တင်များကို ကြည့်နိုင်သည်"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"လုံခြုံရေးနှင့် ကိုယ်ရေးဒေတာ အမြန်ဆက်တင်များ"</string>
diff --git a/PermissionController/res/values-my/strings.xml b/PermissionController/res/values-my/strings.xml
index a7f85acf2..f1ef9ded9 100644
--- a/PermissionController/res/values-my/strings.xml
+++ b/PermissionController/res/values-my/strings.xml
@@ -23,7 +23,7 @@
<string name="back" msgid="6249950659061523680">"နောက်သို့"</string>
<string name="available" msgid="6007778121920339498">"ရနိုင်သည်"</string>
<string name="blocked" msgid="9195547604866033708">"ပိတ်ထားသည်"</string>
- <string name="on" msgid="280241003226755921">"ဖွင့်ထားသည်"</string>
+ <string name="on" msgid="280241003226755921">"ဖွင့်"</string>
<string name="off" msgid="1438489226422866263">"ပိတ်"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"ပရိုဂရမ်ကို ဖယ်ရှားရန် သို့မဟုတ် ပိတ်ရန်"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"အက်ပ် မတွေ့ပါ"</string>
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"နောက်ထပ်"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"အားလုံး ခွင့်ပြုရန်"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"အားလုံး အမြဲခွင့်ပြုရန်"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"ကန့်သတ်သုံးခြင်းကို ခွင့်ပြုရန်"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ရွေးထားသော ဓာတ်ပုံနှင့်ဗီဒီယိုများ"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"နောက်ထပ် ရွေးရန်"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"နောက်ထပ်မရွေးပါနှင့်"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"မည်သို့ပင်ဖြစ်စေ ခွင့်မပြုပါ"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"ပယ်ရန်"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> ထဲမှ <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို <xliff:g id="ACTION">%2$s</xliff:g> ရန်ခွင့်ပြုမလား။"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို <xliff:g id="ACTION">%2$s</xliff:g> ရန် အမြဲခွင့်ပြုသလား။"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို <xliff:g id="ACTION">%2$s</xliff:g>ခွင့် ပြုမလား။"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို <xliff:g id="ACTION">%2$s</xliff:g>ခွင့် အမြဲပြုသလား။"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"အက်ပ်အသုံးပြုစဉ်သာ"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"အမြဲတမ်း"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"ခွင့်မပြုပါ၊ ထပ်မမေးပါနှင့်"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"အက်ပ်များ"</string>
<string name="app_permissions" msgid="3369917736607944781">"အက်ပ်ခွင့်ပြုချက်များ"</string>
<string name="unused_apps" msgid="2058057455175955094">"အသုံးမပြုသော အက်ပ်များ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ဤအက်ပ်အတွက် ရွေးထားသောဓာတ်ပုံများကို ပြင်ရန်"</string>
<string name="no_unused_apps" msgid="12809387670415295">"အသုံးမပြုသောအက်ပ်များ မရှိပါ"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"အသုံးမပြုသောအက်ပ် 0 ခု"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"လတ်တလောခွင့်ပြုသည့် ဆုံးဖြတ်ချက်များ"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"ခွင့်ပြုချက် အားလုံး"</string>
<string name="other_permissions" msgid="2901186127193849594">"အခြားအက်ပ်၏ စွမ်းရည်များ"</string>
<string name="permission_request_title" msgid="8790310151025020126">"ခွင့်ပြုချက် တောင်းခံမှု"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear ပေါ်တွင် ထည့်သွင်းခြင်း/ဖြုတ်ခြင်းများကို ပံ့ပိုးမထားပါ။"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&amp;It;b7gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&amp;It;/b&gt; က အသုံးပြုခွင့်ရမည့် အရာတို့ကို ရွေးပါ"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&amp;It;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&amp;It;/b&gt; ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ။ ဤအက်ပ်က အသုံးပြုခွင့်ရမည့်အရာတို့ကို ရွေးပါ။"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"မလုပ်တော့"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"အက်ပ်ကိုအသုံးမပြုလျှင် ခွင့်ပြုချက်များ ဖယ်ရှားရန်"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"ခွင့်ပြုချက်များဖယ်ရှားပြီး နေရာလွတ်ပြုလုပ်ရန်"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"အသုံးမပြုပါက အက်ပ်လုပ်ဆောင်ချက် ခဏရပ်ရန်"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"အသုံးမပြုပါက အက်ပ်ကို စီမံရန်"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ခွင့်ပြုချက် ဖယ်ရှားခြင်း၊ ယာယီဖိုင် ဖျက်ခြင်း၊ အကြောင်းကြားချက် ရပ်ခြင်း"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ခွင့်ပြုချက်များ ဖယ်ရှားခြင်း၊ ယာယီဖိုင်များ ဖျက်ခြင်း၊ အကြောင်းကြားချက်များ ရပ်ခြင်းနှင့် အက်ပ်သိမ်းခြင်းတို့ ပြုလုပ်နိုင်သည်"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"အက်ပ်ကို လအနည်းငယ် အသုံးမပြုပါက သင်၏ဒေတာကိုကာကွယ်ရန် ဤအက်ပ်အတွက် ခွင့်ပြုချက်များကို ဖယ်ရှားပါမည်။"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"အက်ပ်ကို လအနည်းငယ် အသုံးမပြုပါက သင်၏ဒေတာကိုကာကွယ်ရန် အောက်ပါခွင့်ပြုချက်များကို ဖယ်ရှားပါမည်- <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"သင်၏ဒေတာကိုကာကွယ်ရန် လအနည်းငယ်အတွင်း အသုံးမပြုသော အက်ပ်များမှ ခွင့်ပြုချက်များကို ဖယ်ရှားလိုက်သည်။"</string>
@@ -397,10 +399,20 @@
<string name="role_watch_description" msgid="267003778693177779">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> ကို ခွင့်ပြုပါမည်။"</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"သင့်အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန်နှင့် သင့်အက်ပ်များကို ချိတ်ဆက်ထားသောစက်သို့ တိုက်ရိုက်လွှင့်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> ကို ခွင့်ပြုပါမည်။"</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"ဤဝန်ဆောင်မှုသည် သင်၏ဖုန်းမှ ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များကို အခြားစက်ပစ္စည်းများသို့ မျှဝေသည်။"</string>
- <string name="role_notes_label" msgid="7451627001058089536">"မူလ မှတ်စုရေးသောအက်ပ်"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"မူရင်း မှတ်စုအက်ပ်"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"မှတ်စုရေးသောအက်ပ်"</string>
<string name="role_notes_description" msgid="8496852798616883551">"စက်ပစ္စည်းတွင် မှတ်စုရေးခွင့်ပြုသော အက်ပ်များ"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"မှတ်စုများ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"လက်ရှိ မူရင်း"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"ထပ်မမေးပါနှင့်"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"မူရင်း သတ်မှတ်ရန်"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"အကူအညီစတင်ရန် သိရှိမှုစနစ်ကို ပြပါ"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"အသံအကူအညီ စတင်ရန် မိုက်ခရိုဖုန်းအသုံးပြုသည့်အခါ သင်္ကေတကို အခြေအနေဘားတွင် ပြပါ"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင့်စက်ပေါ်ရှိ ဓာတ်ပုံနှင့် မီဒီယာဖိုင်များ ဝင်သုံးခွင့်ပေးလိုပါသလား။"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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> ၏ တည်နေရာသုံးခွင့်ပြုမလား။"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"သင် အသုံးမပြုနေလျှင်တောင်မှ ဤအက်ပ်က သင့်တည်နေရာကို သုံးခွင့်ရနေပါမည်။ "<annotation id="link">"ဆက်တင်များတွင် ခွင့်ပြုပါ။"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&amp;gt တို့အတွက် တည်နေရာ ဝင်ခွင့် ပြောင်းပေးမလား။"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"သင် အသုံးမပြုနေလျှင်တောင်မှ ဤအက်ပ်က သင့်တည်နေရာကို သုံးခွင့်ရလိုသည်။ "<annotation id="link">"ဆက်တင်များတွင် ခွင့်ပြုပါ။"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"အနီးရှိ စက်များ၏ မှန်းခြေနေရာ ရှာရန်၊ ချိတ်ဆက်ရန်နှင့် သတ်မှတ်ရန် &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို ခွင့်ပြုမလား။"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင့် &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် အနီးတစ်ဝိုက်ရှိ စက်များ၏ ဆက်စပ်နေရာကို ရှာရန်၊ ချိတ်ဆက်ရန်နှင့် သတ်မှတ်ရန် ခွင့်ပြုမလား။"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"အနီးရှိ စက်များ၏မှန်းခြေနေရာကို ရှာရန်၊ ချိတ်ဆက်ရန်နှင့် သတ်မှတ်ရန် &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား ခွင့်ပြုမလား။ "<annotation id="link">"ဆက်တင်များတွင် ခွင့်ပြုပါ။"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ၏ တည်နေရာသုံးခွင့်ကို ခန့်မှန်းခြေမှ အတိအကျသို့ ပြောင်းမလား။"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ၏ တည်နေရာသုံးခွင့်ကို ခန့်မှန်းခြေမှ အတိအကျသို့ ပြောင်းမလား။"</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင့် &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ရှိ SMS မက်ဆေ့ဂျ်များကို ပို့ခွင့်နှင့် ကြည့်ရှုခွင့်ပေးမလား။"</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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ရှိ ဓာတ်ပုံ၊ မီဒီယာနှင့် ဖိုင်များကို သုံးခွင့်ပြုမလား။"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"ဤစက်ရှိ &lt;b&gt;ဓာတ်ပုံ၊ ဗီဒီယို၊ တေးဂီတနှင့် အသံများ&lt;/b&gt; ကို &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သုံးခွင့်ပေးမလား။"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"စက်ရှိ &lt;b&gt;ဓာတ်ပုံ၊ ဗီဒီယို၊ တေးဂီတ၊ အသံနှင့်အခြားဖိုင်များ&lt;/b&gt; ကို &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သုံးခွင့်ပေးမလား။"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"ဤစက်ရှိ တေးဂီတနှင့် အသံဖိုင်ကို &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သုံးခွင့်ပေးမလား။"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; ရှိ တေးဂီတနှင့် အသံဖိုင်ကို သုံးခွင့်ပြုမလား။"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"ဤစက်ရှိ ဓာတ်ပုံနှင့် ဗီဒီယိုများကို &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သုံးခွင့်ပေးမလား။"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် ဓာတ်ပုံနှင့် ဗီဒီယိုများကို သုံးခွင့်ပြုမလား။"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"ဤစက်ရှိ နောက်ထပ်ဓာတ်ပုံနှင့် ဗီဒီယိုများကို &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သုံးခွင့်ပေးမလား။"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် နောက်ထပ်ဓာတ်ပုံနှင့် ဗီဒီယိုများ သုံးခွင့်ပြုမလား။"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို အသံဖမ်းယူခွင့် ပေးလိုပါသလား။"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင့် &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် အသံဖမ်းယူခွင့်ပြုမလား။"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"ဤအက်ပ်ကို အသုံးပြုနေသည့် အချိန်တွင်သာ ၎င်းက အသံဖမ်းနိုင်သည်။"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို အသံဖမ်းခွင့် ပေးလိုပါသလား။"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင့် &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် အသံဖမ်းယူခွင့်ပြုမလား။"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ဤအက်ပ်ကို သင်အသုံးမပြုနေလျှင်ပင် ၎င်းက တစ်ချိန်လုံး အသံဖမ်းယူလိုသည်။ "<annotation id="link">"ဆက်တင်များတွင် ခွင့်ပြုပါ။"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&amp;gt အတွက် မိုက်ခရိုဖုန်း အသုံးပြုခွင့် ပြောင်းမလား။"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"ဤအက်ပ်ကို သင်အသုံးမပြုနေလျှင်ပင် ၎င်းက တစ်ချိန်လုံး အသံဖမ်းလိုသည်။ "<annotation id="link">"ဆက်တင်များတွင် ခွင့်ပြုပါ။"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင့်ကိုယ်ခန္ဓာလှုပ်ရှားမှုကို ဝင်ကြည့်ခွင့် ပေးလိုပါသလား။"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် သင့်ကိုယ်ခန္ဓာလှုပ်ရှားမှု သုံးခွင့်ပြုမလား။"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား ဓာတ်ပုံနှင့် ဗီဒီယိုရိုက်ကူးခွင့် ပေးလိုပါသလား။"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် ဓာတ်ပုံနှင့် ဗီဒီယိုရိုက်ကူးခွင့်ပြုမလား။"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"ဤအက်ပ်ကို အသုံးပြုနေသည့် အချိန်တွင်သာ ၎င်းက ဓာတ်ပုံနှင့် ဗီဒီယိုများကို ရိုက်ကူးနိုင်သည်။"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို ဓာတ်ပုံနှင့် ဗီဒီယိုရိုက်ကူးခွင့် ပေးလိုပါသလား။"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် ဓာတ်ပုံနှင့် ဗီဒီယိုရိုက်ကူးခွင့်ပြုမလား။"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ဤအက်ပ်ကို သင်အသုံးမပြုနေလျှင်ပင် ၎င်းက ဓာတ်ပုံနှင့် ဗီဒီယိုများကို တစ်ချိန်လုံး ရိုက်ကူးလိုသည်။ "<annotation id="link">"ဆက်တင်များတွင် ခွင့်ပြုပါ။"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&amp;gt အတွက် ကင်မရာအသုံးပြုခွင့် ပြောင်းမလား။"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"ဤအက်ပ်ကို သင်အသုံးမပြုနေလျှင်ပင် ၎င်းက ဓာတ်ပုံနှင့် ဗီဒီယိုများကို တစ်ချိန်လုံး ရိုက်ကူးလိုသည်။ "<annotation id="link">"ဆက်တင်များတွင် ခွင့်ပြုပါ။"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ခေါ်ဆိုထားသော မှတ်တမ်းများကို သုံးခွင့်ပေးလိုပါသလား။"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် သင့်ဖုန်းခေါ်ဆိုမှတ်တမ်း သုံးခွင့်ပြုမလား။"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို ဖုန်းခေါ်ဆိုမှုများ ပြုလုပ်ခွင့်နှင့် စီမံခွင့်ပေးလိုပါသလား။"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် ဖုန်းခေါ်ဆိုခွင့်နှင့် စီမံခွင့်ပေးမလား။"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ အရေးကြီးသော ကျန်းမာရေးလက္ခဏာဆိုင်ရာ အာရုံခံကိရိယာဒေတာ သုံးခွင့်ပေးလိုပါသလား။"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် သင့်အဓိကကိုယ်တွင်းအင်္ဂါအခြေအနေ လက္ခဏာများနှင့်ပတ်သက်သည့် အာရုံခံစနစ်ဒေတာ သုံးခွင့်ပြုမလား။"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"အက်ပ်သုံးမနေသော်လည်း ဤအက်ပ်က သင်၏အရေးကြီးသည့် ကျန်းမာရေးလက္ခဏာဆိုင်ရာ အာရုံခံစနစ်ဒေတာကို အမြဲသုံးခွင့် ရယူလိုသည်။ ဤအပြောင်းအလဲကို ပြုလုပ်ရန် "<annotation id="link">"ဆက်တင်များသို့ သွားပါ။"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား သင်၏ အရေးကြီးသော ကျန်းမာရေးလက္ခဏာဆိုင်ရာ အာရုံခံစနစ်ဒေတာကို သုံးခွင့်ပေးလိုပါသလား။"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; အား &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် သင့်အဓိကကိုယ်တွင်းအင်္ဂါအခြေအနေ လက္ခဏာများနှင့်ပတ်သက်သည့် အာရုံခံစနစ်ဒေတာ သုံးခွင့်ပြုမလား။"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"အက်ပ်သုံးမနေသော်လည်း ဤအက်ပ်ကို ခန္ဓာကိုယ်အာရုံခံစနစ် ဒေတာများ အမြဲသုံးခွင့်ပြုရန် "<annotation id="link">"ဆက်တင်များသို့ သွားပါ။"</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"အက်ပ်သုံးစဉ် &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို ခန္ဓာကိုယ်အာရုံခံစနစ် ဒေတာ ဆက်သုံးခွင့်ပြုမလား။"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"အက်ပ်သုံးစဉ် &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် ခန္ဓာကိုယ် အာရုံခံကိရိယာ ဒေတာ ဆက်သုံးခွင့်ပြုမလား။"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို သင့်ထံ အကြောင်းကြားချက်များ ပို့ခွင့်ပြုမလား။"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ကို သင်၏ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; တွင် သင့်ထံ အကြောင်းကြားချက်များ ပို့ခွင့်ပြုမလား။"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"ထိန်းချုပ်ထားသော ခွင့်ပြုချက်များ"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> တွင် တည်နေရာသုံးခွင့်ရှိသည်"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"သင်၏အဖွဲ့အစည်းက <xliff:g id="APP_NAME">%1$s</xliff:g> အား သင့်တည်နေရာကို သုံးခွင့်ပြုသည်"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"အခြားခွင့်ပြုချက်များ"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"စနစ်က အသုံးပြုသည့် ခွင့်ပြုချက်"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"စနစ် အပလီကေးရှင်းများကသာ အသုံးပြုသည့် ခွင့်ပြုချက်များ။"</string>
@@ -584,13 +621,14 @@
<string name="perm_toggle_description" msgid="7801326363741451379">"အက်ပ်နှင့် ဝန်ဆောင်မှုများအတွက်"</string>
<string name="mic_toggle_description" msgid="9163104307990677157">"အက်ပ်နှင့် ဝန်ဆောင်မှုများအတွက်။ ဤဆက်တင်ကို ပိတ်ထားသော်လည်း အရေးပေါ် နံပါတ်ကို သင်ခေါ်ဆိုချိန်တွင် မိုက်ခရိုဖုန်းဒေတာကို မျှဝေနိုင်သေးသည်။"</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"တည်နေရာသုံးခွင့်ရှိသော အက်ပ်နှင့် ဝန်ဆောင်မှုများကို ကြည့်ပါ"</string>
- <string name="show_clip_access_notification_title" msgid="5168467637351109096">"ကလစ်ဘုတ်အသုံးပြုမှုကို ပြခြင်း"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"အက်ပ်များက သင်မိတ္တူကူးထားသော စာသား၊ ပုံများ (သို့) အခြားအကြောင်းအရာကို သုံးသောအခါ အကြောင်းကြားပါ"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"ကလစ်ဘုတ်အသုံးပြုမှု ပြရန်"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"အက်ပ်များက သင်မိတ္တူကူးထားသော စာသား၊ ပုံများ (သို့) အခြားအကြောင်းအရာကို သုံးသောအခါ အကြောင်းကြားသည်"</string>
<string name="show_password_title" msgid="2877269286984684659">"စကားဝှက်များပြရန်"</string>
<string name="show_password_summary" msgid="1110166488865981610">"စာရိုက်သည့်အခါ အက္ခရာများကို ခဏတာပြသည်"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"ဤအက်ပ်က ၎င်းသည် ဒေတာကို ပြင်ပအဖွဲ့များနှင့် မျှဝေနိုင်ကြောင်း ဖော်ပြထားသည်"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ဒေတာမျှဝေခြင်းနှင့် တည်နေရာ"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ဒေတာမျှဝေခြင်း အချက်အလက် ရလာသောနေရာ"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ဆော့ဖ်ဝဲရေးသူသည် ဤအက်ပ် ဒေတာမျှဝေပုံအကြောင်း အချက်အလက်ကို ဤစက်၏ ထုတ်လုပ်သူထံသို့ ပေးထားသည်။ ဆော့ဖ်ဝဲရေးသူက ဤအချက်အလက်ကို အချိန်နှင့်အမျှ အပ်ဒိတ်လုပ်နိုင်သည်။"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ဆော့ဖ်ဝဲရေးသူသည် ဤအက်ပ် ဒေတာမျှဝေပုံအကြောင်း အချက်အလက်ကို "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" သို့ ပေးထားသည်။ ဆော့ဖ်ဝဲရေးသူက ဤအချက်အလက်ကို အချိန်နှင့်အမျှ အပ်ဒိတ်လုပ်နိုင်သည်။"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ဤအက်ပ်က အောက်ပါတို့ကြောင့် တည်နေရာဒေတာမျှဝေနိုင်သည်-"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ဒေတာမျှဝေခြင်း ကွဲပြားပုံ"</string>
@@ -608,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ဒေတာ ဘေးကင်းလုံခြုံရေး"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"တည်နေရာဒေတာကို မျှဝေနိုင်သည်"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"ဤအက်ပ်က ၎င်းသည် သင်၏ တည်နေရာဒေတာကို ပြင်ပကုမ္ပဏီများနှင့် မျှဝေနိုင်ကြောင်း ဖော်ပြထားသည်"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ဤလင့်ခ်ကို ဖွင့်၍မရပါ"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"တည်နေရာအတွက် ဒေတာမျှဝေခြင်း အပ်ဒိတ်"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"သင်၏ တည်နေရာဒေတာ မျှဝေနိုင်သောနည်းလမ်းအား ပြောင်းထားသော အက်ပ်များကို စိစစ်ပါ"</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"သင်၏ တည်နေရာဒေတာ မျှဝေနိုင်သောနည်းလမ်းအား ပြောင်းထားသော အက်ပ်များကို စိစစ်သည်"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"ဤအက်ပ်များသည် ၎င်းတို့က သင်၏ တည်နေရာဒေတာ မျှဝေနိုင်သော နည်းလမ်းကို ပြောင်းလိုက်ပါပြီ။ ၎င်းတို့သည် ဒေတာကို ယခင်က မျှဝေထားခြင်း မရှိနိုင်ပါ သို့မဟုတ် ကြော်ငြာခြင်း (သို့) အရောင်းမြှင့်တင်ခြင်းတို့အတွက် ဒေတာကို ယခုမျှဝေနိုင်သည်။"</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"ဤအက်ပ်များ၏ ဆော့ဖ်ဝဲရေးသူများသည် ၎င်းတို့၏ ဒေတာမျှဝေခြင်း လုပ်ထုံးလုပ်နည်းများအကြောင်း အချက်အလက်ကို အက်ပ်စတိုးသို့ ပေးထားသည်။ သူတို့သည် ၎င်းကို အချိန်နှင့်အမျှ အပ်ဒိတ်လုပ်နိုင်သည်။\n\nဒေတာမျှဝေခြင်း လုပ်ထုံးလုပ်နည်းများသည် သင်၏ အက်ပ်ဗားရှင်း၊ အသုံးပြုမှု၊ ဒေသနှင့် အသက်အရွယ်ပေါ် အခြေခံ၍ ကွဲပြားနိုင်သည်။"</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"ဒေတာမျှဝေခြင်းအကြောင်း လေ့လာရန်"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ဒေတာမျှဝေခြင်း အပ်ဒိတ်"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"အက်ပ်အချို့သည် ၎င်းတို့က သင်၏ တည်နေရာဒေတာ မျှဝေနိုင်သော နည်းလမ်းကို ပြောင်းထားသည်"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ဆက်တင်များ"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g> တွင် ဝင်ကြည့်ထားသည်"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"မနေ့ <xliff:g id="TIME_DATE">%1$s</xliff:g> တွင် ဝင်ကြည့်ထားသည်"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g><xliff:g id="TIME_DATE_1">%2$s</xliff:g> တွင် ဝင်ကြည့်ထားသည်"</string>
</resources>
diff --git a/PermissionController/res/values-nb-v33/strings.xml b/PermissionController/res/values-nb-v33/strings.xml
index 88d17ffcc..570e99d27 100644
--- a/PermissionController/res/values-nb-v33/strings.xml
+++ b/PermissionController/res/values-nb-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Flere varsler"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Avviste varsler"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Dobbelttrykk for å se et varsel til}other{Dobbelttrykk for å se # varsler til}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Varsel. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Handlingen er fullført"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Sjekk innstillinger som kan øke beskyttelsen til enheten"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Hurtiginnstillinger for sikkerhet og personvern"</string>
diff --git a/PermissionController/res/values-nb/strings.xml b/PermissionController/res/values-nb/strings.xml
index 26ccb9950..41f6ecaf6 100644
--- a/PermissionController/res/values-nb/strings.xml
+++ b/PermissionController/res/values-nb/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Mer info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Tillat alle"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Tillat alltid alle"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Gi begrenset tilgang"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Velg bilder og videoer"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Velg flere"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ikke velg flere"</string>
@@ -48,7 +49,7 @@
<string name="permission_revoked_count" msgid="4785082705441547086">"<xliff:g id="COUNT">%1$d</xliff:g> er slått av"</string>
<string name="permission_revoked_all" msgid="3397649017727222283">"alt er slått av"</string>
<string name="permission_revoked_none" msgid="9213345075484381180">"ingen er slått av"</string>
- <string name="grant_dialog_button_allow" msgid="5314677880021102550">"Ja"</string>
+ <string name="grant_dialog_button_allow" msgid="5314677880021102550">"Tillat"</string>
<string name="grant_dialog_button_allow_always" msgid="4485552579273565981">"Tillat hele tiden"</string>
<string name="grant_dialog_button_allow_foreground" msgid="501896824973636533">"Når appen brukes"</string>
<string name="grant_dialog_button_change_to_precise_location" msgid="3273115879467236033">"Bytt til nøyaktig posisjon"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apper"</string>
<string name="app_permissions" msgid="3369917736607944781">"Apptillatelser"</string>
<string name="unused_apps" msgid="2058057455175955094">"Ubrukte apper"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Endre bilder som er valgt for denne appen"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Ingen ubrukte apper"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ubrukte apper"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nylige tillatelsesavgjørelser"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Alle tillatelser"</string>
<string name="other_permissions" msgid="2901186127193849594">"Andre appfunksjoner"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Forespørsel om tillatelse"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Handlinger for å installere og avinstallere støttes ikke på Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Velg hva du vil gi <xliff:g id="APP_NAME">%1$s</xliff:g> tilgang til"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"<xliff:g id="APP_NAME">%1$s</xliff:g> er oppdatert. Velg hva du vil gi denne appen tilgang til."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Avbryt"</string>
@@ -196,7 +196,7 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"Bruk nøyaktig posisjon"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Når nøyaktig posisjon er av, har apper tilgang til den omtrentlige posisjonen din"</string>
<string name="app_permission_title" msgid="2090897901051370711">"Tillatelse: <xliff:g id="PERM">%1$s</xliff:g>"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"<xliff:g id="PERM">%1$s</xliff:g>: tilgang for denne appen"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"Tilgang for denne appen: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Se alle tillatelsene <xliff:g id="APP">%1$s</xliff:g> har"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Se alle apper med denne tillatelsen"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Vis bruk av assistentmikrofonen"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Fjern tillatelser hvis appen ikke brukes"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Fjern tillatelser og frigjør plass"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Sett appaktivitet på pause hvis ubrukt"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Administrer appen hvis den ikke brukes"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Fjern tillatelser, slett midlertidige filer, og stopp varsler"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Fjern tillatelser, slett midlertidige filer, stopp varsler, og arkiver appen"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"For å beskytte dataene dine fjernes tillatelser for denne appen hvis appen ikke brukes på noen måneder."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Hvis appen ikke brukes på noen måneder, fjernes disse tillatelsene for å beskytte dataene dine: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"For å beskytte dataene dine har tillatelser blitt fjernet fra apper du ikke har brukt på noen måneder."</string>
@@ -397,10 +399,20 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og strømme appene dine til den tilkoblede enheten."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Denne tjenesten deler bildene, mediene og varslene dine fra telefonen din til andre enheter."</string>
- <string name="role_notes_label" msgid="7451627001058089536">"Standard notatapper"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Standard notatapp"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"Notatapp"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apper du kan bruke til å ta notater på enheten"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notater"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Gjeldende standard"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ikke spør igjen"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Angi som standard"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Vis aktivering av assistenten"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Vis ikon i statusfeltet når mikrofonen brukes til å aktivere taleassistent"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til bilder og medier på enheten din?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke bilder og medier på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til kontaktene dine?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke kontakter på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til denne enhetens posisjon?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se posisjonen til &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Appen får bare tilgang til posisjonen når du bruker appen"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til denne enhetens posisjon?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se posisjonen til &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Denne appen vil kanskje ha tilgang til posisjonen din hele tiden, selv når du ikke bruker appen. "<annotation id="link">"Gi tillatelse i innstillingene."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Vil du endre posisjonstilgang for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Vil du endre posisjonstilgangen for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Denne appen vil ha tilgang til posisjonen din hele tiden, selv når du ikke bruker appen. "<annotation id="link">"Gi tillatelse i innstillingene."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tillatelse til å finne, koble til og fastslå den relative posisjonen til enheter i nærheten?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; finne, koble til og fastslå den relative posisjonen til enheter i nærheten på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tillatelse til å finne, koble til og fastslå den relative posisjonen til enheter i nærheten? "<annotation id="link">"Tillat i innstillingene."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Vil du endre posisjontilgangen til <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> fra omtrentlig til nøyaktig?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Vil du endre tilgangen <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> har til posisjon på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; fra omtrentlig til nøyaktig?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til denne enhetens omtrentlige posisjon?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se den omtrentlige posisjonen til &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Nøyaktig"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Omtrentlig"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til kalenderen din?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke kalenderen på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sende og se tekstmeldinger?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sende og se SMS-meldinger på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til bilder, medier og filer på enheten din?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke bilder, medier og filer på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke &lt;b&gt;bilder, videoer, musikk og lyd&lt;/b&gt; på denne enheten?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke &lt;b&gt;bilder, videoer, musikk, lyd og andre filer&lt;/b&gt; på denne enheten?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke musikk og lyd på denne enheten?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke musikk og lyd på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke bilder og videoer på denne enheten?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke bilder og videoer på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke flere bilder og videoer på denne enheten?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bruke flere bilder og videoer på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ta opp lyd?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ta opp lyd på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Appen kan bare ta opp lyd mens du bruker den."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ta opp lyd?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ta opp lyd på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Denne appen vil kanskje ta opp lyd hele tiden, selv når du ikke bruker den. "<annotation id="link">"Gi tillatelse i innstillingene."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Vil du endre mikrofontilgang for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Vil du endre mikrofontilgangen for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Denne appen vil ta opp lyd hele tiden, selv når du ikke bruker den. "<annotation id="link">"Gi tillatelse i innstillingene."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til den fysiske aktiviteten din?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se fysisk aktivitet på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ta bilder og spille inn video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ta bilder og spille inn videoer på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Appen kan bare ta bilder og spille inn videoer mens du bruker den"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ta bilder og spille inn videoer?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ta bilder og spille inn videoer på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Denne appen vil kanskje ta bilder og spille inn videoer hele tiden, selv når du ikke bruker den. "<annotation id="link">"Gi tillatelse i innstillingene."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Vil du endre kameratilgang for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Vil du endre kameratilgangen for &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Denne appen vil ta bilder og spille inn videoer hele tiden, selv når du ikke bruker den. "<annotation id="link">"Gi tillatelse i innstillingene."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til samtaleloggene dine?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se samtaleloggene på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ringe og administrere telefonsamtaler?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ringe og administrere telefonsamtaler på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til sensordata om de vitale tegnene dine?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se sensordata om de vitale tegnene dine på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Denne appen vil ha tilgang til sensordata om de vitale tegnene dine hele tiden, selv når du ikke bruker den. For å gjøre denne endringen, "<annotation id="link">"gå til innstillingene."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Vil du gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til sensordataene om de vitale tegnene dine?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se sensordataene om de vitale tegnene dine på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"For å gi denne appen tilgang til data fra kroppssensorer til enhver tid, selv når du ikke bruker den, "<annotation id="link">"gå til innstillingene."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Vil du fortsette å gi &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tilgang til data fra kroppssensorer mens appen er i bruk?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Vil du fortsette å la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; se data fra kroppssensorer på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mens appen er i bruk?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sende deg varsler?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Vil du la &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sende deg varsler på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontrollerte tillatelser"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> har posisjonstilgang"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Organisasjonen din lar <xliff:g id="APP_NAME">%1$s</xliff:g> se hvor du er"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Andre tillatelser"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Tillatelser som brukes av systemet"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Tillatelser som bare brukes av systemappene."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Denne appen har oppgitt at den kan dele posisjonsdata med tredjeparter"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Datadeling og posisjon"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Hvor kommer informasjon om datadeling fra?"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Utvikleren har gitt produsenten av denne enheten informasjon om hvordan denne appen deler data. Utvikleren kan oppdatere denne informasjonen over tid."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Utvikleren har gitt informasjon til "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" om hvordan denne appen deler data. Utvikleren kan oppdatere denne informasjonen over tid."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Denne appen kan dele posisjonsdata for"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datadeling varierer"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Datasikkerhet"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Posisjonsdata kan deles"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Denne appen har oppgitt at den kan dele posisjonsdataene dine med tredjeparter"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Kan ikke åpne denne linken"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Oppdatering av datadeling for posisjon"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Gjennomgå apper som har endret hvordan de deler posisjonsdataene dine"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Disse appene har endret hvordan de kan dele posisjonsdataene dine. De har muligens ikke delt dem før eller kan nå dele dem for annonsering eller markedsføring."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Oppdateringer av datadeling"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Noen apper har endret hvordan de kan dele posisjonsdataene dine"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Innstillinger"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Åpnet <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Åpnet i går <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Åpnet <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-ne-v33/strings.xml b/PermissionController/res/values-ne-v33/strings.xml
index eea107bfb..b16622bd0 100644
--- a/PermissionController/res/values-ne-v33/strings.xml
+++ b/PermissionController/res/values-ne-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"थप अलर्टहरू"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"खारेज गरिएका अलर्टहरू"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{एक्स्पान्ड गरेर थप एउटा अलर्ट हेर्नुहोस्}other{एक्स्पान्ड गरेर थप # वटा अलर्ट हेर्नुहोस्}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"सतर्कता अपनाउनुहोस्। <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"यो कार्य पूरा भएको छ"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"तपाईंको डिभाइस थप सुरक्षित गर्न सक्ने सेटिङ जाँच्नुहोस्"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"सुरक्षा तथा गोपनीयतासम्बन्धी द्रुत सेटिङ"</string>
diff --git a/PermissionController/res/values-ne/strings.xml b/PermissionController/res/values-ne/strings.xml
index 001b72f09..13a3591e0 100644
--- a/PermissionController/res/values-ne/strings.xml
+++ b/PermissionController/res/values-ne/strings.xml
@@ -32,11 +32,12 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"“एप प्रयोगमा भएको बेलामा” शीर्षक कायम राख्नुहोस्"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"“यस बेला मात्र” राख्नुहोस्"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"थप जानकारी"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"सबै अनुमति दिनुहोस्"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"सबै डेटा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"सधैँ सबै अनुमति दिइयोस्"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"सीमित एक्सेस दिनुहोस्"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"फोटो र भिडियोहरू चयन गर्नुहोस्"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"अझ धेरै फोटो चयन गर्नुहोस्"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"थप फोटो वा कन्ट्याक्ट चयन नगर्नुहोस्"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"थप डेटा चयन नगर्नुहोस्"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"जे भए पनि फेरि नसोध्नुहोस्"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"खारेज गर्नुहोस्"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> मध्ये <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"एपहरू"</string>
<string name="app_permissions" msgid="3369917736607944781">"एपसम्बन्धी अनुमति"</string>
<string name="unused_apps" msgid="2058057455175955094">"प्रयोग नगरिएका एपहरू"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"यो एपका लागि चयन गरिएका फोटोहरू सम्पादन गर्नुहोस्"</string>
<string name="no_unused_apps" msgid="12809387670415295">"सबै एप चलाइएका छन्"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"प्रयोग नगरिएका एउटा पनि एप छैन"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"हालै दिइएका अनुमतिसम्बन्धी निर्णयहरू"</string>
@@ -71,7 +73,7 @@
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{आज}=1{१ दिनअघि}other{# दिनअघि}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"एप असक्षम पार्नुहोस्"</string>
<string name="app_disable_dlg_text" msgid="3126943217146120240">"तपाईंले यो एप असक्षम पार्नुभयो भने Android र अन्य एपहरूले अब उप्रान्त अपेक्षाअनुसार कार्य नगर्न सक्छन्। स्मरण रहोस्, तपाईं यो एप तपाईंको यन्त्रसँग पहिल्यै स्थापना भएर आएको हुँदा तपाईं यसलाई मेटाउन सक्नुहुन्न। यो एप असक्षम पारेर, तपाईं यसलाई निष्क्रिय पार्नुहुन्छ तथा यसलाई आफ्नो डिभाइसमा लुकाउनुहुन्छ।"</string>
- <string name="app_permission_manager" msgid="3903811137630909550">"पर्मिसन म्यानेजर"</string>
+ <string name="app_permission_manager" msgid="3903811137630909550">"अनुमति व्यवस्थापन"</string>
<string name="never_ask_again" msgid="4728762438198560329">"फेरि नसोध्नुहोला"</string>
<string name="no_permissions" msgid="3881676756371148563">"अनुमति दिन भनी कुनै अनुरोध छैन"</string>
<string name="additional_permissions" msgid="5801285469338873430">"अतिरिक्त अनुमति"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"सबै अनुमति"</string>
<string name="other_permissions" msgid="2901186127193849594">"एपका अन्य क्षमताहरू"</string>
<string name="permission_request_title" msgid="8790310151025020126">"अनुमति दिन भनी गरिएको अनुरोध"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear मा स्थापना/स्थापना रद्द गर्ने कारबाहीहरू समर्थित छैनन्।"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई केमाथि पहुँच राख्न दिने हो छनौट गर्नुहोस्"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; अद्यावधिक गरिएको छ। यस एपलाई केमाथि पहुँच राख्न दिने हो छनौट गर्नुहोस्।"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"रद्द गर्नुहोस्"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"यो एप प्रयोग नहुँदा यसलाई दिइएका अनुमतिहरू रद्द गरियोस्"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"अनुमतिहरू हटाई ठाउँ खाली गरियोस्"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"एप प्रयोग नगरिएको अवस्थामा उक्त एपमा बिताएको समय रेकर्ड नगरियोस्"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"एप प्रयोग गरिएको छैन भने व्यवस्थापन गरियोस्"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"अनुमतिहरू रद्द गरियोस्, अस्थायी फाइलहरू मेटाइयोस् र एपसम्बन्धी सूचना नपठाइयोस्"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"अनुमति रद्द गरियोस्, अस्थायी फाइलहरू मेटाइयोस्, सूचना नपठाइयोस् र एप अभिलेखमा राखियोस्"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"तपाईंका डेटाको सुरक्षार्थ यो एप केही महिनासम्म प्रयोग नगरिएका खण्डमा यसलाई दिइएका अनुमति रद्द गरिने छन्।"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"तपाईंका डेटाको सुरक्षार्थ यो एप केही महिनासम्म प्रयोग नगरिएका खण्डमा निम्न अनुमति रद्द गरिने छन्: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"तपाईंका डेटाको सुरक्षार्थ तपाईंले केही महिनादेखि प्रयोग नगरेका एपलाई दिइएका अनुमति रद्द गरिएका छन्।"</string>
@@ -366,7 +368,7 @@
<string name="role_sms_description" msgid="3424020199148153513">"तपाईंलाई छोटा टेक्स्ट म्यासेज, फोटो, भिडियो र थप कुरा पठाउन र प्राप्त गर्न आफ्नो फोन नम्बर प्रयोग गर्न दिने एपहरू"</string>
<string name="role_sms_request_title" msgid="7953552109601185602">"आफ्नो डिफल्ट SMS एपका रूपमा <xliff:g id="APP_NAME">%1$s</xliff:g> सेट गर्ने हो?"</string>
<string name="role_sms_request_description" msgid="2691004766132144886">"यो एपलाई क्यामेरा, कन्ट्याक्ट, फाइल तथा मिडिया, माइक्रोफोन, फोन र SMS हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ"</string>
- <string name="role_sms_search_keywords" msgid="8022048144395047352">"टेक्स्ट म्यासेज, टेक्स्ट म्यासेज पठाउने, सन्देशहरू, सन्देश प्रवाह"</string>
+ <string name="role_sms_search_keywords" msgid="8022048144395047352">"टेक्स्ट म्यासेज, टेक्स्ट म्यासेज पठाउने, म्यासेजहरू, सन्देश प्रवाह"</string>
<string name="role_emergency_label" msgid="7028825857206842366">"डिफल्ट आपत्‌कालीन एप"</string>
<string name="role_emergency_short_label" msgid="2388431453335350348">"आपत्‌कालीन एप"</string>
<string name="role_emergency_description" msgid="5051840234887686630">"तपाईंलाई आफ्नो स्वास्थ्यसम्बन्धी जानकारी रेकर्ड गर्न र आपत्‌कालीन अवस्थामा सहयोग गर्ने मान्छेहरूलाई उक्त जानकारीमाथि पहुँच प्रदान गर्न; कठोर मौसम तथा विपत्तिसम्बन्धी अलर्टहरू प्रदान गर्न; तपाईंलाई आवश्यकता पर्दा अरू मान्छेहरूलाई जानकारी दिन अनुमति दिने एपहरू"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"नोट एप"</string>
<string name="role_notes_description" msgid="8496852798616883551">"तपाईंलाई आफ्नो डिभाइसमा नोट बनाउन दिने एपहरू"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"नोटहरू"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"हालको डिफल्ट एप"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"फेरि नसोध्नुहोस्"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"डिफल्ट सेट गर्नुहोस्"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"सहायक ट्रिगर भएको पत्ता लागेमा देखाउनुहोस्"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"आवाज सहायक सक्रिय गर्न माइक्रोफोनको प्रयोग गरिँदा स्टाटस बारमा आइकन देखाउनुहोस्"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई आफ्नो डिभाइसका फोटो र मिडियामाथि पहुँच राख्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>’s&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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> को लोकेसन एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"तपाईं उक्त एप प्रयोग नगरिरहेका बेलामा लगायत जुनसुकै समयमा यो एपले तपाईंको स्थानमाथि पहुँच राख्न सक्छ। "<annotation id="link">"सेटिङमा गई अनुमति दिनुहोस्।"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; का लागि स्थानसम्बन्धी पहुँच परिवर्तन गर्ने हो?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; को लोकेसन एक्सेस गर्न दिइएको अनुमति परिवर्तन गर्ने हो?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"तपाईं उक्त एप प्रयोग नगरिरहेका बेलामा लगायत जुनसुकै समयमा यो एपले तपाईंको स्थानमाथि पहुँच राख्न खोज्छ। "<annotation id="link">"सेटिङमा गई अनुमति दिनुहोस्।"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई नजिकै रहेका डिभाइसहरू भेट्टाउने, ती डिभाइससँग कनेक्ट गर्ने र तिनको सापेक्ष स्थिति निर्धारण गर्ने अनुमति दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा नजिकैका डिभाइसहरू भेट्टाउने, ती डिभाइससँग कनेक्ट गर्ने र तिनको सापेक्ष स्थिति निर्धारण गर्ने अनुमति दिने हो?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई नजिकै रहेका डिभाइसहरू भेट्टाउने, ती डिभाइससँग कनेक्ट गर्ने र तिनको सापेक्ष स्थिति निर्धारण गर्ने अनुमति दिने हो? "<annotation id="link">"सेटिङमा गई अनुमति दिनुहोस्।"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> लाई अनुमानित लोकेसनको साटो सटीक लोकेसन प्रयोग गर्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा SMS म्यासेज पठाउने र हेर्ने अनुमति दिने हो?"</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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएका फोटो, मिडिया तथा फाइलहरू एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई यो डिभाइसमा रहेका &lt;b&gt;फोटो, भिडियो, सङ्गीत र अडियो&lt;/b&gt; प्रयोग गर्न दिने हो?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई यो डिभाइसमा रहेका &lt;b&gt;फोटो, भिडियो, सङ्गीत, अडियो तथा अन्य फाइलहरू&lt;/b&gt; प्रयोग गर्न दिने हो?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई यस डिभाइसमा रहेका सङ्गीत तथा अन्य अडियो फाइलहरू प्रयोग गर्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएका सङ्गीत तथा अडियो एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई यस डिभाइसमा रहेका फोटो र भिडियोहरू प्रयोग गर्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएका फोटो तथा भिडियोहरू एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई यो डिभाइसमा भएका थप फोटो तथा भिडियोहरू प्रयोग गर्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएका थप फोटो तथा भिडियोहरू एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई अडियो रेकर्ड गर्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा अडियो रेकर्ड गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"तपाईंले यो एप प्रयोग गरिरहेका बेलामा मात्र यसले अडियो रेकर्ड गर्न सक्ने छ"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई अडियो रेकर्ड गर्न दिने हो?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा अडियो रेकर्ड गर्ने अनुमति दिने हो?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"तपाईंले यो एप प्रयोग नगरेका बेलामा पनि यसले अडियो रेकर्ड गर्न सक्छ। "<annotation id="link">"सेटिङमा गई यो अनुमति दिनुहोस्।"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई माइक्रोफोन प्रयोग गर्न दिइएको अनुमति परिवर्तन गर्ने हो?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; को माइक्रोफोन एक्सेस गर्न दिइएको अनुमति परिवर्तन गर्ने हो?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"तपाईंले यो एप प्रयोग नगरेका बेलामा पनि यसले अडियो रेकर्ड गर्न चाहन्छ। "<annotation id="link">"सेटिङमा गई यो अनुमति दिनुहोस्।"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई आफ्नो शारीरिक क्रियाकलाप प्रयोग गर्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएको तपाईंको शारीरिक गतिविधिसम्बन्धी डेटा एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई फोटो खिच्न र भिडियो रेकर्ड गर्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा फोटो खिच्ने र भिडियो रेकर्ड गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"तपाईंले यो एप प्रयोग गरिरहेका बेलामा मात्र यसले फोटो खिच्न र भिडियो रेकर्ड गर्न सक्ने छ"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई फोटो खिच्न र भिडियो रेकर्ड गर्न दिने हो?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा फोटो खिच्ने र भिडियो रेकर्ड गर्ने अनुमति दिने हो?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"तपाईंले यो एप प्रयोग नगरेका बेलामा पनि यसले फोटो खिच्न तथा भिडियो रेकर्ड गर्न सक्छ। "<annotation id="link">"सेटिङमा गई यो अनुमति दिनुहोस्।"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई क्यामेरा प्रयोग गर्न दिइएको अनुमति परिवर्तन गर्ने हो?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; को क्यामेरा एक्सेस गर्न दिइएको अनुमति परिवर्तन गर्ने हो?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"तपाईंले यो एप प्रयोग नगरेका बेलामा पनि यसले फोटो खिच्न तथा भिडियो रेकर्ड गर्न चाहन्छ। "<annotation id="link">"सेटिङमा गई यो अनुमति दिनुहोस्।"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई आफ्ना कल लग प्रयोग गर्ने अनुमति दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएका तपाईंका फोन कल लगहरू एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई फोन कल गर्न र ती कलको व्यवस्थापन गर्न दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा फोन कल गर्ने र फोन कलहरू व्यवस्थापन गर्ने अनुमति दिने हो?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई नाडी आदि जस्ता महत्त्वपूर्ण संकेतसम्बन्धी सेन्सर डेटा हेर्ने अनुमति दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएको तपाईंको स्वास्थ्यसम्बन्धी आधारभूत विवरण उपलब्ध गराउने सेन्सरसम्बन्धी डेटा एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"यो एप जुनसुकै बेला (तपाईंले एप प्रयोग नगरेका बेलासमेत) तपाईंका नाडी, धड्कज जस्ता सेन्सर डेटा हेर्न र प्रयोग गर्न चाहन्छ।। यस्तो परिवर्तन गर्न "<annotation id="link">"सेटिङमा जानुहोस्।"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई नाडी, धड्कन जस्ता सेन्सर डेटा प्रयोग गर्न र हेर्न दिने हो?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएको तपाईंको स्वास्थ्यसम्बन्धी आधारभूत विवरण उपलब्ध गराउने सेन्सरसम्बन्धी डेटा एक्सेस गर्ने अनुमति दिने हो?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"यो एपलाई जुनसुकै बेला (तपाईंले एप नचलाएका बेलासमेत) बडी सेन्सरसम्बन्धी डेटा हेर्न र प्रयोग गर्न दिन "<annotation id="link">"सेटिङमा जानुहोस्।"</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"यो एप प्रयोग गरिँदै गरेका बेला यसलाई &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; बडी सेन्सरसम्बन्धी डेटा हेर्ने र प्रयोग गर्ने अनुमति दिइरहने हो?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई यो एप प्रयोग गरिँदै गरेका बेला तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा भएको बडी सेन्सरसम्बन्धी डेटा एक्सेस गर्ने अनुमति दिइरहने हो?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंलाई सूचना पठाउन दिने हो?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; लाई तपाईंको &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; मा सूचना पठाउने अनुमति दिने हो?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"नियन्त्रित अनुमतिहरू"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई लोकेसन प्रयोग गर्ने अनुमति दिइएको छ"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"तपाईंको सङ्गठनले <xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंको लोकेसन प्रयोग गर्ने अनुमति दिएको छ"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"अन्य अनुमतिहरू"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">" सिस्टमले प्रयोग गर्ने अनुमतिहरू"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"सिस्टमका एपहरूमा मात्र प्रयोग गरिने अनुमतिहरू।"</string>
@@ -538,7 +575,7 @@
<string name="privacy_controls_qs" msgid="5780144882040591169">"तपाईंका गोपनीयतासम्बन्धी सेटिङ"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"थप सेटिङ"</string>
<string name="camera_toggle_label_qs" msgid="3880261453066157285">"क्यामेरा प्रयोग गर्ने अनुमति"</string>
- <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"माइक प्रयोग गर्ने अनुमति"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"माइक एक्सेस"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"अनुमति हटाइएको छ"</string>
<string name="camera_usage_qs" msgid="4394233566086665994">"हालसालै गरिएको क्यामेराको प्रयोगसम्बन्धी जानकारी हेर्नुहोस्"</string>
<string name="microphone_usage_qs" msgid="8527666682168170417">"हालसालै गरिएको माइकको प्रयोगसम्बन्धी जानकारी हेर्नुहोस्"</string>
@@ -577,7 +614,7 @@
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"ब्याकग्राउन्डमा लोकेसन प्रयोग गर्ने अनुमति दिइएको एपको समीक्षा गर्नुहोस्"</string>
<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="safety_center_view_recent_location_access" msgid="3524391299490678243">"हालसालै कहिले लोकेसनसम्बन्धी प्रयोग गरिएको थियो हेर्नुहोस्"</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>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"यो एपले यसले लोकेसन डेटा तेस्रो पक्षसँग सेयर गर्न सक्छ भन्ने जानकारी दिएको छ"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"लोकेसन डेटा सेयर गर्नेसम्बन्धी अभ्यास"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"जानकारी सेयर गर्नेसम्बन्धी अभ्यासको स्रोत"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"यो एपका विकासकर्ताले यो एपले जानकारी सेयर गर्ने तरिकाका बारेमा यो डिभाइसका उत्पादकलाई जानकारी दिएका छन्। ती विकासकर्ता भविष्यमा उक्त जानकारी संशोधन गर्न सक्छन्।"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"यो एपका विकासकर्ताले यो एपले जानकारी सेयर गर्ने तरिकाका बारेमा "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" लाई जानकारी दिएका छन्। ती विकासकर्ता समय क्रममा उक्त जानकारी संशोधन गर्न सक्छन्।"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"यो एपले निम्न प्रयोजनका लागि लोकेसन सेयर गर्न सक्छ:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"जानकारी सेयर गर्नेसम्बन्धी अभ्यास फरक हुन सक्छ"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"जानकारीको सुरक्षा"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"लोकेसन डेटा सेयर गरिन सक्छ"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"यो एपले यसले तपाईंको लोकेसन डेटा तेस्रो पक्षसँग सेयर गर्न सक्छ भन्ने जानकारी दिएको छ"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"यो लिंक खोल्न सकिएन"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"लोकेसन डेटा सेयर गर्नेसम्बन्धी अभ्यासका बारेमा अद्यावधिक जानकारी"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"तपाईंको लोकेसन डेटा सेयर गर्न सक्ने तरिका परिवर्तन गरेका एपहरूको समीक्षा गर्नुहोस्"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"यी एपहरूले तपाईंको लोकेसन डेटा सेयर गर्न सक्ने तरिका परिवर्तन गरेका छन्। यी एपहरूले यसअघि तपाईंको लोकेसन डेटा सेयर नगरेका हुन सक्छन् तर अब भने विज्ञापन तथा मार्केटिङ गर्ने प्रयोजनका लागि तपाईंको लोकेसन डेटा सेयर गर्न सक्छन्।"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"जानकारी सेयर गर्नेसम्बन्धी अभ्यासका बारेमा अद्यावधिक जानकारी"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"केही एपहरूले तपाईंको लोकेसन डेटा सेयर गर्न सक्ने तरिका परिवर्तन गरेका छन्"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"सेटिङ"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g> मा एक्सेस गरिएको"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"हिजो <xliff:g id="TIME_DATE">%1$s</xliff:g> मा एक्सेस गरिएको"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g> मा एक्सेस गरिएको"</string>
</resources>
diff --git a/PermissionController/res/values-night-v33/themes.xml b/PermissionController/res/values-night-v33/themes.xml
index 6374ee088..9b6f638a6 100644
--- a/PermissionController/res/values-night-v33/themes.xml
+++ b/PermissionController/res/values-night-v33/themes.xml
@@ -16,10 +16,6 @@
-->
<resources>
- <style name="Theme.SafetyCenterQs" parent="Theme.SafetyCenterQsBase">
- <item name="textColorScSecondaryActionButton">?android:attr/textColorPrimary</item>
- </style>
-
<style name="Theme.SafetyCenterBase" parent="Theme.PermissionController.Settings.FilterTouches">
<item name="colorSurface">@color/sc_surface_dark</item>
<item name="colorSurfaceVariant">@color/sc_surface_variant_dark</item>
@@ -49,8 +45,12 @@
<item name="scStatusButtonStyle">@style/SafetyCenterStatusButton.Responsive</item>
<!-- Buttons -->
- <item name="scActionButtonStyle">@style/SafetyCenterActionButton</item>
- <item name="scSecondaryActionButtonStyle">@style/SafetyCenterActionButton.Secondary</item>
+ <item name="scActionButtonListLayout">@layout/action_button_list_responsive</item>
+ <item name="scActionButtonTheme">@style/Theme.MaterialComponents.DayNight</item>
+ <item name="scActionButtonStyle">@style/SafetyCenterActionButton.Responsive</item>
+ <item name="scSecondaryActionButtonStyle">
+ @style/SecondarySafetyCenterActionButton.Responsive
+ </item>
<item name="textColorScActionButton">@color/sc_primary_action_button_text</item>
<item name="textColorScSecondaryActionButton">?android:attr/textColorPrimary</item>
diff --git a/PermissionController/res/values-night-v34/themes.xml b/PermissionController/res/values-night-v34/themes.xml
index affc57027..b6328d782 100644
--- a/PermissionController/res/values-night-v34/themes.xml
+++ b/PermissionController/res/values-night-v34/themes.xml
@@ -21,11 +21,6 @@
<item name="android:colorBackground">@color/google_grey_800</item>
</style>
- <style name="Theme.SafetyCenterQs" parent="Theme.SafetyCenterQsBase">
- <item name="textColorScSecondaryActionButton">?android:attr/textColorPrimary</item>
- <item name="colorScShieldAccent">@color/sc_shield_accent_dark</item>
- </style>
-
<style name="Theme.SafetyCenter" parent="Theme.SafetyCenterBase">
<item name="colorScShieldAccent">@color/sc_shield_accent_dark</item>
</style>
diff --git a/PermissionController/res/values-nl-v33/strings.xml b/PermissionController/res/values-nl-v33/strings.xml
index df5ad6a15..5b89f1135 100644
--- a/PermissionController/res/values-nl-v33/strings.xml
+++ b/PermissionController/res/values-nl-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Meer meldingen"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Gesloten meldingen"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Uitvouwen en nog 1 melding bekijken}other{Uitvouwen en nog # meldingen bekijken}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Waarschuwing. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Actie afgerond"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Check de instellingen die je apparaat beter kunnen beschermen"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Snelle instellingen voor beveiliging en privacy"</string>
diff --git a/PermissionController/res/values-nl-v34/strings.xml b/PermissionController/res/values-nl-v34/strings.xml
index a695de975..b3265d254 100644
--- a/PermissionController/res/values-nl-v34/strings.xml
+++ b/PermissionController/res/values-nl-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Beveiliging en privacy"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Bediening"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Toegang van app tot gezondheidsgegevens beheren"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Beheer de toegang van apps tot je gezondheidsgegevens"</string>
<string name="location_settings" msgid="8863940440881290182">"Locatietoegang"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"Voor apps en services. Als deze instelling uitstaat, kunnen microfoongegevens nog altijd worden gedeeld als je een alarmnummer belt."</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Voor apps en services"</string>
diff --git a/PermissionController/res/values-nl/strings.xml b/PermissionController/res/values-nl/strings.xml
index e7c8a81b0..b79fdc98f 100644
--- a/PermissionController/res/values-nl/strings.xml
+++ b/PermissionController/res/values-nl/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Meer informatie"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Alles toestaan"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Altijd alles toestaan"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Beperkte toegang toestaan"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Foto\'s en video\'s selecteren"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Meer selecteren"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Niet meer selecteren"</string>
@@ -41,7 +42,7 @@
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Sluiten"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> van <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; het volgende toestaan: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; altijd toestaan om <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; altijd het volgende toestaan: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Alleen als app in gebruik is"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Altijd"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Niet toestaan en niet meer vragen"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"App-rechten"</string>
<string name="unused_apps" msgid="2058057455175955094">"Niet-gebruikte apps"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Bewerk geselecteerde foto\'s voor deze app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Geen niet-gebruikte apps"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 niet-gebruikte apps"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Recente rechtenbeslissingen"</string>
@@ -71,7 +73,7 @@
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{Vandaag}=1{1 dag geleden}other{# dagen geleden}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"App uitzetten"</string>
<string name="app_disable_dlg_text" msgid="3126943217146120240">"Als je deze app uitzet, werken Android en andere apps mogelijk niet meer zoals bedoeld. Je kunt deze app niet verwijderen omdat deze vooraf geïnstalleerd was op je apparaat. Door de app uit te zetten verberg je deze ook op je apparaat."</string>
- <string name="app_permission_manager" msgid="3903811137630909550">"Rechtenbeheer"</string>
+ <string name="app_permission_manager" msgid="3903811137630909550">"Rechten­beheer"</string>
<string name="never_ask_again" msgid="4728762438198560329">"Niet meer vragen"</string>
<string name="no_permissions" msgid="3881676756371148563">"Geen rechten"</string>
<string name="additional_permissions" msgid="5801285469338873430">"Aanvullende rechten"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Altijd toestaan"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Toestaan bij gebruik van app"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Alleen toestaan bij gebruik van app"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Niet toestaan"</string>
<string name="loading" msgid="4789365003890741082">"Laden…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Alle rechten"</string>
<string name="other_permissions" msgid="2901186127193849594">"Andere app-mogelijkheden"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Rechtenverzoek"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Acties voor installeren/verwijderen niet ondersteund op Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Kiezen waartoe &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang krijgt"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; is geüpdatet. Kies waartoe je deze app toegang wilt geven."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Annuleren"</string>
@@ -195,7 +195,7 @@
<string name="approximate_image_description" msgid="938803699637069884">"Geschatte locatie"</string>
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"Exacte locatie gebruiken"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Als de exacte locatie uitstaat, hebben apps toegang tot je geschatte locatie"</string>
- <string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g>-rechten"</string>
+ <string name="app_permission_title" msgid="2090897901051370711">"Rechten: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_header" msgid="2951363137032603806">"Toegang tot <xliff:g id="PERM">%1$s</xliff:g> voor deze app"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Alle rechten van <xliff:g id="APP">%1$s</xliff:g> bekijken"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Alle apps met dit recht bekijken"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Rechten intrekken als app niet wordt gebruikt"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Rechten intrekken en ruimte vrijmaken"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"App-activiteit onderbreken indien niet gebruikt"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"App beheren indien ongebruikt"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Verwijder rechten en tijdelijke bestanden, en stop meldingen"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Verwijder rechten en tijdelijke bestanden, stop meldingen en archiveer de app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Om je gegevens te beschermen worden de rechten voor deze app verwijderd als de app een aantal maanden niet is gebruikt."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Om je gegevens te beschermen worden de volgende rechten ingetrokken als de app een paar maanden niet is gebruikt: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Om je gegevens te beschermen zijn de rechten verwijderd van apps die al een paar maanden niet zijn gebruikt."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Notitie-app"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps waarmee je notities op je apparaat kunt maken"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notities"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Huidige standaard-app"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Niet meer vragen"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Standaard instellen"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Activeringsdetectie van de assistent tonen"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Icoon op statusbalk tonen als microfoon wordt gebruikt om de Spraakassistent te activeren"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot foto\'s en media op je apparaat?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot foto\'s en media op je &lt;b&gt;<xliff:g id="DEVICE">%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; toegang geven tot je contacten?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot de contacten op je &lt;b&gt;<xliff:g id="DEVICE">%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; toegang geven tot de locatie van dit apparaat?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot de locatie van je &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"De app heeft alleen toegang tot de locatie wanneer je de app gebruikt"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot de locatie van dit apparaat?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot de locatie van je &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Deze app wil mogelijk altijd toegang tot je locatie, ook als je de app niet gebruikt. "<annotation id="link">"Je kunt dit toestaan via de instellingen."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Toegang tot locatie wijzigen voor &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Toegang tot locatie wijzigen voor &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Deze app wil altijd toegang tot je locatie, ook als je de app niet gebruikt. "<annotation id="link">"Je kunt dit toestaan via de instellingen."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Toestaan dat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; apparaten in de buurt vindt, er verbinding mee maakt en de relatieve positie bepaalt?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Toestaan dat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; apparaten in de buurt vindt, ermee verbinding maakt en de relatieve positie ervan bepaalt op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Toestaan dat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; apparaten in de buurt vindt, er verbinding mee maakt en de relatieve positie bepaalt? "<annotation id="link">"Toestaan in Instellingen"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Locatietoegang van <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> wijzigen van geschatte in exacte locatie?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Locatietoegang van <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; wijzigen van geschat in exact?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot de geschatte locatie van dit apparaat?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot de geschatte locatie van je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exact"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Geschat"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot je agenda?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot de agenda op je &lt;b&gt;<xliff:g id="DEVICE">%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; toestaan om sms\'jes te verzenden en te bekijken?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om sms-berichten te sturen en te bekijken op je &lt;b&gt;<xliff:g id="DEVICE">%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; toegang geven tot foto\'s, media en bestanden op je apparaat?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot foto\'s, media en bestanden op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot &lt;b&gt;foto\'s, video\'s, muziek en audio&lt;/b&gt; op dit apparaat?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot &lt;b&gt;foto\'s, video\'s, muziek, audio en andere bestanden&lt;/b&gt; op dit apparaat?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot muziek en audio op dit apparaat?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot muziek en audio op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot foto\'s en video\'s op dit apparaat?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot foto\'s en video\'s op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot meer foto\'s en video\'s op dit apparaat?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot meer foto\'s en video\'s op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om audio op te nemen?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om audio op te nemen op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Deze app kan alleen audio opnemen als je de app gebruikt"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om audio op te nemen?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om audio op te nemen op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Deze app wil mogelijk altijd audio opnemen, ook als je de app niet gebruikt. "<annotation id="link">"Toestaan in instellingen."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Toegang tot microfoon wijzigen voor &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Toegang tot microfoon wijzigen voor &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Deze app wil altijd audio opnemen, ook als je de app niet gebruikt. "<annotation id="link">"Toestaan in instellingen."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot je fysieke activiteit?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot je fysieke activiteit op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om foto\'s te maken en video\'s op te nemen?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om foto\'s te maken en video\'s op te nemen op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Deze app kan alleen foto\'s maken en video\'s opnemen als je de app gebruikt"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om foto\'s te maken en video\'s op te nemen?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om foto\'s te maken en video\'s op te nemen op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Deze app wil mogelijk altijd foto\'s maken en video\'s opnemen, ook als je de app niet gebruikt. "<annotation id="link">"Toestaan in Instellingen."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Toegang tot camera wijzigen voor &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Toegang tot camera wijzigen voor &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Deze app wil altijd foto\'s maken en video\'s opnemen, ook als je de app niet gebruikt. "<annotation id="link">"Toestaan in Instellingen."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot je gesprekslijsten?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot de gesprekslijsten op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om telefoongesprekken te starten en te beheren?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om telefoongesprekken te starten en te beheren op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot sensorgegevens over je vitale functies?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot sensorgegevens over je vitale functies op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Deze app wil altijd toegang tot gegevens van lichaamssensoren over je vitale functies, ook als je de app niet gebruikt. "<annotation id="link">"Ga naar Instellingen"</annotation>" als je deze wijziging wilt doorvoeren."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot sensorgegevens over je vitale functies?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang geven tot sensorgegevens over je vitale functies op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Als je deze app altijd toegang tot gegevens van lichaamssensoren wilt geven, ook als je de app niet gebruikt, "<annotation id="link">"ga je naar Instellingen"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Instelling behouden dat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot gegevens van lichaamssensoren heeft als de app wordt gebruikt?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Blijven toestaan dat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toegang tot gegevens van lichaamssensoren op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; heeft als de app wordt gebruikt?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Toestaan dat &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; je meldingen stuurt?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; toestaan om je meldingen te sturen op je &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Beheerde rechten"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> heeft toegang tot je locatie"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Je organisatie geeft <xliff:g id="APP_NAME">%1$s</xliff:g> toegang tot je locatie"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Overige rechten"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Recht gebruikt door het systeem"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Rechten alleen gebruikt door systeem-apps."</string>
@@ -572,9 +609,9 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Deze app ondersteunt de nieuwste versie van Android niet. Als deze app geen toegang heeft tot muziek- en audiobestanden, heeft deze ook geen toegang tot foto\'s en video\'s."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Deze app ondersteunt de nieuwste versie van Android niet. Als deze app toegang heeft tot foto\'s en video\'s, heeft deze ook toegang tot muziek- en audiobestanden."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Deze app ondersteunt de nieuwste versie van Android niet. Als deze app geen toegang heeft tot muziek- en audiobestanden, heeft deze ook geen toegang tot foto\'s en video\'s."</string>
- <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Apps met toegang tot locatie op de achtergrond bekijken"</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"App met toegang tot locatie op de achtergrond doornemen"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> heeft altijd toegang tot je locatie, ook als de app gesloten is"</string>
- <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Apps met toegang tot locatie op de achtergrond bekijken"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"App met toegang tot locatie op de achtergrond doornemen"</string>
<string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Deze app heeft altijd toegang tot je locatie, ook als de app gesloten is.\n\nBepaalde veiligheids- en nood-apps hebben op de achtergrond toegang tot je locatie nodig voor een juiste werking."</string>
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Toegang gewijzigd"</string>
<string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Recent locatiegebruik bekijken"</string>
@@ -587,10 +624,11 @@
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Toegang tot klembord tonen"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Toon een bericht als apps toegang hebben tot tekst, afbeeldingen of andere content die je hebt gekopieerd"</string>
<string name="show_password_title" msgid="2877269286984684659">"Wachtwoorden tonen"</string>
- <string name="show_password_summary" msgid="1110166488865981610">"Tekens kort tonen terwijl je typt"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Geef tekens kort weer terwijl je typt"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Deze app geeft aan dat locatiegegevens kunnen worden gedeeld met derden"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Gegevens delen en locatie"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Waar informatie over gegevens delen vandaan komt"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"De ontwikkelaar heeft de fabrikant van het apparaat informatie gegeven over de manier waarop deze app gegevens deelt. De ontwikkelaar kan deze informatie in de loop van de tijd updaten."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"De ontwikkelaar heeft informatie gegeven aan "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" over hoe deze app gegevens deelt. De ontwikkelaar kan deze informatie in de loop van de tijd updaten."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Deze app kan locatiegegevens delen voor:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Gegevens delen verschilt"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Veiligheid van gegevens"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Locatiegegevens kunnen worden gedeeld"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Deze app geeft aan dat je locatiegegevens met derden kunnen worden gedeeld"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Link kan niet worden geopend"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Updates voor het delen van locatiegegevens"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Check apps die de manier hebben veranderd waarop je locatiegegevens worden gedeeld"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Deze apps hebben de manier veranderd waarop ze je locatiegegevens kunnen delen. Misschien deelden ze de gegevens eerder niet, of kunnen ze deze nu delen voor reclame- en marketingdoeleinden."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Updates voor gegevens delen"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Sommige apps kunnen je locatiegegevens nu op een andere manier delen"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Instellingen"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Geopend: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Geopend: gisteren om <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Geopend: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> om <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-or-v33/strings.xml b/PermissionController/res/values-or-v33/strings.xml
index 21b7042f4..84c07b84e 100644
--- a/PermissionController/res/values-or-v33/strings.xml
+++ b/PermissionController/res/values-or-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"ଅଧିକ ଆଲର୍ଟ"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"ଖାରଜ କରାଯାଇଥିବା ଆଲର୍ଟଗୁଡ଼ିକ"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{ବିସ୍ତାର କରି ଆଉ ଗୋଟିଏ ଆଲର୍ଟ ଦେଖନ୍ତୁ}other{ବିସ୍ତାର କରି ଆଉ #ଟି ଆଲର୍ଟ ଦେଖନ୍ତୁ}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"ଆଲର୍ଟ। <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"କାର୍ଯ୍ୟ ସମୂର୍ଣ୍ଣ ହୋଇଛି"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"ଆପଣଙ୍କ ଡିଭାଇସରେ ସୁରକ୍ଷା ଯୋଗ କରୁଥିବା ସେଟିଂସକୁ ଦେଖନ୍ତୁ"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"ସୁରକ୍ଷା ଏବଂ ଗୋପନୀୟତା କ୍ୱିକ ସେଟିଂସ"</string>
diff --git a/PermissionController/res/values-or-v34/strings.xml b/PermissionController/res/values-or-v34/strings.xml
index dab5f74f9..2994a3f25 100644
--- a/PermissionController/res/values-or-v34/strings.xml
+++ b/PermissionController/res/values-or-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"ସୁରକ୍ଷା ଏବଂ ଗୋପନୀୟତା"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"ସ୍ୱାସ୍ଥ୍ୟ ଡାଟାକୁ ଆପର ଆକ୍ସେସକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"ସ୍ୱାସ୍ଥ୍ୟ ଡାଟା ପାଇଁ ଆପର ଆକ୍ସେସକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="location_settings" msgid="8863940440881290182">"ଲୋକେସନ ଆକ୍ସେସ"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"ଆପ୍ସ ଏବଂ ସେବାଗୁଡ଼ିକ ପାଇଁ। ଯଦି ଏହି ସେଟିଂ ବନ୍ଦ ଥାଏ, ତେବେ ଆପଣ ଏକ ଜରୁରୀକାଳୀନ ନମ୍ବରକୁ କଲ କରିବା ସମୟରେ ମାଇକ୍ରୋଫୋନ ଡାଟା ଏବେ ବି ସେୟାର କରାଯାଇପାରେ"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"ଆପ୍ସ ଏବଂ ସେବାଗୁଡ଼ିକ ପାଇଁ"</string>
diff --git a/PermissionController/res/values-or-watch/strings.xml b/PermissionController/res/values-or-watch/strings.xml
index b5c17dbb0..ef9515f25 100644
--- a/PermissionController/res/values-or-watch/strings.xml
+++ b/PermissionController/res/values-or-watch/strings.xml
@@ -21,5 +21,5 @@
<string name="preference_show_system_apps" msgid="1055740303992024300">"ସିଷ୍ଟମ୍‍ ଆପ୍ସ ଦେଖାନ୍ତୁ"</string>
<string name="permission_summary_enforced_by_policy" msgid="2352478756952948019">"ଏହା ବଦଳାଯାଇପାରିବ ନାହିଁ"</string>
<string name="generic_yes" msgid="2489207724988649846">"ହଁ"</string>
- <string name="generic_cancel" msgid="2631708607129269698">"ବାତିଲ"</string>
+ <string name="generic_cancel" msgid="2631708607129269698">"ବାତିଲ କରନ୍ତୁ"</string>
</resources>
diff --git a/PermissionController/res/values-or/strings.xml b/PermissionController/res/values-or/strings.xml
index e56b39141..5be6ff200 100644
--- a/PermissionController/res/values-or/strings.xml
+++ b/PermissionController/res/values-or/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"ଅଧିକ ସୂଚନା"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"ସବୁକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"ସର୍ବଦା ସବୁକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"ସୀମିତ ଆକ୍ସେସକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ଫଟୋ ଏବଂ ଭିଡିଓଗୁଡ଼ିକୁ ଚୟନ କରନ୍ତୁ"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"ଅଧିକ ଚୟନ କରନ୍ତୁ"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ଅଧିକ ଚୟନ କରନ୍ତୁ ନାହିଁ"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"ଯେ କୌଣସି ମତେ ଅନୁମତି ଦିଅ ନାହିଁ"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"ଖାରଜ କରନ୍ତୁ"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> ରୁ <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ <xliff:g id="ACTION">%2$s</xliff:g> ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ସବୁବେଳେ <xliff:g id="ACTION">%2$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ <xliff:g id="ACTION">%2$s</xliff:g> ପାଇଁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ସବୁବେଳେ <xliff:g id="ACTION">%2$s</xliff:g> ପାଇଁ ଅନୁମତି ଦେବେ?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"କେବଳ ଆପ୍‍ ବ୍ୟବହାର ସମୟରେ"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"ସର୍ବଦା"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ ଏବଂ ପୁଣି ପଚାରନ୍ତୁ ନାହିଁ"</string>
@@ -59,7 +60,8 @@
<string name="grant_dialog_button_allow_media_only" msgid="4832877658422573832">"ମିଡିଆ ଫାଇଲଗୁଡ଼ିକୁ ଆକ୍ସେସ୍ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ଆପ୍ସ"</string>
<string name="app_permissions" msgid="3369917736607944781">"ଆପ ଅନୁମତିଗୁଡ଼ିକ"</string>
- <string name="unused_apps" msgid="2058057455175955094">"ଅବ୍ୟବହୃତ ଆପଗୁଡ଼ିକ"</string>
+ <string name="unused_apps" msgid="2058057455175955094">"ଅବ୍ୟବହୃତ ଆପ୍ସ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ଏହି ଆପ ପାଇଁ ଚୟନିତ ଫଟୋଗୁଡ଼ିକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="no_unused_apps" msgid="12809387670415295">"କୌଣସି ଅବ୍ୟବହୃତ ଆପ୍ ନାହିଁ"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0ଟି ଅବ୍ୟବହୃତ ଆପ୍"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"ବର୍ତ୍ତମାନର ଅନୁମତି ନିଷ୍ପତ୍ତି"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"ସର୍ବଦା ଅନୁମତି ଦିଅନ୍ତୁ"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"ଆପ୍ ବ୍ୟବହାର ବେଳେ କେବଳ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"ଆପ ବ୍ୟବହାର ବେଳେ କେବଳ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="permission_access_never" msgid="4647014230217936900">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
<string name="loading" msgid="4789365003890741082">"ଲୋଡ୍ ହେଉଛି…"</string>
<string name="all_permissions" msgid="6911125611996872522">"ସମସ୍ତ ଅନୁମତିଗୁଡ଼ିକ"</string>
<string name="other_permissions" msgid="2901186127193849594">"ଅନ୍ୟାନ୍ୟ ଆପ୍‍ ଦକ୍ଷତା"</string>
<string name="permission_request_title" msgid="8790310151025020126">"ଅନୁମତି ଅନୁରୋଧ"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android ୱିୟର୍‌"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"ୱିୟର୍‌ରେ ଇନଷ୍ଟଲ୍‍/ଅନଇନଷ୍ଟଲ୍‍ କାର୍ଯ୍ୟଗୁଡ଼ିକ ସମର୍ଥନ କରେନାହିଁ।"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ଆକ୍ସେସ୍‍ କରିବା ପାଇଁ କେଉଁସବୁ ଅନୁମତି ଦିଆଯିବ, ତାହା ବାଛନ୍ତୁ"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ଅପଡେଟ୍‍ କରାଯାଇଛି। ଏହି ଆପ୍‍ କେଉଁସବୁ ଆକ୍ସେସ୍‍ କରିପାରିବ, ତାହା ବାଛନ୍ତୁ।"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"ବାତିଲ କରନ୍ତୁ"</string>
@@ -124,7 +124,7 @@
<string name="current_permissions_category" msgid="4292990083585728880">"ବର୍ତ୍ତମାନର ଅନୁମତିଗୁଡ଼ିକ"</string>
<string name="message_staging" msgid="9110563899955511866">"ଆପ୍‍ ପର୍ଯ୍ୟାୟଭୁକ୍ତ କରାଯାଉଛି…"</string>
<string name="app_name_unknown" msgid="1319665005754048952">"ଅଜଣା"</string>
- <string name="permission_usage_title" msgid="1568233336351734538">"ଗୋପନୀୟତା ଡ୍ୟାସବୋର୍ଡ"</string>
+ <string name="permission_usage_title" msgid="1568233336351734538">"ଗୋପନୀୟତା ଡେସବୋର୍ଡ"</string>
<string name="auto_permission_usage_summary" msgid="7335667266743337075">"କେଉଁ ଆପଗୁଡ଼ିକ ଏବେ ଅନୁମତିଗୁଡ଼ିକ ବ୍ୟବହାର କରିଛି ତାହା ଦେଖନ୍ତୁ"</string>
<string name="permission_group_usage_title" msgid="2595013198075285173">"<xliff:g id="PERMGROUP">%1$s</xliff:g> ବ୍ୟବହାର"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"ଅନ୍ୟ ଅନୁମତିଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
@@ -187,7 +187,7 @@
<string name="app_permission_button_allow_all_files" msgid="1792232272599018825">"ସମସ୍ତ ଫାଇଲର ପରିଚାଳନା ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"କେବଳ ମିଡିଆକୁ ଆକ୍ସେସ୍ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"ସବୁ ସମୟ ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
- <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"ଆପ୍ ବ୍ୟବହାର ବେଳେ କେବଳ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"ଆପ ବ୍ୟବହାର ବେଳେ କେବଳ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"ସର୍ବଦା ସବୁକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ପ୍ରତ୍ୟେକ ଥର ପଚାରନ୍ତୁ"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
@@ -196,7 +196,7 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"ସଠିକ୍ ଲୋକେସନ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"ଯେତେବେଳେ ସଠିକ୍ ଲୋକେସନ୍ ବନ୍ଦ ଥାଏ, ସେତେବେଳେ ଆପଗୁଡ଼ିକ ଆପଣଙ୍କ ଆନୁମାନିକ ଲୋକେସନକୁ ଆକ୍ସେସ୍ କରିପାରିବ"</string>
<string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g> ଅନୁମତି"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"ଏହି ଆପ ପାଇଁ <xliff:g id="PERM">%1$s</xliff:g> ଆକ୍ସେସକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"ଏହି ଆପ ପାଇଁ <xliff:g id="PERM">%1$s</xliff:g>ର ଆକ୍ସେସ"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"ସମସ୍ତ <xliff:g id="APP">%1$s</xliff:g> ଅନୁମତି ଦେଖନ୍ତୁ"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"ଏହି ଅନୁମତି ଥିବା ସମସ୍ତ ଆପ୍ସ ଦେଖନ୍ତୁ"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Assistant ମାଇକ୍ରୋଫୋନ୍ ବ୍ୟବହାର ଦେଖାନ୍ତୁ"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ଯଦି ଆପ୍ ବ୍ୟବହାର କରାଯାଇନାହିଁ, ତେବେ ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ସ୍ପେସ୍ ଖାଲି କରନ୍ତୁ"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"ବ୍ୟବହାର ହେଉନଥିଲେ ଆପ କାର୍ଯ୍ୟକଳାପ ବିରତ କରନ୍ତୁ"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ଆପକୁ ବ୍ୟବହାର କରାଯାଉନଥିଲେ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଅନ୍ତୁ, ଅସ୍ଥାୟୀ ଫାଇଲଗୁଡ଼ିକୁ ଡିଲିଟ କରନ୍ତୁ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଅନ୍ତୁ, ଅସ୍ଥାୟୀ ଫାଇଲଗୁଡ଼ିକୁ ଡିଲିଟ କରନ୍ତୁ, ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବନ୍ଦ କରନ୍ତୁ ଏବଂ ଆପକୁ ଆର୍କାଇଭ କରନ୍ତୁ"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"ଯଦି ଏହି ଆପକୁ କିଛି ମାସ ପାଇଁ ବ୍ୟବହାର କରାଯାଇନାହିଁ, ତେବେ ଆପଣଙ୍କ ଡାଟାର ସୁରକ୍ଷା ନିମନ୍ତେ ଏହାର ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯିବ।"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"ଯଦି ଏହି ଆପକୁ କିଛି ମାସ ପାଇଁ ବ୍ୟବହାର କରାଯାଇନାହିଁ ତେବେ ଆପଣଙ୍କ ଡାଟାର ସୁରକ୍ଷା ନିମନ୍ତେ, ନିମ୍ନୋକ୍ତ ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯିବ: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"ଆପଣଙ୍କ ଡାଟାର ସୁରକ୍ଷା ପାଇଁ, ଆପଣ କିଛି ମାସ ହେଲା ବ୍ୟବହାର କରିନଥିବା ଆପଗୁଡ଼ିକରୁ ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯାଇଛି।"</string>
@@ -218,7 +220,7 @@
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> ଅନୁମତିକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> ଏବଂ <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> ଅନୁମତିକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> ଏବଂ ଅନ୍ୟ <xliff:g id="NUMBER">%2$s</xliff:g>ଟି ଅନୁମତି କାଢ଼ି ଦିଆଯାଇଛି"</string>
- <string name="unused_apps_page_title" msgid="6986983535677572559">"ଅବ୍ୟବହୃତ ଆପଗୁଡ଼ିକ"</string>
+ <string name="unused_apps_page_title" msgid="6986983535677572559">"ଅବ୍ୟବହୃତ ଆପ୍ସ"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"ଯଦି ଏକ ଆପ୍ କିଛି ମାସ ପାଇଁ ଅବ୍ୟବହୃତ ଅଛି, ତେବେ:\n\n• ଆପଣଙ୍କ ଡାଟାକୁ ସୁରକ୍ଷା ଦେବା ପାଇଁ ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯାଏ\n• ବ୍ୟାଟେରୀ ସେଭ୍ କରିବାକୁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବନ୍ଦ କରାଯାଏ\n• ସ୍ପେସ୍ ଖାଲି କରିବା ପାଇଁ ଅସ୍ଥାୟୀ ଫାଇଲଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯାଏ\n\nଅନୁମତି ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ପୁଣି ଅନୁମତି ଦେବା ପାଇଁ, ଆପ୍ ଖୋଲନ୍ତୁ।"</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"ଯଦି କୌଣସି ଆପକୁ ଏକ ମାସ ପାଇଁ ବ୍ୟବହାର କରାଯାଇନାହିଁ, ତେବେ:\n\n• ଆପଣଙ୍କ ଡାଟାକୁ ସୁରକ୍ଷିତ ରଖିବା ପାଇଁ ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯାଏ\n• ସ୍ପେସ ଖାଲି କରିବା ପାଇଁ ଅସ୍ଥାୟୀ ଫାଇଲଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯାଏ\n\nପୁଣି ଅନୁମତିଗୁଡ଼ିକ ଦେବା ପାଇଁ, ଆପକୁ ଖୋଲନ୍ତୁ।"</string>
<string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{# ମାସରୁ ଅଧିକ ସମୟ ପୂର୍ବେ ଖୋଲାଯାଇଥିଲା}other{# ମାସରୁ ଅଧିକ ସମୟ ପୂର୍ବେ ଖୋଲାଯାଇଥିଲା}}"</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"ଗତ ଥର <xliff:g id="DATE">%s</xliff:g>ରେ ଖୋଲାଯାଇଥିଲା"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"ଯଦି ଆପଣ ସମସ୍ତ ଫାଇଲର ପରିଚାଳନାକୁ ଅନୁମତି ଦିଅନ୍ତି, ତେବେ ଏହି ଆପ୍ ଏ ଡିଭାଇସ୍ କିମ୍ବା ସଂଯୋଗ ହୋଇଥିବା ଷ୍ଟୋରେଜ୍ ଡିଭାଇସର ସାଧାରଣ ଷ୍ଟୋରେଜରେ ଥିବା ଯେ କୌଣସି ଫାଇଲକୁ ଆକ୍ସେସ୍, ପରିବର୍ତ୍ତନ ଏବଂ ଡିଲିଟ୍ କରିପାରିବ। ଆପଟି ଆପଣଙ୍କୁ ନ ପଚାରି ଫାଇଲଗୁଡ଼ିକୁ ଆକ୍ସେସ୍ କରିପାରେ।"</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"ଏହି ଆପକୁ ଏ ଡିଭାଇସରେ କିମ୍ବା ଯେ କୌଣସି ସଂଯୋଗ ହୋଇଥିବା ଷ୍ଟୋରେଜ୍ ଡିଭାଇସଗୁଡ଼ିକରେ ଥିବା ଫାଇଲଗୁଡ଼ିକୁ ଆକ୍ସେସ୍, ପରିବର୍ତ୍ତନ ଏବଂ ଡିଲିଟ୍ କରିବାକୁ ଅନୁମତି ଦେବେ କି? ଏହି ଆପ୍ ଆପଣଙ୍କୁ ନ ପଚାରି ଫାଇଲଗୁଡ଼ିକୁ ଆକ୍ସେସ୍ କରିପାରେ।"</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"ଏହି ଅନୁମତି ଥିବା ଆପ୍ସ <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"ଏହି ଅନୁମତି ଥିବା ଆପ୍ସ ଏହା କରିପାରିବ <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"ଏହି ଅନୁମତି ସହିତ ଆପଗୁଡ଼ିକ, ଚାଲିବା, ବାଇକ୍ ଚଲାଇବା, ଡ୍ରାଇଭିଂ, ଷ୍ଟେପ୍ ଗଣନା ଏବଂ ଆହୁରି ଅନେକ କିଛି ପରି ଆପଣଙ୍କ ଶାରୀରିକ କାର୍ଯ୍ୟକଳାପକୁ ଆକ୍ସେସ୍ କରିପାରିବ"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"ଏହି ଅନୁମତି ଥିବା ଆପ୍ସ ଆପଣଙ୍କର କ୍ୟାଲେଣ୍ଡର୍ ଆକ୍ସେସ୍ କରିପାରିବ"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"ଏହି ଅନୁମତି ଥିବା ଆପ୍‌ଗୁଡ଼ିକ ଫୋନ୍‌ କଲ୍ ଲଗ୍ ପଢ଼ିପାରିବେ ଏବଂ ଲେଖିପାରିବେ"</string>
@@ -302,7 +304,7 @@
<string name="auto_revoke_before_notification_title_one" msgid="6758024954464359876">"1ଟି ଆପ୍ ବ୍ୟବହାର କରାଯାଇନାହିଁ"</string>
<string name="auto_revoke_before_notification_title_many" msgid="4415543943846385685">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g>ଟି ଆପ୍ ବ୍ୟବହାର କରାଯାଇନାହିଁ"</string>
<string name="auto_revoke_before_notification_content_one" msgid="1156635373417068822">"ଆପଣଙ୍କ ଗୋପନୀୟତାକୁ ସୁରକ୍ଷା ଦେବା ପାଇଁ ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯିବ। ସମୀକ୍ଷା କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
- <string name="unused_apps_title" msgid="8589298917717872239">"ଅବ୍ୟବହୃତ ଆପଗୁଡ଼ିକ"</string>
+ <string name="unused_apps_title" msgid="8589298917717872239">"ଅବ୍ୟବହୃତ ଆପ୍ସ"</string>
<string name="unused_apps_subtitle_after" msgid="2034267519506357898">"ଏଥିରୁ ଅନୁମତିଗୁଡ଼ିକ କାଢ଼ି ଦିଆଯାଇଛି"</string>
<string name="unused_apps_subtitle_before" msgid="5233302577076132427">"ଏଥିରୁ ଅନୁମତିଗୁଡ଼ିକ କାଢ଼ି ଦିଆଯିବ"</string>
<string name="unused_permissions_subtitle_two" msgid="2207266295008423015">"<xliff:g id="PERM_NAME_0">%1$s</xliff:g> ଏବଂ <xliff:g id="PERM_NAME_1">%2$s</xliff:g>"</string>
@@ -315,7 +317,7 @@
<string name="permission_subtitle_media_only" msgid="8917869683764720717">"ମିଡିଆ"</string>
<string name="permission_subtitle_all_files" msgid="4982613338298067862">"ସମସ୍ତ ଫାଇଲ୍"</string>
<string name="permission_subtitle_background" msgid="8916750995309083180">"ସର୍ବଦା ଅନୁମତି ଦିଆଯାଇଛି"</string>
- <string name="app_perms_24h_access" msgid="99069906850627181">"<xliff:g id="TIME_DATE">%1$s</xliff:g>ରେ ଗତଥର ଆକ୍ସେସ୍ କରାଯାଇଛି"</string>
+ <string name="app_perms_24h_access" msgid="99069906850627181">"<xliff:g id="TIME_DATE">%1$s</xliff:g>ରେ ଗତଥର ଆକ୍ସେସ କରାଯାଇଛି"</string>
<string name="app_perms_24h_access_yest" msgid="5411926024794555022">"ଗତକାଲି <xliff:g id="TIME_DATE">%1$s</xliff:g>ରେ ଗତଥର ଆକ୍ସେସ୍ କରାଯାଇଛି"</string>
<string name="app_perms_7d_access" msgid="4945055548894683751">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>ରେ ଗତଥର ଆକ୍ସେସ କରାଯାଇଛି"</string>
<string name="app_perms_content_provider_24h" msgid="1055526027667508972">"ଗତ 24 ଘଣ୍ଟାରେ ଆକ୍ସେସ କରାଯାଇଛି"</string>
@@ -337,7 +339,7 @@
<string name="app_perms_content_provider_7d_all_files" msgid="7962416229708835558">"ଗତ 7 ଦିନରେ ଆକ୍ସେସ କରାଯାଇଛି • ସମସ୍ତ ଫାଇଲ"</string>
<string name="no_permissions_allowed" msgid="6081976856354669209">"କୌଣସି ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
<string name="no_permissions_denied" msgid="8159923922804043282">"କୌଣସି ଅନୁମତି ଅଗ୍ରାହ୍ୟ କରାଯାଇନାହିଁ"</string>
- <string name="no_apps_allowed" msgid="7718822655254468631">"କୌଣସି ଆପକୁ ଅନୁମତି ନାହିଁ"</string>
+ <string name="no_apps_allowed" msgid="7718822655254468631">"କୌଣସି ଆପ୍ସକୁ ଅନୁମତି ନାହିଁ"</string>
<string name="no_apps_allowed_full" msgid="8011716991498934104">"ସମସ୍ତ ଫାଇଲ୍ ପାଇଁ କୌଣସି ଆପକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
<string name="no_apps_allowed_scoped" msgid="4908850477787659501">"କେବଳ ମିଡିଆ ପାଇଁ କୌଣସି ଆପକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
<string name="no_apps_denied" msgid="7663435886986784743">"କୌଣସି ଆପକୁ ଅଗ୍ରାହ୍ୟ କରାଯାଇନାହିଁ"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"ନୋଟ୍ସ ଆପ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଆପଣଙ୍କୁ ନୋଟ ନେବା ପାଇଁ ଅନୁମତି ଦେଉଥିବା ଆପ୍ସ"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ନୋଟ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"ସମ୍ପ୍ରତ୍ତି ଡିଫଲ୍ଟ"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"ଆଉ ପଚାରନ୍ତୁ ନାହିଁ"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ଡିଫଲ୍ଟ ଭାବେ ସେଟ୍ କରନ୍ତୁ"</string>
@@ -426,7 +438,7 @@
<string name="default_apps_more" msgid="4078194675848858093">"ଅଧିକ ଡିଫଲ୍ଟଗୁଡ଼ିକ"</string>
<string name="default_apps_manage_domain_urls" msgid="6775566451561036069">"ଓପନିଂ ଲିଙ୍କ୍"</string>
<string name="default_apps_for_work" msgid="4970308943596201811">"କାର୍ଯ୍ୟ ପାଇଁ ଡିଫଲ୍ଟ ଅଛି"</string>
- <string name="default_app_none" msgid="9084592086808194457">"କିଛି ଆପ୍‌ ସେଟ୍‌ କରାଯାଇନାହିଁ"</string>
+ <string name="default_app_none" msgid="9084592086808194457">"କିଛି ଆପ ସେଟ କରାଯାଇନାହିଁ"</string>
<string name="default_app_system_default" msgid="6218386768175513760">"(ସିଷ୍ଟମ୍ ଡିଫଲ୍ଟ)"</string>
<string name="default_app_no_apps" msgid="115720991680586885">"କୌଣସି ଆପ୍‌ ନାହିଁ"</string>
<string name="car_default_app_selected" msgid="5416420830430644174">"ଚୟନ କରାଯାଇଛି"</string>
@@ -455,59 +467,84 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"ଆସିଷ୍ଟାଣ୍ଟ ଟ୍ରିଗର୍ ଚିହ୍ନଟକରଣ ଦେଖାନ୍ତୁ"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"ଭଏସ୍ ଆସିଷ୍ଟାଣ୍ଟ୍ ସକ୍ରିୟ କରିବା ପାଇଁ ମାଇକ୍ରୋଫାନ୍ ବ୍ୟବହାର କରୁଥିବା ସମୟରେ ସ୍ଥିତି ବାର୍‌ରେ ଆଇକନ୍ ଦେଖାନ୍ତୁ"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"ଆପଣଙ୍କ ଡିଭାଇସ୍‌ରେ ଥିବା ଫଟୋ ଓ ମିଡିଆ ଆକ୍‌ସେସ୍ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$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_storage_isolated" msgid="5934218468708513375">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_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="2270563860206654757">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_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="6641436550953715107">"ଆପଣଙ୍କ &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="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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>ର ଲୋକେସନକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ଆପଣ ଆପ୍ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ଏହି ଆପ୍ ସବୁ ସମୟରେ ଆପଣଙ୍କର ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରିବାକୁ ଚାହିଁପାରେ। "<annotation id="link">"ସେଟିଂସରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ପାଇଁ ଲୋକେସନ୍ ଆକ୍ସେସ୍ ବଦଳାଇବେ କି?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"ଆପଣ ଆପ୍ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ଏହି ଆପ୍ ସବୁ ସମୟରେ ଆପଣଙ୍କର ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରିବାକୁ ଚାହେଁ। "<annotation id="link">"ସେଟିଂସରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"ଆଖପାଖର ଡିଭାଇସଗୁଡ଼ିକର ଆପେକ୍ଷିକ ଅବସ୍ଥିତିକୁ ଖୋଜିବା, କନେକ୍ଟ ଏବଂ ନିର୍ଦ୍ଧାରଣ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"ଆଖପାଖର ଡିଭାଇସଗୁଡ଼ିକର ଆପେକ୍ଷିକ ଅବସ୍ଥିତିକୁ ଖୋଜିବା, ସଂଯୋଗ ଏବଂ ନିର୍ଦ୍ଧାରଣ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ? "<annotation id="link">"ସେଟିଂସରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>ର ଲୋକେସନ୍ ଆକ୍ସେସକୁ ଆନୁମାନିକରୁ ସଠିକକୁ ବଦଳାଇବେ?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ରେ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>ର ଲୋକେସନ ଆକ୍ସେସକୁ ଆନୁମାନିକରୁ ସଠିକକୁ ପରିବର୍ତ୍ତନ କରିବେ?"</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="9001956706241104626">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_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="3103987548035171850">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ SMS ମେସେଜ୍‍ ପଠାଇବା ଓ ଦେଖିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ରେ SMS ମେସେଜ ପଠାଇବା ଏବଂ ଭ୍ୟୁ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$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="872629037299467086">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_storage_q_to_s" msgid="8213701872983685505">"ଏହି ଡିଭାଇସରେ ଥିବା &lt;b&gt;ଫଟୋ, ଭିଡିଓ, ମ୍ୟୁଜିକ ଓ ଅଡିଓ&lt;/b&gt;କୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"ଏହି ଡିଭାଇସରେ ଥିବା&lt;b&gt;ଫଟୋ, ଭିଡିଓ, ମ୍ୟୁଜିକ, ଅଡିଓ ଓ ଅନ୍ୟ ଫାଇଲ&lt;/b&gt; ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"ଏହି ଡିଭାଇସରେ ଥିବା ମ୍ୟୁଜିକ ଏବଂ ଅଡିଓକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_read_media_visual" msgid="5548780620779729975">"ଏହି ଡିଭାଇସରେ ଥିବା ଫଟୋ ଏବଂ ଭିଡିଓଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_more_photos" msgid="128933814654231321">"ଏହି ଡିଭାଇସରେ ଥିବା ଅଧିକ ଫଟୋ ଏବଂ ଭିଡିଓକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
- <string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅଡିଓ ରେକର୍ଡ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅଡିଓ ରେକର୍ଡ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_microphone" msgid="8510456971528228861">"ଆପଣ ଆପକୁ ବ୍ୟବହାର କରୁଥିବା ସମୟରେ କେବଳ ଏହା ଅଡିଓ ରେକର୍ଡ କରିବାକୁ ସକ୍ଷମ ହେବ"</string>
- <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅଡିଓ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅଡିଓ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ଆପଣ ଆପକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ଏହା ସବୁ ସମୟରେ ଅଡିଓ ରେକର୍ଡ କରିବାକୁ ଚାହିଁ ପାରେ। "<annotation id="link">"ସେଟିଂସରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ପାଇଁ ମାଇକ୍ରୋଫୋନର ଆକ୍ସେସ୍ ବଦଳାଇବେ କି?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"ଆପଣ ଆପକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ଏହା ସବୁ ସମୟରେ ଅଡିଓ ରେକର୍ଡ କରିବାକୁ ଚାହେଁ। "<annotation id="link">"ସେଟିଂସରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"ଆପଣ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଆପଣଙ୍କର ଶାରୀରିକ କାର୍ଯ୍ୟକଳାପକୁ ଆକ୍ସେସ୍ କରିବାକୁ ଅନୁମତି ଦେବେ କି?"</string>
- <string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଫଟୋ ଉଠାଇବାକୁ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଫଟୋ ଉଠାଇବାକୁ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_camera" msgid="9085323239764667883">"ଆପଣ ଆପକୁ ବ୍ୟବହାର କରୁଥିବା ସମୟରେ କେବଳ ଏହା ଛବି ନେବାକୁ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିବାକୁ ସକ୍ଷମ ହେବ"</string>
- <string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଛବି ନେବାକୁ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଫଟୋ ଉଠାଇବାକୁ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ଆପଣ ଆପକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ଏହା ସବୁ ସମୟରେ ଛବି ନେବାକୁ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିବାକୁ ଚାହିଁ ପାରେ। "<annotation id="link">"ସେଟିଂସରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ପାଇଁ କ୍ୟାମେରାର ଆକ୍ସେସ୍ ବଦଳାଇବେ କି?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"ଆପଣ ଆପକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ଏହା ସବୁ ସମୟରେ ଛବି ନେବାକୁ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିବାକୁ ଚାହେଁ। "<annotation id="link">"ସେଟିଂସରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</annotation></string>
- <string name="permgrouprequest_calllog" msgid="2065327180175371397">"ଆପଣଙ୍କର ଫୋନ୍‌‌ର କଲ୍‌ ଲଗ୍‌ ଆକ୍ସେସ୍‌ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ କି?"</string>
- <string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଫୋନ୍‍ କଲ୍‍ କରିବାକୁ ତଥା ପରିଚାଳନା କରିବାକୁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgrouprequest_calllog" msgid="2065327180175371397">"ଆପଣଙ୍କ ଫୋନର କଲ ଲଗ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଫୋନ କଲ କରିବାକୁ ତଥା ପରିଚାଳନା କରିବାକୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଆପଣଙ୍କ ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଲକ୍ଷଣଗୁଡ଼ିକ ବିଷୟରେ ସେନ୍ସର୍‍ ଡାଟା ଆକ୍ସେସ୍‍ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"ଆପଣ ଆପ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ଏହି ଆପ ସବୁ ସମୟରେ ଆପଣଙ୍କ ମହତ୍ତ୍ୱପୂର୍ଣ୍ଣ ଲକ୍ଷଣଗୁଡ଼ିକ ବିଷୟରେ ସେନ୍ସର ଡାଟାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଚାହେଁ। ଏହି ପରିବର୍ତ୍ତନ କରିବାକୁ, "<annotation id="link">"ସେଟିଂସକୁ ଯାଆନ୍ତୁ।"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"ଆପଣଙ୍କ ମହତ୍ତ୍ୱପୂର୍ଣ୍ଣ ଲକ୍ଷଣଗୁଡ଼ିକ ବିଷୟରେ ସେନ୍ସର ଡାଟାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"ଆପଣ ଆପ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ, ବଡି ସେନ୍ସର ଡାଟାକୁ ସର୍ବଦା ଆକ୍ସେସ କରିବା ନିମନ୍ତେ ଏହି ଆପକୁ ଅନୁମତି ଦେବା ପାଇଁ, "<annotation id="link">"ସେଟିଂସକୁ ଯାଆନ୍ତୁ।"</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ଆପ ବ୍ୟବହାରରେ ଥିବା ସମୟରେ ବଡି ସେନ୍ସର ଡାଟାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବା ଜାରି ରଖିବେ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"ଆପକୁ ବ୍ୟବହାର କରାଯାଉଥିବା ବେଳେ &lt;b&gt;<xliff:g id="DEVICE">%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_notifications" msgid="6396739062335106181">"ଆପଣଙ୍କୁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପଠାଇବା ପାଇଁ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"ଆପଣଙ୍କ &lt;b&gt;<xliff:g id="DEVICE">%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="auto_granted_permissions" msgid="6009452264824455892">"ନିୟନ୍ତ୍ରିତ ଅନୁରୋଧଗୁଡ଼ିକ"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର ଲୋକେସନ ଆକ୍ସେସ ଅଛି"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"ଆପଣଙ୍କ ଲୋକେସନକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣଙ୍କ ସଂସ୍ଥା <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଏ"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"ଅନ୍ୟ ଅନୁମତିଗୁଡ଼ିକ"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"ସିଷ୍ଟମ୍ ଦ୍ୱାରା ବ୍ୟବହୃତ ହୋଇଥିବା ଅନୁମତି"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"କେବଳ ସିଷ୍ଟମ୍ ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଦ୍ୱାରା ବ୍ୟବହୃତ ହୋଇଥିବା ଅନୁମତିଗୁଡ଼ିକ।"</string>
<string name="additional_permissions_label" msgid="7693557637462569046">"ଅତିରିକ୍ତ ଅନୁମତି"</string>
<string name="additional_permissions_description" msgid="2186611950890732112">"ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଦ୍ୱାରା ପରିଭାଷିତ ହୋଇଥିବା ଅନୁମତିଗୁଡ଼ିକ।"</string>
- <string name="privdash_label_camera" msgid="1426440033626198096">"କ୍ୟାମେରା"</string>
+ <string name="privdash_label_camera" msgid="1426440033626198096">"କେମେରା"</string>
<string name="privdash_label_microphone" msgid="8415035835803511693">"ମାଇକ୍ରୋଫୋନ"</string>
<string name="privdash_label_location" msgid="6882400763866489291">"ଲୋକେସନ"</string>
<string name="privdash_label_other" msgid="3710394147423236033">"ଅନ୍ୟ"</string>
@@ -537,7 +574,7 @@
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ସ୍ଥିତି ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"ଆପଣଙ୍କ ଗୋପନୀୟତା ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"ଅଧିକ ସେଟିଂସ"</string>
- <string name="camera_toggle_label_qs" msgid="3880261453066157285">"କ୍ୟାମେରା ଆକ୍ସେସ"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"କେମେରା ଆକ୍ସେସ"</string>
<string name="microphone_toggle_label_qs" msgid="8132912469813396552">"ମାଇକ ଆକ୍ସେସ"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"ଅନୁମତିକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
<string name="camera_usage_qs" msgid="4394233566086665994">"ବର୍ତ୍ତମାନର କ୍ୟାମେରା ବ୍ୟବହାର ଦେଖନ୍ତୁ"</string>
@@ -575,11 +612,11 @@
<string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"ପୃଷ୍ଠପଟ ଲୋକେସନ ଆକ୍ସେସ ଥିବା ଆପର ସମୀକ୍ଷା କରନ୍ତୁ"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> ଆପ ବନ୍ଦ ଥିବା ସମୟରେ ମଧ୍ୟ ସର୍ବଦା ଆପଣଙ୍କ ଲୋକେସନକୁ ଆକ୍ସେସ କରିପାରିବ"</string>
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"ପୃଷ୍ଠପଟ ଲୋକେସନ ଆକ୍ସେସ ଥିବା ଆପର ସମୀକ୍ଷା କରନ୍ତୁ"</string>
- <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"ଏହି ଆପ ବନ୍ଦ ଥିବା ସମୟରେ ମଧ୍ୟ ସର୍ବଦା ଆପଣଙ୍କ ଲୋକେସନକୁ ଆକ୍ସେସ କରିପାରିବ।\n\nକିଛି ସୁରକ୍ଷା ଏବଂ ଜରୁରୀକାଳୀନ ଆପ୍ସ ଆଶା କରାଯାଉଥିବା ଅନୁସାରେ କାର୍ଯ୍ୟ କରିବା ପାଇଁ ପୃଷ୍ଠପଟରେ ଆପଣଙ୍କ ଲୋକେସନକୁ ଆକ୍ସେସ ଆବଶ୍ୟକ କରେ।"</string>
+ <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="camera_toggle_title" msgid="1251201397431837666">"କ୍ୟାମେରା ଆକ୍ସେସ"</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>
<string name="mic_toggle_description" msgid="9163104307990677157">"ଆପ୍ସ ଏବଂ ସେବାଗୁଡ଼ିକ ପାଇଁ। ଯଦି ଏହି ସେଟିଂ ବନ୍ଦ ଥାଏ, ତେବେ ଆପଣ ଏକ ଜରୁରୀକାଳୀନ ନମ୍ବରକୁ କଲ କରିବା ସମୟରେ ମାଇକ୍ରୋଫୋନ ଡାଟା ଏବେ ବି ସେୟାର କରାଯାଇପାରେ।"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"ଏହି ଆପ ଉଲ୍ଲେଖ କରିଛି ଯେ ଏହା ତୃତୀୟ ପକ୍ଷଗୁଡ଼ିକ ସହ ଲୋକେସନ ଡାଟା ସେୟାର କରିପାରେ"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ଡାଟା ସେୟାରିଂ ଏବଂ ଲୋକେସନ"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ଡାଟା ସେୟାରିଂ ସୂଚନା କେଉଁଠାରୁ ଆସିଥାଏ"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ଏହି ଆପ କିପରି ଡାଟା ସେୟାର କରେ ସେ ବିଷୟରେ ଡେଭେଲପର ଏହି ଡିଭାଇସର ନିର୍ମାତାଙ୍କୁ ସୂଚନା ପ୍ରଦାନ କରିଛନ୍ତି। ଡେଭେଲପର ସମୟ ଅନୁସାରେ ଏହି ସୂଚନାକୁ ଅପଡେଟ କରିପାରନ୍ତି।"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ଏହି ଆପ କିପରି ଡାଟା ସେୟାର କରେ ସେ ବିଷୟରେ ଡେଭେଲପର "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"ରେ ସୂଚନା ପ୍ରଦାନ କରିଛନ୍ତି। ଡେଭେଲପର ସମୟ ଅନୁସାରେ ଏହି ସୂଚନାକୁ ଅପଡେଟ କରିପାରନ୍ତି।"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ଏଥିପାଇଁ ଏହି ଆପ ଲୋକେସନ ଡାଟା ସେୟାର କରିପାରେ:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ଡାଟା ସେୟାରିଂ ଭିନ୍ନ ହୋଇଥାଏ"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ଡାଟା ସୁରକ୍ଷା"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"ଲୋକେସନ ଡାଟା ସେୟାର କରାଯାଇପାରେ"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"ଏହି ଆପ ଉଲ୍ଲେଖ କରିଛି ଯେ ଏହା ତୃତୀୟ ପକ୍ଷଗୁଡ଼ିକ ସହ ଆପଣଙ୍କ ଲୋକେସନ ଡାଟା ସେୟାର କରିପାରେ"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ଏହି ଲିଙ୍କ ଖୋଲାଯାଇପାରିବ ନାହିଁ"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"ଲୋକେସନ ପାଇଁ ଡାଟା ସେୟାରିଂ ଅପଡେଟଗୁଡ଼ିକ"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ଆପଣଙ୍କ ଲୋକେସନ ଡାଟା ସେୟାର କରିବା ଉପାୟକୁ ପରିବର୍ତ୍ତନ କରିଥିବା ଆପ୍ସର ସମୀକ୍ଷା କରନ୍ତୁ"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"ଏହି ଆପ୍ସ ଆପଣଙ୍କ ଲୋକେସନ ଡାଟା ସେୟାର କରିବା ଉପାୟକୁ ପରିବର୍ତ୍ତନ କରିଛି। ସେଗୁଡ଼ିକ ଏହାକୁ ପୂର୍ବରୁ ସେୟାର କରିନଥାଇପାରେ କିମ୍ବା ବର୍ତ୍ତମାନ ଏହାକୁ ବିଜ୍ଞାପନ ବା ମାର୍କେଟିଂ ଉଦ୍ଦେଶ୍ୟରେ ସେୟାର କରିପାରେ।"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ଡାଟା ସେୟାରିଂ ଅପଡେଟଗୁଡ଼ିକ"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"କିଛି ଆପ୍ସ ଆପଣଙ୍କ ଲୋକେସନ ଡାଟା ସେୟାର କରିବା ଉପାୟକୁ ପରିବର୍ତ୍ତନ କରିଛି"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ସେଟିଂସ"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇଛି"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"ଗତକାଲି <xliff:g id="TIME_DATE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇଛି"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇଛି"</string>
</resources>
diff --git a/PermissionController/res/values-pa-v33/strings.xml b/PermissionController/res/values-pa-v33/strings.xml
index 19930a93b..0aa143302 100644
--- a/PermissionController/res/values-pa-v33/strings.xml
+++ b/PermissionController/res/values-pa-v33/strings.xml
@@ -27,11 +27,10 @@
<string name="safety_center_entry_group_with_actions_needed_content_description" msgid="2708884606775932657">"ਸੂਚੀ। <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. ਕਾਰਵਾਈਆਂ ਦੀ ਲੋੜ ਹੈ। <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
<string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"ਸੂਚੀ ਆਈਟਮ। <xliff:g id="ENTRY_ITEM_TITLE">%1$s</xliff:g>. <xliff:g id="ENTRY_ITEM_SUMMARY">%2$s</xliff:g>"</string>
<string name="safety_center_entry_content_description" msgid="3639565652938224321">"<xliff:g id="ENTRY_ITEM_TITLE">%1$s</xliff:g>. <xliff:g id="ENTRY_ITEM_SUMMARY">%2$s</xliff:g>"</string>
- <string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"ਹੋਰ ਸੁਚੇਤਨਾਵਾਂ"</string>
- <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"ਖਾਰਜ ਕੀਤੀਆਂ ਗਈਆਂ ਸੁਚੇਤਨਾਵਾਂ"</string>
- <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{ਵਿਸਤਾਰ ਕਰੋ ਅਤੇ ਇੱਕ ਹੋਰ ਸੁਚੇਤਨਾ ਦੇਖੋ}one{ਵਿਸਤਾਰ ਕਰੋ ਅਤੇ # ਹੋਰ ਸੁਚੇਤਨਾ ਦੇਖੋ}other{ਵਿਸਤਾਰ ਕਰੋ ਅਤੇ # ਹੋਰ ਸੁਚੇਤਨਾਵਾਂ ਦੇਖੋ}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"ਹੋਰ ਅਲਰਟ"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"ਖਾਰਜ ਕੀਤੇ ਅਲਰਟ"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{ਵਿਸਤਾਰ ਕਰੋ ਅਤੇ ਇੱਕ ਹੋਰ ਅਲਰਟ ਦੇਖੋ}one{ਵਿਸਤਾਰ ਕਰੋ ਅਤੇ # ਹੋਰ ਅਲਰਟ ਦੇਖੋ}other{ਵਿਸਤਾਰ ਕਰੋ ਅਤੇ # ਹੋਰ ਅਲਰਟ ਦੇਖੋ}}"</string>
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"ਅਲਰਟ। <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"ਕਾਰਵਾਈ ਪੂਰੀ ਹੋਈ"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"ਉਨ੍ਹਾਂ ਸੈਟਿੰਗਾਂ ਦੀ ਜਾਂਚ ਕਰੋ ਜੋ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਵਿੱਚ ਸੁਰੱਖਿਆ ਸ਼ਾਮਲ ਕਰ ਸਕਦੀਆਂ ਹਨ"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"ਸੁਰੱਖਿਆ ਅਤੇ ਪਰਦੇਦਾਰੀ ਸੰਬੰਧੀ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ"</string>
diff --git a/PermissionController/res/values-pa/strings.xml b/PermissionController/res/values-pa/strings.xml
index 055596f04..c565b12d5 100644
--- a/PermissionController/res/values-pa/strings.xml
+++ b/PermissionController/res/values-pa/strings.xml
@@ -27,13 +27,14 @@
<string name="off" msgid="1438489226422866263">"ਬੰਦ"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"ਅਣਸਥਾਪਤ ਕਰੋ ਜਾਂ ਬੰਦ ਕਰੋ"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"ਐਪ ਨਹੀਂ ਮਿਲੀ"</string>
- <string name="grant_dialog_button_deny" msgid="88262611492697192">"ਨਾ ਕਰਨ ਦਿਓ"</string>
+ <string name="grant_dialog_button_deny" msgid="88262611492697192">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
<string name="grant_dialog_button_deny_and_dont_ask_again" msgid="1748925431574312595">"ਆਗਿਆ ਨਾ ਦਿਓ ਅਤੇ ਦੁਬਾਰਾ ਨਾ ਪੁੱਛੋ"</string>
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"“ਐਪ ਵਰਤੋਂ ਵਿੱਚ ਹੋਣ ਵੇਲੇ” ਨੂੰ ਰੱਖੋ"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"“ਸਿਰਫ਼ ਇਸ ਸਮੇਂ ਲਈ ਇਜਾਜ਼ਤ ਦਿਓ” ਰੱਖੋ"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"ਹੋਰ ਜਾਣਕਾਰੀ"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"ਸਭ ਨੂੰ ਆਗਿਆ ਦਿਓ"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"ਸਭ \'ਤੇ ਕਰਨ ਦਿਓ"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"ਹਮੇਸ਼ਾਂ ਸਭ ਨੂੰ ਆਗਿਆ ਦਿਓ"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"ਸੀਮਤ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਚੁਣੋ"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"ਹੋਰ ਚੁਣੋ"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ਹੋਰ ਡਾਟਾ ਨਾ ਚੁਣੋ"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ਐਪਾਂ"</string>
<string name="app_permissions" msgid="3369917736607944781">"ਐਪ ਇਜਾਜ਼ਤਾਂ"</string>
<string name="unused_apps" msgid="2058057455175955094">"ਅਣਵਰਤੀਆਂ ਐਪਾਂ"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ਇਸ ਐਪ ਲਈ ਚੁਣੀਆਂ ਫ਼ੋਟੋਆਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ਕੋਈ ਅਣਵਰਤੀ ਐਪ ਨਹੀਂ"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ਅਣਵਰਤੀਆਂ ਐਪਾਂ"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"ਇਜਾਜ਼ਤ ਸੰਬੰਧੀ ਹਾਲੀਆ ਫ਼ੈਸਲੇ"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"ਸਾਰੀਆਂ ਇਜਾਜ਼ਤਾਂ"</string>
<string name="other_permissions" msgid="2901186127193849594">"ਐਪ ਦੀਆਂ ਹੋਰ ਸਮਰੱਥਤਾਵਾਂ"</string>
<string name="permission_request_title" msgid="8790310151025020126">"ਇਜਾਜ਼ਤ ਬੇਨਤੀ"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear \'ਤੇ ਸਥਾਪਤ/ਅਣਸਥਾਪਤ ਕਰਨ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਸਮਰਥਿਤ ਨਹੀਂ ਹਨ।"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"ਇਹ ਚੁਣੋ ਕਿ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਕਿਸ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ। ਇਹ ਚੁਣੋ ਕਿ ਇਸ ਐਪ ਨੂੰ ਕਿਸ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ।"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"ਰੱਦ ਕਰੋ"</string>
@@ -195,7 +195,7 @@
<string name="approximate_image_description" msgid="938803699637069884">"ਅੰਦਾਜ਼ਨ ਟਿਕਾਣਾ"</string>
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"ਸਹੀ ਟਿਕਾਣਾ ਵਰਤੋ"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"ਜਦੋਂ ਸਹੀ ਟਿਕਾਣੇ ਦੀ ਜਾਣਕਾਰੀ ਬੰਦ ਹੋਵੇ, ਤਾਂ ਐਪਾਂ ਤੁਹਾਡੀ ਅੰਦਾਜ਼ਨ ਟਿਕਾਣੇ ਦੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀਆਂ ਹਨ"</string>
- <string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g> ਇਜਾਜ਼ਤ"</string>
+ <string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g> ਸੰਬੰਧੀ ਇਜਾਜ਼ਤ"</string>
<string name="app_permission_header" msgid="2951363137032603806">"ਇਸ ਐਪ ਲਈ <xliff:g id="PERM">%1$s</xliff:g> ਪਹੁੰਚ"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"<xliff:g id="APP">%1$s</xliff:g> ਦੀਆਂ ਸਾਰੀਆਂ ਇਜਾਜ਼ਤਾਂ ਦੇਖੋ"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"ਇਸ ਇਜਾਜ਼ਤ ਵਾਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਦੇਖੋ"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ਐਪ ਨੂੰ ਨਾ ਵਰਤੇ ਜਾਣ \'ਤੇ ਇਸ ਲਈ ਦਿੱਤੀਆਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾ ਦਿਓ"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"ਇਜਾਜ਼ਤਾਂ ਹਟਾਓ ਅਤੇ ਜਗ੍ਹਾ ਖਾਲੀ ਕਰੋ"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"ਵਰਤੋਂ ਵਿੱਚ ਨਾ ਹੋਣ \'ਤੇ, ਐਪ ਸਰਗਰਮੀ ਰੋਕੋ"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ਵਰਤੋਂ ਵਿੱਚ ਨਾ ਹੋਣ \'ਤੇ, ਐਪ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"ਇਜਾਜ਼ਤਾਂ ਹਟਾਓ, ਅਸਥਾਈ ਫ਼ਾਈਲਾਂ ਮਿਟਾਓ ਅਤੇ ਸੂਚਨਾਵਾਂ ਬੰਦ ਕਰੋ"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"ਇਜਾਜ਼ਤਾਂ ਹਟਾਓ, ਅਸਥਾਈ ਫ਼ਾਈਲਾਂ ਮਿਟਾਓ, ਸੂਚਨਾਵਾਂ ਬੰਦ ਕਰੋ ਅਤੇ ਐਪ ਨੂੰ ਪੁਰਾਲੇਖਬੱਧ ਕਰੋ"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"ਤੁਹਾਡੀ ਡਾਟਾ ਸੁਰੱਖਿਆ ਲਈ, ਜੇ ਇਹ ਐਪ ਕੁਝ ਮਹੀਨਿਆਂ ਲਈ ਵਰਤੀ ਨਹੀਂ ਗਈ, ਤਾਂ ਇਸ ਐਪ ਲਈ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"ਤੁਹਾਡੀ ਡਾਟਾ ਸੁਰੱਖਿਆ ਲਈ, ਜੇ ਇਹ ਐਪ ਕੁਝ ਮਹੀਨਿਆਂ ਲਈ ਵਰਤੀ ਨਹੀਂ ਗਈ, ਤਾਂ ਅੱਗੇ ਦਿੱਤੀਆਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"ਤੁਹਾਡੀ ਡਾਟਾ ਸੁਰੱਖਿਆ ਲਈ, ਜੋ ਐਪਾਂ ਤੁਸੀਂ ਕੁਝ ਮਹੀਨਿਆਂ ਤੋਂ ਨਹੀਂ ਵਰਤੀਆਂ ਉਹਨਾਂ ਐਪਾਂ ਤੋਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਗਿਆ ਹੈ।"</string>
@@ -221,12 +223,12 @@
<string name="unused_apps_page_title" msgid="6986983535677572559">"ਅਣਵਰਤੀਆਂ ਐਪਾਂ"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"ਜੇ ਕਿਸੇ ਐਪ ਨੂੰ ਕੁਝ ਮਹੀਨਿਆਂ ਤੱਕ ਵਰਤਿਆ ਨਹੀਂ ਜਾਂਦਾ ਹੈ, ਤਾਂ:\n\n• ਤੁਹਾਡੇ ਡਾਟੇ ਦੀ ਸੁਰੱਖਿਆ ਕਰਨ ਲਈ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ\n• ਬੈਟਰੀ ਬਚਾਉਣ ਲਈ ਸੂਚਨਾਵਾਂ ਬੰਦ ਕਰ ਦਿੱਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ\n• ਜਗ੍ਹਾ ਖਾਲੀ ਕਰਨ ਲਈ ਅਸਥਾਈ ਫ਼ਾਈਲਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ\n\nਦੁਬਾਰਾ ਇਜਾਜ਼ਤਾਂ ਦੇਣ ਅਤੇ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, ਐਪ ਖੋਲ੍ਹੋ।"</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"ਜੇ ਕਿਸੇ ਐਪ ਨੂੰ ਇੱਕ ਮਹੀਨੇ ਤੱਕ ਨਹੀਂ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ, ਤਾਂ:\n\n• ਤੁਹਾਡੇ ਡਾਟੇ ਦੀ ਸੁਰੱਖਿਆ ਕਰਨ ਲਈ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ\n• ਜਗ੍ਹਾ ਖਾਲੀ ਕਰਨ ਲਈ ਅਸਥਾਈ ਫ਼ਾਈਲਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ\n\nਇਜਾਜ਼ਤਾਂ ਦੀ ਦੁਬਾਰਾ ਆਗਿਆ ਦੇਣ ਲਈ, ਐਪ ਨੂੰ ਖੋਲ੍ਹੋ।"</string>
- <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{ਪਿਛਲੀ ਵਾਰ # ਮਹੀਨੇ ਤੋਂ ਵੱਧ ਪਹਿਲਾਂ ਖੋਲ੍ਹੀਆਂ ਗਈਆਂ}one{ਪਿਛਲੀ ਵਾਰ # ਮਹੀਨੇ ਤੋਂ ਵੱਧ ਪਹਿਲਾਂ ਖੋਲ੍ਹੀਆਂ ਗਈਆਂ}other{ਪਿਛਲੀ ਵਾਰ # ਮਹੀਨਿਆਂ ਤੋਂ ਵੱਧ ਪਹਿਲਾਂ ਖੋਲ੍ਹੀਆਂ ਗਈਆਂ}}"</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{ਪਿਛਲੀ ਵਾਰ # ਮਹੀਨੇ ਤੋਂ ਵੱਧ ਸਮਾਂ ਪਹਿਲਾਂ ਖੋਲ੍ਹੀਆਂ ਗਈਆਂ}one{ਪਿਛਲੀ ਵਾਰ # ਮਹੀਨੇ ਤੋਂ ਵੱਧ ਸਮਾਂ ਪਹਿਲਾਂ ਖੋਲ੍ਹੀਆਂ ਗਈਆਂ}other{ਪਿਛਲੀ ਵਾਰ # ਮਹੀਨਿਆਂ ਤੋਂ ਵੱਧ ਸਮਾਂ ਪਹਿਲਾਂ ਖੋਲ੍ਹੀਆਂ ਗਈਆਂ}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"ਐਪ ਨੂੰ ਆਖਰੀ ਵਾਰ <xliff:g id="DATE">%s</xliff:g> ਨੂੰ ਖੋਲ੍ਹਿਆ ਗਿਆ"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"ਆਖਰੀ ਵਾਰ <xliff:g id="DATE">%s</xliff:g> ਨੂੰ ਖੋਲ੍ਹਿਆ ਗਿਆ"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"ਜੇ ਤੁਸੀਂ ਸਾਰੀਆਂ ਫ਼ਾਈਲਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਐਪ ਇਸ ਡੀਵਾਈਸ ਜਾਂ ਕਨੈਕਟ ਕੀਤੇ ਸਟੋਰੇਜ ਡੀਵਾਈਸਾਂ ਦੀ ਸਾਂਝੀ ਸਟੋਰੇਜ ਵਿੱਚ ਕਿਸੇ ਵੀ ਫ਼ਾਈਲ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ, ਉਸ ਵਿੱਚ ਸੋਧ ਕਰ ਸਕਦੀ ਅਤੇ ਉਸ ਨੂੰ ਮਿਟਾ ਸਕਦੀ ਹੈ। ਐਪ ਤੁਹਾਨੂੰ ਪੁੱਛੇ ਬਿਨਾਂ ਫ਼ਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਇਸ ਡੀਵਾਈਸ ਜਾਂ ਕਨੈਕਟ ਕੀਤੇ ਸਟੋਰੇਜ ਡੀਵਾਈਸਾਂ \'ਤੇ ਫ਼ਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ, ਉਹਨਾਂ ਨੂੰ ਸੋਧਣ ਅਤੇ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ? ਇਹ ਐਪ ਤੁਹਾਨੂੰ ਪੁੱਛੇ ਬਿਨਾਂ ਫ਼ਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ।"</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"ਇਸ ਇਜਾਜ਼ਤ ਵਾਲੀਆਂ ਐਪਾਂ <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"ਇਸ ਇਜਾਜ਼ਤ ਵਾਲੀਆਂ ਐਪਾਂ ਇਹ ਕਰ ਸਕਦੀਆਂ ਹਨ: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"ਇਸ ਇਜਾਜ਼ਤ ਵਾਲੀਆਂ ਐਪਾਂ ਤੁਹਾਡੀ ਸਰੀਰਕ ਸਰਗਰਮੀ, ਜਿਵੇਂ ਕਿ ਪੈਦਲ-ਸੈਰ, ਸਾਈਕਲ ਚਲਾਉਣਾ, ਗੱਡੀ ਚਲਾਉਣਾ, ਕਦਮਾਂ ਦੀ ਗਿਣਤੀ ਅਤੇ ਹੋਰ ਚੀਜ਼ਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀਆਂ ਹਨ"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"ਇਸ ਇਜਾਜ਼ਤ ਵਾਲੀਆਂ ਐਪਾਂ ਤੁਹਾਡੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀਆਂ ਹਨ"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"ਇਸ ਇਜਾਜ਼ਤ ਵਾਲੀਆਂ ਐਪਾਂ ਫ਼ੋਨ ਕਾਲ ਲੌਗ ਪੜ੍ਹ-ਲਿਖ ਸਕਦੀਆਂ ਹਨ"</string>
@@ -369,7 +371,7 @@
<string name="role_sms_search_keywords" msgid="8022048144395047352">"ਲਿਖਤ ਸੁਨੇਹਾ, ਲਿਖਤ ਭੇਜਣਾ, ਸੁਨੇਹੇ, ਸੁਨੇਹਾ ਭੇਜਣਾ"</string>
<string name="role_emergency_label" msgid="7028825857206842366">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੰਕਟਕਾਲੀਨ ਐਪ"</string>
<string name="role_emergency_short_label" msgid="2388431453335350348">"ਸੰਕਟਕਾਲੀਨ ਐਪ"</string>
- <string name="role_emergency_description" msgid="5051840234887686630">"ਐਪਾਂ ਜੋ ਤੁਹਾਨੂੰ ਤੁਹਾਡੀ ਡਾਕਟਰੀ ਜਾਣਕਾਰੀ ਰਿਕਾਰਡ ਕਰਨ ਅਤੇ ਇਸਨੂੰ ਸੰਕਟਕਾਲੀਨ ਮਦਦਗਾਰਾਂ ਤੱਕ ਪਹੁੰਚਯੋਗ ਬਣਾਉਣ ਦਿੰਦੀਆਂ ਹਨ; ਗੰਭੀਰ ਮੌਸਮੀ ਘਟਨਾਵਾਂ ਅਤੇ ਆਫ਼ਤਾਂ ਬਾਰੇ ਸੁਚੇਤਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਦਿੰਦੀਆਂ ਹਨ; ਤੁਹਾਨੂੰ ਮਦਦ ਦੀ ਲੋੜ ਪੈਣ \'ਤੇ ਹੋਰਾਂ ਨੂੰ ਸੂਚਿਤ ਕਰਨ ਦਿੰਦੀਆਂ ਹਨ"</string>
+ <string name="role_emergency_description" msgid="5051840234887686630">"ਐਪਾਂ ਜੋ ਤੁਹਾਨੂੰ ਤੁਹਾਡੀ ਡਾਕਟਰੀ ਜਾਣਕਾਰੀ ਰਿਕਾਰਡ ਕਰਨ ਅਤੇ ਇਸਨੂੰ ਐਮਰਜੈਂਸੀ ਮਦਦਗਾਰਾਂ ਤੱਕ ਪਹੁੰਚਯੋਗ ਬਣਾਉਣ ਦਿੰਦੀਆਂ ਹਨ; ਬਹੁਤ ਜ਼ਿਆਦਾ ਖਰਾਬ ਮੌਸਮੀ ਘਟਨਾਵਾਂ ਅਤੇ ਆਫ਼ਤਾਂ ਬਾਰੇ ਅਲਰਟ ਪ੍ਰਾਪਤ ਕਰਨ ਦਿੰਦੀਆਂ ਹਨ; ਤੁਹਾਨੂੰ ਮਦਦ ਦੀ ਲੋੜ ਪੈਣ \'ਤੇ ਹੋਰਾਂ ਨੂੰ ਸੂਚਿਤ ਕਰਨ ਦਿੰਦੀਆਂ ਹਨ"</string>
<string name="role_emergency_request_title" msgid="8469579020654348567">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੰਕਟਕਾਲੀਨ ਐਪ ਵਜੋਂ ਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
<string name="role_emergency_request_description" msgid="131645948770262850">"ਕਿਸੇ ਇਜਾਜ਼ਤ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ"</string>
<string name="role_emergency_search_keywords" msgid="1920007722599213358">"ice"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"ਨੋਟ-ਕਥਨਾਂ ਲਈ ਐਪ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"ਐਪਾਂ ਜੋ ਤੁਹਾਨੂੰ ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਨੋਟ-ਕਥਨ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀਆਂ ਹਨ"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ਨੋਟ-ਕਥਨ"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"ਮੌਜੂਦਾ ਪੂਰਵ-ਨਿਰਧਾਰਤ"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"ਦੁਬਾਰਾ ਨਾ ਪੁੱਛੋ"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਵਜੋਂ ਸੈੱਟ ਕਰੋ"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"ਸਹਾਇਕ ਟ੍ਰਿਗਰ ਦੀ ਸੂਹ ਦਿਖਾਓ"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"ਜਦੋਂ ਅਵਾਜ਼ੀ ਸਹਾਇਕ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰਨ ਲਈ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ ਤਾਂ ਸਥਿਤੀ ਪੱਟੀ ਵਿੱਚ ਪ੍ਰਤੀਕ ਦਿਖਾਓ"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਫ਼ੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"ਕੀ &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"ਕੀ &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> ਦਾ ਟਿਕਾਣਾ ਸਾਂਝਾ ਕਰਨ ਦੇਣਾ ਹੈ?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ਸ਼ਾਇਦ ਇਸ ਐਪ ਨੂੰ ਹਰ ਵੇਲੇ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇ, ਭਾਵੇਂ ਤੁਸੀਂ ਐਪ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੇ ਹੋ ਜਾਂ ਨਾ। "<annotation id="link">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਗਿਆ ਦਿਓ।"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਲਈ ਟਿਕਾਣਾ ਪਹੁੰਚ ਨੂੰ ਬਦਲਣਾ ਹੈ?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਲਈ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਟਿਕਾਣਾ ਪਹੁੰਚ ਨੂੰ ਬਦਲਣਾ ਹੈ?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"ਇਸ ਐਪ ਨੂੰ ਹਰ ਵੇਲੇ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਚਾਹੀਦੀ ਹੈ, ਭਾਵੇਂ ਤੁਸੀਂ ਐਪ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੇ ਹੋ ਜਾਂ ਨਾ। "<annotation id="link">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਗਿਆ ਦਿਓ।"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਲੱਭਣ, ਉਨ੍ਹਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰਨ ਅਤੇ ਸੰਬੰਧਿਤ ਸਥਿਤੀ ਨੂੰ ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੇਣਾ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸ ਲੱਭਣ, ਕਨੈਕਟ ਕਰਨ ਅਤੇ ਸਥਿਤੀ ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਲੱਭਣ, ਉਨ੍ਹਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰਨ ਅਤੇ ਸੰਬੰਧਿਤ ਸਥਿਤੀ ਨੂੰ ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੇਣਾ ਹੈ? "<annotation id="link">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਗਿਆ ਦਿਓ।"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"ਕੀ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ਦੀ ਟਿਕਾਣਾ ਪਹੁੰਚ ਨੂੰ ਅੰਦਾਜ਼ਨ ਤੋਂ ਸਹੀ ਟਿਕਾਣੇ \'ਤੇ ਬਦਲਣਾ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"ਕੀ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ਦੀ ਟਿਕਾਣਾ ਪਹੁੰਚ ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ SMS ਸੁਨੇਹੇ ਭੇਜਣ ਅਤੇ ਦੇਖਣ ਦੇਣੇ ਹਨ?"</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="872629037299467086">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਫ਼ਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਇਸ ਡੀਵਾਈਸ \'ਤੇ &lt;b&gt;ਫ਼ੋਟੋਆਂ, ਵੀਡੀਓ, ਸੰਗੀਤ ਅਤੇ ਆਡੀਓ&lt;/b&gt; ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਇਸ ਡੀਵਾਈਸ \'ਤੇ &lt;b&gt;ਫ਼ੋਟੋਆਂ, ਵੀਡੀਓ, ਸੰਗੀਤ, ਆਡੀਓ ਅਤੇ ਹੋਰ ਫ਼ਾਈਲਾਂ&lt;/b&gt; ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸੰਗੀਤ ਅਤੇ ਆਡੀਓ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਸੰਗੀਤ ਅਤੇ ਆਡੀਓ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਫ਼ੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਫ਼ੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਹੋਰ ਫ਼ੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਹੋਰ ਫ਼ੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਐਪ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਹੀ ਐਪ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰ ਸਕੇਗੀ"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ਇਹ ਐਪ ਹਰ ਵੇਲੇ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਸਕਦੀ ਹੈ, ਉਦੋਂ ਵੀ ਜਦੋਂ ਤੁਸੀਂ ਐਪ ਦੀ ਵਰਤੋਂ ਨਾ ਕਰ ਰਹੇ ਹੋਵੋ। "<annotation id="link">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਜਾਜ਼ਤ ਦਿਓ।"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਲਈ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਪਹੁੰਚ ਨੂੰ ਬਦਲਣਾ ਹੈ?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਲਈ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਪਹੁੰਚ ਨੂੰ ਬਦਲਣਾ ਹੈ?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"ਇਹ ਐਪ ਹਰ ਵੇਲੇ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗਦੀ ਹੈ, ਉਦੋਂ ਵੀ ਜਦੋਂ ਤੁਸੀਂ ਐਪ ਦੀ ਵਰਤੋਂ ਨਾ ਕਰ ਰਹੇ ਹੋਵੋ। "<annotation id="link">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਜਾਜ਼ਤ ਦਿਓ।"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੀ ਸਰੀਰਕ ਸਰਗਰਮੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਆਪਣੀ ਸਰੀਰਕ ਸਰਗਰਮੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਤਸਵੀਰਾਂ ਖਿੱਚਣ ਅਤੇ ਵੀਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੇਣਾ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਤਸਵੀਰਾਂ ਖਿੱਚਣ ਅਤੇ ਵੀਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਐਪ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਹੀ ਐਪ ਤਸਵੀਰਾਂ ਖਿੱਚ ਸਕੇਗੀ ਅਤੇ ਵੀਡੀਓ ਰਿਕਾਰਡ ਕਰ ਸਕੇਗੀ"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਤਸਵੀਰਾਂ ਖਿੱਚਣ ਅਤੇ ਵੀਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਤਸਵੀਰਾਂ ਖਿੱਚਣ ਅਤੇ ਵੀਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ਇਹ ਐਪ ਹਰ ਵੇਲੇ ਤਸਵੀਰਾਂ ਖਿੱਚਣ ਅਤੇ ਵੀਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਸਕਦੀ ਹੈ, ਉਦੋਂ ਵੀ ਜਦੋਂ ਤੁਸੀਂ ਐਪ ਦੀ ਵਰਤੋਂ ਨਾ ਕਰ ਰਹੇ ਹੋਵੋ। "<annotation id="link">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਜਾਜ਼ਤ ਦਿਓ।"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਲਈ ਕੈਮਰਾ ਪਹੁੰਚ ਨੂੰ ਬਦਲਣਾ ਹੈ?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਲਈ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਕੈਮਰਾ ਪਹੁੰਚ ਨੂੰ ਬਦਲਣਾ ਹੈ?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"ਇਹ ਐਪ ਹਰ ਵੇਲੇ ਤਸਵੀਰਾਂ ਖਿੱਚਣ ਅਤੇ ਵੀਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗਦੀ ਹੈ, ਉਦੋਂ ਵੀ ਜਦੋਂ ਤੁਸੀਂ ਐਪ ਦੀ ਵਰਤੋਂ ਨਾ ਕਰ ਰਹੇ ਹੋਵੋ। "<annotation id="link">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਜਾਜ਼ਤ ਦਿਓ।"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੇ ਕਾਲ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਆਪਣੇ ਫ਼ੋਨ ਕਾਲ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਫ਼ੋਨ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੇਣਾ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਫ਼ੋਨ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੇਣਾ ਹੈ?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਤੁਹਾਡੇ ਸਰੀਰ ਦੇ ਅਹਿਮ ਲੱਛਣਾਂ ਸੰਬੰਧੀ ਸੈਂਸਰ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਤੁਹਾਡੇ ਮਹੱਤਵਪੂਰਨ ਲੱਛਣਾਂ ਸੰਬੰਧੀ ਸੈਂਸਰ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"ਇਸ ਐਪ ਨੂੰ ਹਰ ਵੇਲੇ ਤੁਹਾਡੇ ਸਰੀਰ ਦੇ ਅਹਿਮ ਲੱਛਣਾਂ ਸੰਬੰਧੀ ਸੈਂਸਰ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਚਾਹੀਦੀ ਹੈ, ਭਾਵੇਂ ਤੁਸੀਂ ਐਪ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੇ ਹੋ ਜਾਂ ਨਹੀਂ। ਇਹ ਤਬਦੀਲੀ ਕਰਨ ਲਈ, "<annotation id="link">"ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਤੁਹਾਡੇ ਸਰੀਰ ਦੇ ਅਹਿਮ ਲੱਛਣਾਂ ਸੰਬੰਧੀ ਸੈਂਸਰ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਤੁਹਾਡੇ ਮਹੱਤਵਪੂਰਨ ਲੱਛਣਾਂ ਸੰਬੰਧੀ ਸੈਂਸਰ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"ਐਪ ਦੀ ਵਰਤੋਂ ਨਾ ਕਰਨ ਵੇਲੇ ਵੀ, ਇਸ ਐਪ ਨੂੰ ਹਰ ਸਮੇਂ ਸਰੀਰ ਸੰਬੰਧੀ ਸੈਂਸਰ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣ ਲਈ, "<annotation id="link">"ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ਕੀ ਐਪ ਦੇ ਵਰਤੋਂ ਵਿੱਚ ਹੋਣ ਵੇਲੇ ਸਰੀਰ ਸੰਬੰਧੀ ਸੈਂਸਰ ਦੇ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣ ਲਈ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਗਿਆ ਦੇਣਾ ਜਾਰੀ ਰੱਖਣੀ ਹੈ?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"ਕੀ ਐਪ ਵਰਤੋਂ ਵਿੱਚ ਹੋਣ ਵੇਲੇ ਸਰੀਰ ਸੰਬੰਧੀ ਸੈਂਸਰ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਦੇਣ ਲਈ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਆਗਿਆ ਦੇ ਕੇ ਰੱਖਣੀ ਹੈ?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਤੁਹਾਨੂੰ ਸੂਚਨਾਵਾਂ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"ਕੀ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਨੂੰ ਆਪਣੇ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; \'ਤੇ ਸੂਚਨਾਵਾਂ ਭੇਜਣ ਦੇਣੀਆਂ ਹਨ?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"ਨਿਯੰਤਰਿਤ ਇਜਾਜ਼ਤਾਂ"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਹੈ"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"ਤੁਹਾਡੀ ਸੰਸਥਾ <xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"ਹੋਰ ਇਜਾਜ਼ਤਾਂ"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"ਸਿਸਟਮ ਵੱਲੋਂ ਵਰਤੀ ਗਈ ਇਜਾਜ਼ਤ"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"ਸਿਰਫ਼ ਸਿਸਟਮ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਵਰਤੀਆਂ ਗਈਆਂ ਇਜਾਜ਼ਤਾਂ"</string>
@@ -525,7 +562,7 @@
<string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"ਸੁਰੱਖਿਆ ਅਤੇ ਪਰਦੇਦਾਰੀ"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"ਡੀਵਾਈਸ ਨੂੰ ਸਕੈਨ ਕਰੋ"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"ਖਾਰਜ ਕਰੋ"</string>
- <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"ਕੀ ਇਸ ਸੁਚੇਤਨਾ ਨੂੰ ਖਾਰਜ ਕਰਨਾ ਹੈ?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"ਕੀ ਇਸ ਅਲਰਟ ਨੂੰ ਖਾਰਜ ਕਰਨਾ ਹੈ?"</string>
<string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"ਹੋਰ ਸੁਰੱਖਿਆ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣੀਆਂ ਸੁਰੱਖਿਆ ਅਤੇ ਪਰਦੇਦਾਰੀ ਸੈਟਿੰਗਾਂ ਦੀ ਸਮੀਖਿਆ ਕਰੋ"</string>
<string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"ਖਾਰਜ ਕਰੋ"</string>
<string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"ਰੱਦ ਕਰੋ"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"ਇਸ ਐਪ ਨੇ ਸਪਸ਼ਟ ਕੀਤਾ ਕਿ ਇਹ ਤੀਜੀਆਂ ਧਿਰਾਂ ਨਾਲ ਟਿਕਾਣੇ ਦੇ ਡਾਟੇ ਨੂੰ ਸਾਂਝਾ ਕਰ ਸਕਦੀ ਹੈ"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ਡਾਟਾ ਸਾਂਝਾਕਰਨ ਅਤੇ ਟਿਕਾਣਾ"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ਡਾਟਾ ਸਾਂਝਾਕਰਨ ਜਾਣਕਾਰੀ ਕਿੱਥੋਂ ਆਉਂਦੀ ਹੈ"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ਵਿਕਾਸਕਾਰ ਨੇ ਇਸ ਐਪ ਵੱਲੋਂ ਡਾਟਾ ਸਾਂਝਾ ਕੀਤੇ ਜਾਣ ਦੇ ਤਰੀਕੇ ਬਾਰੇ ਜਾਣਕਾਰੀ ਇਸ ਡੀਵਾਈਸ ਦੇ ਨਿਰਮਾਤਾ ਨੂੰ ਮੁਹੱਈਆ ਕਰਵਾਈ ਹੈ। ਵਿਕਾਸਕਾਰ ਸਮੇਂ-ਸਮੇਂ \'ਤੇ ਇਸ ਜਾਣਕਾਰੀ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ਵਿਕਾਸਕਾਰ ਨੇ ਇਸ ਐਪ ਵੱਲੋਂ ਡਾਟਾ ਸਾਂਝਾ ਕੀਤੇ ਜਾਣ ਦੇ ਤਰੀਕੇ ਬਾਰੇ ਜਾਣਕਾਰੀ "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" ਨੂੰ ਮੁਹੱਈਆ ਕਰਵਾਈ ਹੈ। ਵਿਕਾਸਕਾਰ ਸਮੇਂ-ਸਮੇਂ \'ਤੇ ਇਸ ਜਾਣਕਾਰੀ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ਇਹ ਐਪ ਇਸ ਲਈ ਟਿਕਾਣੇ ਦਾ ਡਾਟਾ ਸਾਂਝਾ ਕਰ ਸਕਦੀ ਹੈ:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ਡਾਟਾ ਸਾਂਝਾਕਰਨ ਵੱਖ-ਵੱਖ ਹੁੰਦਾ ਹੈ"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ਡਾਟਾ ਸੁਰੱਖਿਆ"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"ਟਿਕਾਣੇ ਦਾ ਡਾਟਾ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"ਇਸ ਐਪ ਨੇ ਸਪਸ਼ਟ ਕੀਤਾ ਕਿ ਇਹ ਤੀਜੀਆਂ ਧਿਰਾਂ ਨਾਲ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਦੇ ਡਾਟੇ ਨੂੰ ਸਾਂਝਾ ਕਰ ਸਕਦੀ ਹੈ"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ਇਸ ਲਿੰਕ ਨੂੰ ਖੋਲ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"ਟਿਕਾਣੇ ਲਈ ਡਾਟਾ ਸਾਂਝਾਕਰਨ ਅੱਪਡੇਟ"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ਉਨ੍ਹਾਂ ਐਪਾਂ ਦੀ ਸਮੀਖਿਆ ਕਰੋ ਜਿਨ੍ਹਾਂ ਨੇ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਦੇ ਡਾਟੇ ਨੂੰ ਸਾਂਝਾ ਕੀਤੇ ਜਾਣ ਦਾ ਤਰੀਕਾ ਬਦਲ ਦਿੱਤਾ ਹੈ"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"ਇਨ੍ਹਾਂ ਐਪਾਂ ਨੇ ਉਨ੍ਹਾਂ ਵੱਲੋਂ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਦੇ ਡਾਟੇ ਨੂੰ ਸਾਂਝਾ ਕੀਤੇ ਜਾਣ ਦਾ ਤਰੀਕਾ ਬਦਲ ਦਿੱਤਾ ਹੈ। ਉਨ੍ਹਾਂ ਨੇ ਸ਼ਾਇਦ ਇਸਨੂੰ ਪਹਿਲਾਂ ਸਾਂਝਾ ਨਾ ਕੀਤਾ ਹੋਵੇ, ਜਾਂ ਉਹ ਸ਼ਾਇਦ ਹੁਣ ਵਿਗਿਆਪਨ ਜਾਂ ਮਾਰਕੀਟਿੰਗ ਸੰਬੰਧੀ ਉਦੇਸ਼ਾਂ ਲਈ ਹੁਣ ਇਸਨੂੰ ਸਾਂਝਾ ਕਰਨ।"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ਡਾਟਾ ਸਾਂਝਾਕਰਨ ਅੱਪਡੇਟ"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"ਕੁਝ ਐਪਾਂ ਨੇ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਦੇ ਡਾਟੇ ਨੂੰ ਸਾਂਝਾ ਕਰਨ ਦਾ ਤਰੀਕਾ ਬਦਲ ਦਿੱਤਾ ਹੈ"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ਸੈਟਿੰਗਾਂ"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g> ਵਜੇ ਪਹੁੰਚ ਕੀਤੀ ਗਈ"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"<xliff:g id="TIME_DATE">%1$s</xliff:g> ਵਜੇ ਕੱਲ੍ਹ ਪਹੁੰਚ ਕੀਤੀ ਗਈ"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> ਨੂੰ <xliff:g id="TIME_DATE_1">%2$s</xliff:g> ਵਜੇ ਪਹੁੰਚ ਕੀਤੀ ਗਈ"</string>
</resources>
diff --git a/PermissionController/res/values-pl-v33/strings.xml b/PermissionController/res/values-pl-v33/strings.xml
index dbead75d7..a6cdbd775 100644
--- a/PermissionController/res/values-pl-v33/strings.xml
+++ b/PermissionController/res/values-pl-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Więcej alertów"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Odrzucone alerty"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Rozwiń i zobacz jeszcze 1 alert}few{Rozwiń i zobacz jeszcze # alerty}many{Rozwiń i zobacz jeszcze # alertów}other{Rozwiń i zobacz jeszcze # alertu}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alert. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Działanie ukończone"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Sprawdź ustawienia, które mogą zwiększyć bezpieczeństwo Twojego urządzenia"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Szybkie ustawienia bezpieczeństwa i prywatności"</string>
diff --git a/PermissionController/res/values-pl-v34/strings.xml b/PermissionController/res/values-pl-v34/strings.xml
index 1df9c79b1..b69bf4c4f 100644
--- a/PermissionController/res/values-pl-v34/strings.xml
+++ b/PermissionController/res/values-pl-v34/strings.xml
@@ -22,6 +22,6 @@
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
<string name="health_connect_summary" msgid="815473513776882296">"Zarządzaj dostępem aplikacji do danych dotyczących zdrowia"</string>
<string name="location_settings" msgid="8863940440881290182">"Dostęp do lokalizacji"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Aplikacje i usługi. Jeśli wyłączysz to ustawienie, dane mikrofonu wciąż mogą być udostępniane podczas połączenia z numerem alarmowym"</string>
- <string name="location_settings_subtitle" msgid="6846532794702613851">"Aplikacje i usługi"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Dotyczy aplikacji i usług. Jeśli wyłączysz to ustawienie, dane mikrofonu wciąż mogą być udostępniane podczas połączenia z numerem alarmowym"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Dotyczy aplikacji i usług"</string>
</resources>
diff --git a/PermissionController/res/values-pl/strings.xml b/PermissionController/res/values-pl/strings.xml
index be36e5f7e..f722418c2 100644
--- a/PermissionController/res/values-pl/strings.xml
+++ b/PermissionController/res/values-pl/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Więcej"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Zezwalaj na wszystko"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Zawsze zezwalaj na wszystko"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Zezwól na ograniczony dostęp"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Wybierz zdjęcia i filmy"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Wybierz więcej"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nie wybieraj więcej"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"I tak nie zezwalaj"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Odrzuć"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> z <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Zawsze zezwalać aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na to działanie: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Zawsze zezwalać aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na to działanie: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Tylko przy używaniu aplikacji"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Zawsze"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Nie zezwalaj i nie pytaj ponownie"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikacje"</string>
<string name="app_permissions" msgid="3369917736607944781">"Uprawnienia aplikacji"</string>
<string name="unused_apps" msgid="2058057455175955094">"Nieużywane aplikacje"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edytuj zdjęcia wybrane dla tej aplikacji"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Brak nieużywanych aplikacji"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 nieużywanych aplikacji"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Ostatnie decyzje dotyczące uprawnień"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Wszystkie uprawnienia"</string>
<string name="other_permissions" msgid="2901186127193849594">"Inne funkcje aplikacji"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Prośba o pozwolenie"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear nie obsługuje instalowania ani odinstalowywania."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Wybierz, jakie uprawnienia dostępu ma mieć &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Aplikacja &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; została zaktualizowana. Wybierz dla niej uprawnienia dostępu."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Anuluj"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Usuń uprawnienia, jeśli aplikacja jest nieużywana"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Usuń uprawnienia i zwolnij miejsce"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Wstrzymuj aktywność w aplikacji, jeśli jest nieużywana"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Zarządzaj nieużywanymi aplikacjami"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Usuń uprawnienia i pliki tymczasowe oraz zatrzymaj powiadomienia"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Usuń uprawnienia i pliki tymczasowe, zatrzymaj powiadomienia i zarchiwizuj aplikację"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Aby chronić Twoje dane, usuniemy uprawnienia tej aplikacji, jeśli nie była używana od kilku miesięcy."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Aby chronić Twoje dane, jeśli aplikacja nie będzie używana przez kilka miesięcy, usuniemy te uprawnienia: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Aby chronić Twoje dane, usunęliśmy uprawnienia aplikacji, których nie używano od kilku miesięcy."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Ostatnio otwarto <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Jeśli pozwolisz zarządzać wszystkimi plikami, ta aplikacja będzie mogła odczytywać, modyfikować i usuwać dowolne pliki na tym urządzeniu lub zewnętrznych urządzeniach do przechowywania danych. Ta aplikacja może bez pytania uzyskiwać dostęp do plików."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Zezwól tej aplikacji na odczytywanie, modyfikowanie i usuwanie plików na tym urządzeniu oraz wszelkich podłączonych zewnętrznych urządzeniach do przechowywania danych. Ta aplikacja może bez pytania uzyskiwać dostęp do plików."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacje z tym uprawnieniem mogą <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacje z tym uprawnieniem mogą wykonać to działanie: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Aplikacje z tym uprawnieniem mają dostęp do danych o Twojej aktywności fizycznej takiej jak spacery, jazda na rowerze, jazda samochodem, liczba kroków i inne"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Aplikacje z tym uprawnieniem mają dostęp do kalendarza"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Aplikacje z tym uprawnieniem mogą odczytywać i zapisywać rejestr połączeń telefonicznych"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikacja do notatek"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplikacje umożliwiające robienie notatek na urządzeniu"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notatki"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Bieżąca aplikacja domyślna"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Nie pytaj ponownie"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Ustaw jako domyślną"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Pokaż wykrywanie wyzwalacza asystenta"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Pokaż ikonę na pasku stanu, gdy używany jest mikrofon do uruchomienia asystenta głosowego"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do zdjęć i multimediów na urządzeniu?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do zdjęć i multimediów na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do kontaktów?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do kontaktów na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do lokalizacji urządzenia?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do lokalizacji urządzenia &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikacja będzie mieć dostęp do lokalizacji tylko wtedy, gdy będzie używana"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do lokalizacji urządzenia?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do lokalizacji urządzenia &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Aplikacja chce mieć stały dostęp do Twojej lokalizacji, nawet gdy nie jest używana. "<annotation id="link">"Zezwól w ustawieniach"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Zmienić uprawnienia dostępu do lokalizacji w przypadku aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>”?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Zmienić dostęp aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; do lokalizacji na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Aplikacja chce mieć stały dostęp do Twojej lokalizacji, nawet gdy nie jest używana. "<annotation id="link">"Zezwól w ustawieniach"</annotation></string>
- <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na znalezienie, połączenie i ustalenie lokalizacji tego urządzenia?"</string>
- <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na znalezienie, połączenie i ustalenie lokalizacji tego urządzenia? "<annotation id="link">"Zezwól w ustawieniach."</annotation></string>
+ <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na znajdowanie urządzeń w pobliżu, ustalanie ich względnego położenia i łączenie się z nimi?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na znajdowanie urządzeń w pobliżu, ustalanie ich względnego położenia i łączenie się z nimi na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na znajdowanie urządzeń w pobliżu, ustalanie ich względnego położenia i łączenie się z nimi? "<annotation id="link">"Zezwól w ustawieniach."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Zmienić dostęp aplikacji <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> do lokalizacji przybliżonej na dostęp do lokalizacji dokładnej?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Zmienić dostęp aplikacji <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> do lokalizacji urządzenia &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; z przybliżonej na dokładną?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Zezwolić aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>” na dostęp do przybliżonej lokalizacji urządzenia?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do przybliżonej lokalizacji urządzenia &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Dokładna"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Przybliżona"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do kalendarza?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do kalendarza na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na wysyłanie i wyświetlanie SMS-ów?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na wysyłanie i wyświetlanie SMS-ów na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do zdjęć, multimediów i plików na urządzeniu?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do zdjęć, multimediów i plików na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do zdjęć, filmów, muzyki i dźwięków na tym urządzeniu?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do zdjęć, filmów, muzyki, dźwięków i innych plików na tym urządzeniu?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do muzyki i innych plików audio na tym urządzeniu?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do muzyki i innych plików audio na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do zdjęć i filmów na tym urządzeniu?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do zdjęć i filmów na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do kolejnych zdjęć i filmów na tym urządzeniu?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do kolejnych zdjęć i filmów na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na nagrywanie dźwięku?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na nagrywanie dźwięku na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikacja będzie mogła nagrywać dźwięk tylko wtedy, gdy będzie używana"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Zezwolić aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>” na nagrywanie dźwięku?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na nagrywanie dźwięku na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Ta aplikacja chce móc nagrywać dźwięk przez cały czas, nawet gdy jej nie używasz. "<annotation id="link">"Zezwól w ustawieniach."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Zmienić uprawnienia dostępu do mikrofonu w przypadku aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>”?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Zmienić dostęp aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; do mikrofonu na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Ta aplikacja chce móc nagrywać dźwięk przez cały czas, nawet gdy jej nie używasz. "<annotation id="link">"Zezwól w ustawieniach."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do aktywności fizycznej?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do aktywności fizycznej na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na robienie zdjęć i nagrywanie filmów?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na robienie zdjęć i nagrywanie filmów na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikacja będzie mogła robić zdjęcia i nagrywać filmy tylko wtedy, gdy będzie używana"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Zezwolić aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>” na robienie zdjęć i nagrywanie filmów?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na robienie zdjęć i nagrywanie filmów na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Ta aplikacja chce móc robić zdjęcia i nagrywać filmy przez cały czas, nawet gdy jej nie używasz. "<annotation id="link">"Zezwól w ustawieniach."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Zmienić uprawnienia dostępu do aparatu w przypadku aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>”?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Zmienić dostęp aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; do aparatu na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Ta aplikacja chce móc robić zdjęcia i nagrywać filmy przez cały czas, nawet gdy jej nie używasz. "<annotation id="link">"Zezwól w ustawieniach."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do rejestrów połączeń?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do rejestrów połączeń telefonicznych na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na wykonywanie połączeń telefonicznych i zarządzanie nimi?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na wykonywanie połączeń telefonicznych i zarządzanie nimi na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do danych z czujnika podstawowych funkcji życiowych?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do danych z czujnika dotyczących parametrów życiowych na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Ta aplikacja chce mieć dostęp do danych z czujnika dotyczących parametrów życiowych przez cały czas, nawet kiedy jej nie używasz. Aby dokonać tej zmiany, "<annotation id="link">"otwórz ustawienia."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do danych z czujnika podstawowych funkcji życiowych?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do danych z czujnika dotyczących parametrów życiowych na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Aby zezwolić tej aplikacji na dostęp do danych z czujników na ciele przez cały czas, nawet kiedy jej nie używasz, "<annotation id="link">"przejdź do ustawień"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Czy nadal zezwalać aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do czujników na ciele podczas jej używania?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Nadal zezwalać aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do danych z czujników na ciele na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; podczas jej używania?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na wysyłanie powiadomień?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na wysyłanie powiadomień na urządzeniu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Pozwolenia kontrolowane"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> ma dostęp do lokalizacji"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Organizacja zezwala na dostęp aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> do Twojej lokalizacji"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Inne uprawnienia"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Uprawnienia używane przez system"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Uprawnienia używane tylko przez aplikacje systemowe."</string>
@@ -572,17 +609,17 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ta aplikacja nie obsługuje najnowszej wersji Androida. Jeśli ta aplikacja nie ma dostępu do muzyki i plików audio, nie będzie również miała dostępu do zdjęć i filmów."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ta aplikacja nie obsługuje najnowszej wersji Androida. Jeśli ta aplikacja ma dostęp do zdjęć i filmów, będzie również miała dostęp do muzyki i plików audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ta aplikacja nie obsługuje najnowszej wersji Androida. Jeśli ta aplikacja nie ma dostępu do muzyki i plików audio, nie będzie również miała dostępu do zdjęć i filmów."</string>
- <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Zweryfikuj aplikację z dostępem do lokalizacji w tle"</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Zweryfikuj aplikację z dostępem w tle do lokalizacji"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Aplikacja <xliff:g id="APP_NAME">%s</xliff:g> ma dostęp do Twojej lokalizacji, nawet kiedy jest zamknięta"</string>
- <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Zweryfikuj aplikację z dostępem do lokalizacji w tle"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Zweryfikuj aplikację z dostępem w tle do lokalizacji"</string>
<string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ta aplikacja ma dostęp do Twojej lokalizacji nawet wtedy, kiedy jest zamknięta.\n\nNiektóre aplikacje z dziedziny bezpieczeństwa i alarmowe wymagają dostępu w tle do lokalizacji, aby mogły działać zgodnie z oczekiwaniami."</string>
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Uprawnienia dostępu zostały zmienione"</string>
<string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Zobacz ostatnie użycie lokalizacji"</string>
<string name="privacy_controls_title" msgid="7605929972256835199">"Ustawienia prywatności"</string>
<string name="camera_toggle_title" msgid="1251201397431837666">"Dostęp do aparatu"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Dostęp do mikrofonu"</string>
- <string name="perm_toggle_description" msgid="7801326363741451379">"Aplikacje i usługi"</string>
- <string name="mic_toggle_description" msgid="9163104307990677157">"Aplikacje i usługi. Jeśli wyłączysz to ustawienie, dane mikrofonu wciąż mogą być udostępniane podczas połączenia z numerem alarmowym."</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Dotyczy aplikacji i usług"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Dotyczy aplikacji i usług. Jeśli wyłączysz to ustawienie, dane mikrofonu wciąż mogą być udostępniane podczas połączenia z numerem alarmowym."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Wyświetl aplikacje i usługi z dostępem do lokalizacji"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Pokazuj dostęp do schowka"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Pokazuj komunikat, gdy aplikacja uzyskuje dostęp do skopiowanego tekstu, obrazów lub innych treści"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Ta aplikacja deklaruje, że może udostępniać dane o lokalizacji osobom trzecim"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Udostępnianie danych i lokalizacja"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Źródło informacji o udostępnianiu danych"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Deweloper przekazał producentowi urządzenia informacje o tym, jak aplikacja udostępnia dane. Informacje mogą być aktualizowane."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Deweloper zamieścił informacje o tym, jak aplikacja udostępnia dane, w: "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". Informacje mogą być aktualizowane."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Możliwe cele udostępniania danych o lokalizacji:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Różnice w udostępnianiu danych"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Bezpieczeństwo danych"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Dane o lokalizacji mogą być udostępniane"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Ta aplikacja deklaruje, że może udostępniać Twoje dane o lokalizacji innym podmiotom"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Nie można otworzyć tego linku"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Zmiany w udostępnianiu danych o lokalizacji"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Przejrzyj aplikacje, które zmieniły sposób udostępniania Twoich danych o lokalizacji"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Te aplikacje zmieniły sposób udostępniania Twoich danych o lokalizacji. Wcześniej mogły ich nie udostępniać lub teraz zaczęły je udostępniać w celach marketingowych."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Zmiany w udostępnianiu danych"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Niektóre aplikacje zmieniły sposób udostępniania Twoich danych o lokalizacji"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Ustawienia"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Ostatni dostęp <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Ostatni dostęp wczoraj, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Ostatni dostęp <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-pt-rBR-v33/strings.xml b/PermissionController/res/values-pt-rBR-v33/strings.xml
index 01a8edce9..aeda06c8f 100644
--- a/PermissionController/res/values-pt-rBR-v33/strings.xml
+++ b/PermissionController/res/values-pt-rBR-v33/strings.xml
@@ -40,7 +40,7 @@
<string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Chave. <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">"Alternar"</string>
<string name="safety_center_qs_open_action" msgid="2760200829912423728">"Abrir"</string>
- <string name="safety_center_review_settings_button" msgid="938981137942443930">"Revisar configura&amp;#173;ções"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Revisar configura­ções"</string>
<string name="safety_center_gear_label" msgid="5175877094379694098">"Configurações"</string>
<string name="safety_center_info_label" msgid="8993181584061825412">"Informações"</string>
</resources>
diff --git a/PermissionController/res/values-pt-rBR/strings.xml b/PermissionController/res/values-pt-rBR/strings.xml
index f0a018192..ce9b285e2 100644
--- a/PermissionController/res/values-pt-rBR/strings.xml
+++ b/PermissionController/res/values-pt-rBR/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Mais inform."</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Permitir tudo"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Sempre permitir tudo"</string>
- <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Alguns vídeos e fotos"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Permitir acesso limitado"</string>
+ <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Selecionar fotos e vídeos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Selecionar mais"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Não selecionar mais"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Não permitir mesmo assim"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Dispensar"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Sempre permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Permitir o acesso de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; a: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Sempre permitir o acesso de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; a: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Apenas ao usar o app"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Sempre"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Não permitir e não perguntar de novo"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"Permissões do app"</string>
<string name="unused_apps" msgid="2058057455175955094">"Apps não usados"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Editar fotos selecionadas para este app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nenhum app não usado"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 app não usado"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Decisões recentes de permissão"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Todas as permissões"</string>
<string name="other_permissions" msgid="2901186127193849594">"Outros recursos do app"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Solicitação de permissão"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"As ações de instalar/desinstalar não são compatíveis com o Android Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Escolha o que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; terá permissão para acessar"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"O app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; foi atualizado. Escolha o que esse app terá permissão para acessar."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancelar"</string>
@@ -198,13 +198,15 @@
<string name="app_permission_title" msgid="2090897901051370711">"Permissão para acessar <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_header" msgid="2951363137032603806">"Permitir que este app acesse: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Ver todas as permissões do app <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Ver todos os apps que têm esta permissão"</string>
+ <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Mostrar todos os apps que têm esta permissão"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Mostrar uso de microfone pelo Assistente"</string>
<string name="unused_apps_category_title" msgid="2988455616845243901">"Configurações de apps não usados"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"Remover permissões se o app não for usado"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Remover permissões e liberar espaço"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pausar atividade no app quando não usado"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gerenciar o app quando não usado"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Remove permissões, exclui arquivos temporários e para notificações"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Remover permissões, excluir arquivos temporários, parar notificações e arquivar o app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Para proteger seus dados, as permissões serão removidas se o app não for usado por alguns meses."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Para proteger seus dados, se o app não for usado por alguns meses, as seguintes permissões serão removidas: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Para proteger seus dados, as permissões de apps que não foram usados nos últimos meses foram removidas."</string>
@@ -369,7 +371,7 @@
<string name="role_sms_search_keywords" msgid="8022048144395047352">"mensagem de texto, enviar mensagens de texto, mensagens"</string>
<string name="role_emergency_label" msgid="7028825857206842366">"App padrão de emergência"</string>
<string name="role_emergency_short_label" msgid="2388431453335350348">"App de emergência"</string>
- <string name="role_emergency_description" msgid="5051840234887686630">"Apps que permitem registrar informações médicas e disponibilizá-las para socorristas, receber alertas sobre eventos climáticos graves e desastres e notificar outras pessoas se você precisar de ajuda"</string>
+ <string name="role_emergency_description" msgid="5051840234887686630">"Apps que permitem registrar informações de saúde e disponibilizá-las para socorristas, receber alertas sobre eventos climáticos graves e desastres e notificar outras pessoas se você precisar de ajuda"</string>
<string name="role_emergency_request_title" msgid="8469579020654348567">"Definir <xliff:g id="APP_NAME">%1$s</xliff:g> como app padrão de emergência?"</string>
<string name="role_emergency_request_description" msgid="131645948770262850">"Nenhuma permissão necessária"</string>
<string name="role_emergency_search_keywords" msgid="1920007722599213358">"em emergências"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"App de notas"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps que permitem a criação de notas no dispositivo"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notas"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Padrão atual"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Não perguntar novamente"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Definir como padrão"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Mostrar detecção de gatilho do assistente"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mostrar ícone na barra de status quando o microfone for usado para ativar o assistente por voz"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos e mídia no seu dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos e arquivos de mídia no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse seus contatos?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os contatos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse a localização deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse o local do seu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"O app só terá acesso ao local enquanto estiver sendo usado"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse a localização deste dispositivo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse o local do seu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Este app pode querer acessar sua localização o tempo todo, mesmo quando não estiver em uso. "<annotation id="link">"Permita o acesso nas configurações"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Mudar o acesso que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem à localização?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem ao local no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Este app quer acessar sua localização o tempo todo, mesmo quando não estiver em uso. "<annotation id="link">"Permita o acesso nas configurações"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, conecte-se e determine a posição relativa de dispositivos por perto?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, se conecte e saiba o pos. relativo de dsps. por perto no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, conecte-se e determine a posição relativa de dispositivos por perto? "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Permitir a troca para que o app <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> acesse o local exato (em vez do aproximado)?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Mudar o acesso ao local do <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; de aproximado para exato?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse o local aproximado deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse o local aproximado do seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exata"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aproximada"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse sua agenda?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse a agenda no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse e envie mensagens SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envie e acesse mensagens SMS no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos, mídia e arquivos no seu dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos, arquivos de mídia e outros arquivos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse &lt;b&gt;fotos, vídeos, músicas e áudios&lt;/b&gt; neste dispositivo?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse &lt;b&gt;fotos, vídeos, músicas, áudios e outros arquivos&lt;/b&gt; neste dispositivo?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse músicas e áudios neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse músicas e áudios no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos e vídeos neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos e vídeos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse mais fotos e vídeos neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse mais fotos e vídeos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"O app poderá gravar áudio apenas quando estiver em uso"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Este app pode querer gravar áudio a qualquer momento, mesmo quando não estiver em uso. "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem ao microfone?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem ao microfone no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Este app quer gravar áudio a qualquer momento, mesmo quando não estiver em uso. "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse sua atividade física?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os dados de atividade física no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"O app poderá tirar fotos e gravar vídeos apenas quando estiver em uso"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Este app pode querer tirar fotos e gravar vídeos a qualquer momento, mesmo quando não estiver em uso. "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem à câmera?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem à câmera no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Este app quer tirar fotos e gravar vídeos a qualquer momento, mesmo quando não estiver em uso. "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse seu registro de chamadas telefônicas?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os registros de chamadas do smartphone no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gerencie e faça chamadas telefônicas?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faça e gerencie ligações telefônicas no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os dados do sensor sobre seus sinais vitais?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse dados do sensor sobre os sinais vitais do usuário no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Este app quer acessar os dados do sensor sobre seus sinais vitais o tempo todo, mesmo quando não estiver em uso. Para fazer essa mudança, "<annotation id="link">"acesse as configurações"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os dados do sensor sobre seus sinais vitais?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os dados do sensor sobre os sinais vitais do usuário no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Para permitir que o app tenha acesso a dados do sensor corporal a qualquer momento, mesmo quando não estiver em uso, "<annotation id="link">"acesse as configurações"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Continuar permitindo que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse dados do sensor corporal enquanto estiver em uso?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Continuar permitindo que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse dados do sensor corporal durante o uso no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envie notificações?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envie notificações no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Permissões controladas"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> tem acesso à localização"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Sua organização permite que o app <xliff:g id="APP_NAME">%1$s</xliff:g> tenha acesso à sua localização"</string>
@@ -508,7 +547,7 @@
<string name="privdash_label_camera" msgid="1426440033626198096">"Câmera"</string>
<string name="privdash_label_microphone" msgid="8415035835803511693">"Microfone"</string>
<string name="privdash_label_location" msgid="6882400763866489291">"Localização"</string>
- <string name="privdash_label_other" msgid="3710394147423236033">"Outra"</string>
+ <string name="privdash_label_other" msgid="3710394147423236033">"Outras"</string>
<string name="privdash_label_none" msgid="5991866260360484858">"Nenhuma"</string>
<string name="privdash_label_24h" msgid="1512532123865375319">"Últimas\n24 horas"</string>
<string name="privdash_label_7d" msgid="5645301995348656931">"Nos últimos\nsete dias"</string>
@@ -532,7 +571,7 @@
<string name="security_settings" msgid="3808106921175271317">"Configurações de segurança"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"Permissões"</string>
<string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Segurança e privacidade"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Ver status"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Checar status"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Seus controles de privacidade"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Mais configurações"</string>
<string name="camera_toggle_label_qs" msgid="3880261453066157285">"Acesso à câmera"</string>
@@ -547,7 +586,7 @@
<string name="active_call_usage_qs" msgid="8559974395932523391">"Em uso pela chamada telefônica"</string>
<string name="recent_call_usage_qs" msgid="743044899599410935">"Usada recentemente em uma chamada telefônica"</string>
<string name="active_app_usage_qs" msgid="4063912870936464727">"Em uso por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="recent_app_usage_qs" msgid="6650259601306212327">"Usada recentemente por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="recent_app_usage_qs" msgid="6650259601306212327">"Uso recente por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="active_app_usage_1_qs" msgid="4325136375823357052">"Em uso por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Usada recentemente por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="active_app_usage_2_qs" msgid="6107866785243565283">"Em uso por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
@@ -575,7 +614,7 @@
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Revisar apps com acesso à localização em segundo plano"</string>
<string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Este app sempre pode acessar sua localização, mesmo quando está fechado.\n\nAlguns apps de segurança e emergência exigem acesso à sua localização em segundo plano para funcionar corretamente."</string>
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"O acesso foi mudado"</string>
- <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Ver o uso recente da localização"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Verificar o uso recente da localização"</string>
<string name="privacy_controls_title" msgid="7605929972256835199">"Controles de privacidade"</string>
<string name="camera_toggle_title" msgid="1251201397431837666">"Acesso à câmera"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Acesso ao microfone"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Este app declarou que pode compartilhar dados de local com terceiros"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Local e compartilhamento de dados"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"De onde vêm as informações do compartilhamento de dados"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"O desenvolvedor forneceu informações para o fabricante do dispositivo sobre como este app compartilha dados. O desenvolvedor pode atualizar essas informações com o tempo."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"O desenvolvedor forneceu informações para "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" sobre como esse app compartilha dados. O desenvolvedor pode atualizar essas informações com o tempo."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Esse app pode compartilhar dados de local para:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"O compartilhamento de dados varia"</string>
@@ -606,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Segurança dos dados"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Os dados de local podem ser compartilhados"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Este app indicou que pode compartilhar seus dados de local com terceiros"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Não é possível abrir esse link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Atualizações no compartilhamento de dados de local"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"Revise os apps que mudaram a forma de compartilhar os dados de local"</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"Conferir apps que mudaram a forma de compartilhar dados de local"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Esses apps mudaram a forma de compartilhar os dados de local. É possível que eles não tenham compartilhado antes ou que agora compartilhem para fins de publicidade ou marketing."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Os desenvolvedores desses apps oferecem informações sobre as práticas deles de compartilhamento de dados com uma app store. Eles podem atualizar essas informações com o tempo.\n\nAs práticas de compartilhamento de dados podem variar de acordo com a versão do app e com a idade, o uso e a região do usuário."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Saiba mais sobre o compartilhamento de dados"</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Atualizações do compartilhamento de dados"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Alguns apps mudaram a forma como podem compartilhar seus dados de local"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Configurações"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Último acesso: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Último acesso: ontem, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Último acesso: <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-pt-rPT-v33/strings.xml b/PermissionController/res/values-pt-rPT-v33/strings.xml
index cb7bac394..a228677bf 100644
--- a/PermissionController/res/values-pt-rPT-v33/strings.xml
+++ b/PermissionController/res/values-pt-rPT-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Mais alertas"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertas ignorados"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Expandir e ver mais um alerta}many{Expandir e ver mais # alertas}other{Expandir e ver mais # alertas}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerta. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Ação concluída"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Verifique as definições que podem adicionar proteção ao seu dispositivo"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Definições rápidas de segurança e privacidade"</string>
diff --git a/PermissionController/res/values-pt-rPT/strings.xml b/PermissionController/res/values-pt-rPT/strings.xml
index 1c9eda5c6..ca1ee265a 100644
--- a/PermissionController/res/values-pt-rPT/strings.xml
+++ b/PermissionController/res/values-pt-rPT/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Mais informação"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Permitir todos"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Permitir sempre todos"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Permitir acesso limitado"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Selecionar fotos e vídeos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Selecionar mais"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Não selecionar mais"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Não permitir mesmo assim"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Ignorar"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Permitir a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g> sempre?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Permitir a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; o seguinte? <xliff:g id="ACTION">%2$s</xliff:g>"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Permitir sempre isto à app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;? <xliff:g id="ACTION">%2$s</xliff:g>"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Apenas ao utilizar a app"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Sempre"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Não permitir e não perguntar novamente"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"Autorizações da app"</string>
<string name="unused_apps" msgid="2058057455175955094">"Apps não usadas"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Edite as fotos selecionadas para esta app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nenhuma app não usada"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 apps não utilizadas"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Decisões de autorização recentes"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Todas as autorizações"</string>
<string name="other_permissions" msgid="2901186127193849594">"Outras capacidades de aplicações"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Pedido de autorização"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"As ações de instalar/desinstalar não são compatíveis com o Android Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Escolher a que conteúdos permite que o &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"O &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; foi atualizado. Escolha a que conteúdos permite que esta app aceda."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancelar"</string>
@@ -126,7 +126,7 @@
<string name="app_name_unknown" msgid="1319665005754048952">"Desconhecido"</string>
<string name="permission_usage_title" msgid="1568233336351734538">"Painel de privacidade"</string>
<string name="auto_permission_usage_summary" msgid="7335667266743337075">"Veja que apps utilizaram autorizações recentemente"</string>
- <string name="permission_group_usage_title" msgid="2595013198075285173">"utilização de <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
+ <string name="permission_group_usage_title" msgid="2595013198075285173">"Utilização de <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Veja outras autorizações"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
<string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> e mais <xliff:g id="NUM">%3$s</xliff:g>"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Remover autorizações se a app não for utilizada"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Remover autorizações e libertar espaço"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pausar atividade de apps, se não usadas"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gerir app, se não for usada"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Remova autorizações, elimine ficheiros temporários e pare notificações"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Remova autorizações, elimine ficheiros temporários, pare notificações e arquive a app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Para proteger os seus dados, as autorizações desta app serão removidas se a mesma não for utilizada durante alguns meses."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Para proteger os seus dados, se a app não for utilizada há alguns meses, serão removidas as seguintes autorizações: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Para proteger os seus dados, foram removidas as autorizações para as apps que não utiliza há alguns meses."</string>
@@ -351,43 +353,43 @@
<string name="role_assistant_short_label" msgid="3369003713187703399">"App assistente digital"</string>
<string name="role_assistant_description" msgid="6622458130459922952">"As apps de assistência podem ajudá-lo com base em informações do ecrã que está a ver. Algumas apps são compatíveis com serviços de iniciação e de entrada de texto por voz para oferecer assistência integrada."</string>
<string name="role_browser_label" msgid="2877796144554070207">"App navegador predefinida"</string>
- <string name="role_browser_short_label" msgid="6745009127123292296">"Aplicação de navegador"</string>
+ <string name="role_browser_short_label" msgid="6745009127123292296">"App de navegador"</string>
<string name="role_browser_description" msgid="3465253637499842671">"Apps que lhe dão acesso à Internet e apresentam links em que pode tocar."</string>
- <string name="role_browser_request_title" msgid="2895200507835937192">"Pretende definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de navegador predefinida?"</string>
+ <string name="role_browser_request_title" msgid="2895200507835937192">"Quer definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de navegador predefinida?"</string>
<string name="role_browser_request_description" msgid="5888803407905985941">"Não são necessárias autorizações."</string>
<string name="role_dialer_label" msgid="1100224146343237968">"App de telefone predefinida"</string>
<string name="role_dialer_short_label" msgid="7186888549465352489">"App Telefone"</string>
<string name="role_dialer_description" msgid="8768708633696539612">"Apps que permitem efetuar e receber chamadas no seu dispositivo."</string>
- <string name="role_dialer_request_title" msgid="5959618560705912058">"Pretende definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de telefone predefinida?"</string>
+ <string name="role_dialer_request_title" msgid="5959618560705912058">"Quer definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de telefone predefinida?"</string>
<string name="role_dialer_request_description" msgid="6288839625724909320">"Esta app fica com acesso à sua Câmara, Contactos, Microfone, Telefone e SMS"</string>
<string name="role_dialer_search_keywords" msgid="3324448983559188087">"telefone"</string>
<string name="role_sms_label" msgid="8456999857547686640">"App de SMS predefinida"</string>
- <string name="role_sms_short_label" msgid="4371444488034692243">"Aplicação de SMS"</string>
+ <string name="role_sms_short_label" msgid="4371444488034692243">"App de SMS"</string>
<string name="role_sms_description" msgid="3424020199148153513">"Apps que permitem utilizar o seu número de telefone para enviar e receber mensagens de texto, fotos, vídeos e muito mais."</string>
- <string name="role_sms_request_title" msgid="7953552109601185602">"Pretende definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como app SMS predefinida?"</string>
+ <string name="role_sms_request_title" msgid="7953552109601185602">"Quer definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como app SMS predefinida?"</string>
<string name="role_sms_request_description" msgid="2691004766132144886">"Esta app fica com acesso à sua Câmara, Contactos, Ficheiros e multimédia, Microfone, Telefone e SMS"</string>
<string name="role_sms_search_keywords" msgid="8022048144395047352">"mensagem de texto, enviar mensagens de texto, mensagens"</string>
<string name="role_emergency_label" msgid="7028825857206842366">"Aplicação de emergência pred."</string>
<string name="role_emergency_short_label" msgid="2388431453335350348">"Aplicação de emergência"</string>
<string name="role_emergency_description" msgid="5051840234887686630">"Apps que permitem registar as suas informações médicas e disponibilizá-las aos contactos de resposta a emergências, receber alertas acerca de eventos atmosféricos e desastres graves, bem como notificar outras pessoas quando precisar de ajuda."</string>
- <string name="role_emergency_request_title" msgid="8469579020654348567">"Pretende definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de emergência predefinida?"</string>
+ <string name="role_emergency_request_title" msgid="8469579020654348567">"Quer definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de emergência predefinida?"</string>
<string name="role_emergency_request_description" msgid="131645948770262850">"Não são necessárias autorizações."</string>
<string name="role_emergency_search_keywords" msgid="1920007722599213358">"em caso de emergência"</string>
<string name="role_home_label" msgid="3871847846649769412">"App página inicial predefinida"</string>
<string name="role_home_short_label" msgid="8544733747952272337">"App Página inicial"</string>
<string name="role_home_description" msgid="7997371519626556675">"Apps, frequentemente denominadas iniciadores, que substituem os ecrãs principais no dispositivo Android e dão acesso aos conteúdos e às funcionalidades do seu dispositivo."</string>
- <string name="role_home_request_title" msgid="738136983453341081">"Pretende definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app Página inicial predefinida?"</string>
+ <string name="role_home_request_title" msgid="738136983453341081">"Quer definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app Página inicial predefinida?"</string>
<string name="role_home_request_description" msgid="2658833966716057673">"Não são necessárias autorizações."</string>
<string name="role_home_search_keywords" msgid="3830755001192666285">"iniciador"</string>
<string name="role_call_redirection_label" msgid="5785304207206147590">"Aplic. redirec. chamadas pred."</string>
<string name="role_call_redirection_short_label" msgid="7568143419571217757">"Aplic. de redirec. de chamadas"</string>
<string name="role_call_redirection_description" msgid="6091669882014664420">"Apps que permitem encaminhar chamadas efetuadas para outro número de telefone."</string>
- <string name="role_call_redirection_request_title" msgid="2816244455003562925">"Pretende definir <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de redirecionamento de chamadas predefinida?"</string>
+ <string name="role_call_redirection_request_title" msgid="2816244455003562925">"Quer definir <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de redirecionamento de chamadas predefinida?"</string>
<string name="role_call_redirection_request_description" msgid="3118895714178527164">"Não são necessárias autorizações."</string>
<string name="role_call_screening_label" msgid="883935222060878724">"App de filtro de chamadas e spam"</string>
<string name="role_call_screening_short_label" msgid="2048465565063130834">"App de ID de chamada e spam"</string>
<string name="role_call_screening_description" msgid="2349431420497468981">"Apps que lhe permitem identificar chamadas e bloquear spam, chamadas automáticas ou números indesejados."</string>
- <string name="role_call_screening_request_title" msgid="7358309224566977290">"Pretende definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de identificação de chamadas e spam predefinida?"</string>
+ <string name="role_call_screening_request_title" msgid="7358309224566977290">"Quer definir o <xliff:g id="APP_NAME">%1$s</xliff:g> como a app de identificação de chamadas e spam predefinida?"</string>
<string name="role_call_screening_request_description" msgid="7338511921032446006">"Não são necessárias autorizações."</string>
<string name="role_automotive_navigation_label" msgid="2701890757955474751">"App de navegação predefinida"</string>
<string name="role_automotive_navigation_short_label" msgid="5165823092506922457">"App de navegação"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"App de notas"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps que lhe permitem tirar notas no seu dispositivo"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notas"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Predefinição atual"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Não perguntar novamente"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Definir como predef."</string>
@@ -437,11 +449,11 @@
<string name="special_app_access_no_apps" msgid="4102911722787886970">"Sem apps"</string>
<string name="home_missing_work_profile_support" msgid="1756855847669387977">"Não suporta o perfil de trabalho."</string>
<string name="encryption_unaware_confirmation_message" msgid="8274491794636402484">"Nota: se reiniciar o dispositivo e tiver um bloqueio de ecrã definido, só é possível iniciar esta app quando o dispositivo for desbloqueado."</string>
- <string name="assistant_confirmation_message" msgid="7476540402884416212">"O assistente pode ler informações sobre aplicações em utilização no seu sistema, incluindo informações visíveis no ecrã ou acessíveis nas aplicações."</string>
+ <string name="assistant_confirmation_message" msgid="7476540402884416212">"O assistente pode ler informações sobre as apps em utilização no seu sistema, incluindo informações visíveis no ecrã ou acessíveis nas apps."</string>
<string name="incident_report_channel_name" msgid="3144954065936288440">"Partilhar dados de depuração"</string>
- <string name="incident_report_notification_title" msgid="4635984625656519773">"Pretende partilhar dados de depuração detalhados?"</string>
- <string name="incident_report_notification_text" msgid="3376480583513587923">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> pretende carregar informações de depuração."</string>
- <string name="incident_report_dialog_title" msgid="669104389325204095">"Pretende partilhar dados de depuração?"</string>
+ <string name="incident_report_notification_title" msgid="4635984625656519773">"Quer partilhar dados de depuração detalhados?"</string>
+ <string name="incident_report_notification_text" msgid="3376480583513587923">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> quer carregar informações de depuração."</string>
+ <string name="incident_report_dialog_title" msgid="669104389325204095">"Quer partilhar dados de depuração?"</string>
<string name="incident_report_dialog_intro" msgid="5897733669850951832">"O sistema detetou um problema."</string>
<string name="incident_report_dialog_text" msgid="5675553296891757523">"A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> está a solicitar o carregamento de um relatório de erro a partir deste dispositivo realizado a <xliff:g id="DATE">%2$s</xliff:g> à(s) <xliff:g id="TIME">%3$s</xliff:g>. Os relatórios de erros incluem informações pessoais acerca do seu dispositivo ou registadas por app, por exemplo, nomes de utilizador, dados de localização, identificadores do dispositivo e informações da rede. Apenas partilhe relatórios de erros com pessoas e apps nas quais confia. Permite que a app <xliff:g id="APP_NAME_1">%4$s</xliff:g> carregue um relatório de erro?"</string>
<string name="incident_report_error_dialog_text" msgid="4189647113387092272">"Ocorreu um erro ao processar o relatório de erro para a app <xliff:g id="APP_NAME">%1$s</xliff:g>. Como tal, a partilha dos dados de depuração detalhados foi negada. Pedimos desculpa pela interrupção."</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Mostre a deteção do acionador do assistente"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mostre o ícone na barra de estado quando o microfone é utilizado para ativar o assistente de voz"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a fotos e multimédia no dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a fotos e multimédia no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos seus contactos?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos contactos no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda à localização deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda à localização do &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"A app tem acesso à localização apenas enquanto a estiver a utilizar"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda à localização deste dispositivo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda à localização do &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Esta app poderá pretender aceder sempre à sua localização, mesmo quando não a estiver a utilizar. "<annotation id="link">"Permita-o nas definições."</annotation></string>
- <string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Pretende alterar o acesso à localização para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Esta app pretende aceder sempre à sua localização, mesmo quando não a estiver a utilizar. "<annotation id="link">"Permita-o nas definições."</annotation></string>
+ <string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Quer alterar o acesso à localização para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Alterar o acesso à localização para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Esta app quer aceder sempre à sua localização, mesmo quando não a estiver a utilizar. "<annotation id="link">"Permita-o nas definições."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, determine a posição relativa dos dispositivos próximos e se ligue aos mesmos?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, ligue e determine a posição de dispositivos próximos no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, determine a posição relativa dos dispositivos próximos e se ligue aos mesmos? "<annotation id="link">"Permita nas Definições."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Alterar o acesso à localização da app <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> de aproximada para exata?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Alterar o acesso à localização para a app <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; de aproximada para exata?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda à localização aproximada deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda à localização aproximada do &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exata"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aproximada"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda ao calendário?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda ao calendário no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envie e veja mensagens SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envie e veja mensagens SMS no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a fotos, multimédia e ficheiros no dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a fotos, multimédia e ficheiros no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a &lt;b&gt;fotos, vídeos, música e áudio&lt;/b&gt; neste dispositivo?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a &lt;b&gt;fotos, vídeos, música, áudio, etc.&lt;/b&gt; neste dispositivo?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a música e áudio neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a música e áudio no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a fotos e vídeos neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a fotos e vídeos no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a mais fotos e vídeos neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a mais fotos e vídeos no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"A app apenas poderá gravar áudio enquanto a estiver a utilizar."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Esta app pode pretender gravar áudio sempre, mesmo quando não a está a utilizar. "<annotation id="link">"Permita-o nas Definições."</annotation></string>
- <string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Pretende alterar o acesso ao microfone para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Esta app pretende gravar áudio sempre, mesmo quando não a está a utilizar. "<annotation id="link">"Permita-o nas Definições."</annotation></string>
+ <string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Quer alterar o acesso ao microfone para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Alterar o acesso ao microfone para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Esta app quer gravar áudio sempre, mesmo quando não a está a utilizar. "<annotation id="link">"Permita-o nas Definições."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda à sua atividade física?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda à sua atividade física no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeo?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; capture fotos e vídeos no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"A app apenas poderá tirar fotos e gravar vídeos enquanto a estiver a utilizar."</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; capture fotos e vídeos no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Esta app pode pretender tirar fotos e gravar vídeos sempre, mesmo quando não a está a utilizar. "<annotation id="link">"Permita-o nas Definições."</annotation></string>
- <string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Pretende alterar o acesso à câmara para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Esta app pretende tirar fotos e gravar vídeos sempre, mesmo quando não a está a utilizar. "<annotation id="link">"Permita-o nas Definições."</annotation></string>
+ <string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Quer alterar o acesso à câmara para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Alterar o acesso à câmara para a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Esta app quer tirar fotos e gravar vídeos sempre, mesmo quando não a está a utilizar. "<annotation id="link">"Permita-o nas Definições."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos registos de chamadas do seu telemóvel?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos registos de chamadas telefónicas no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faça e gira chamadas telefónicas?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faça e gira chamadas no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos dados de sensores acerca dos seus sinais vitais?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos dados de sensores sobre os seus sinais vitais no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Esta app quer aceder sempre aos dados de sensores sobre os seus sinais vitais, mesmo quando não a estiver a usar. Para fazer esta alteração, "<annotation id="link">"aceda às definições."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos dados de sensores acerca dos seus sinais vitais?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos dados de sensores sobre os seus sinais vitais no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Para permitir que esta app aceda sempre aos dados de sensores de corpo, mesmo quando não está a usá-la, "<annotation id="link">"aceda às definições."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Continuar a permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda aos dados de sensores de corpo enquanto usa a app?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Continuar a permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aceda a dados de sensores de corpo no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; quando usa a app?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lhe envie notificações?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Permitir que a app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lhe envie notificações para o &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Autorizações controladas"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> tem acesso à localização"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"A sua organização permite que a app <xliff:g id="APP_NAME">%1$s</xliff:g> aceda à sua localização"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Outras autorizações"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Autorização utilizada pelo sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Autorizações utilizadas apenas pelas aplicações do sistema."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Esta app declarou que pode partilhar dados de localização com terceiros"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Localização e partilha de dados"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Qual é a origem das informações da partilha de dados"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"O programador deu informações ao fabricante deste dispositivo sobre como esta app partilha dados. O programador pode atualizar estas informações ao longo do tempo."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"O programador forneceu informações a "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" sobre como esta app partilha dados. O programador pode atualizar estas informações ao longo do tempo."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Esta app pode partilhar dados de localização para:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"A partilha de dados varia"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Segurança dos dados"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Os dados de localização podem ser partilhados"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Esta app declarou que pode partilhar os seus dados de localização com terceiros"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Não é possível abrir este link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Atualizações da partilha de dados para a localização"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Reveja apps que mudaram a forma como podem partilhar os seus dados de localização"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Estas apps mudaram a forma como podem partilhar os seus dados de localização. Podem não os ter partilhado antes ou podem partilhá-los agora para fins de publicidade ou marketing."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Atualizações da partilha de dados"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Algumas apps alteraram a forma como podem partilhar os seus dados de localização"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Definições"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Acedido à(s) <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Acedido ontem à(s) <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Acedido a <xliff:g id="TIME_DATE_0">%1$s</xliff:g> à(s) <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-pt-v33/strings.xml b/PermissionController/res/values-pt-v33/strings.xml
index 01a8edce9..aeda06c8f 100644
--- a/PermissionController/res/values-pt-v33/strings.xml
+++ b/PermissionController/res/values-pt-v33/strings.xml
@@ -40,7 +40,7 @@
<string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Chave. <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">"Alternar"</string>
<string name="safety_center_qs_open_action" msgid="2760200829912423728">"Abrir"</string>
- <string name="safety_center_review_settings_button" msgid="938981137942443930">"Revisar configura&amp;#173;ções"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Revisar configura­ções"</string>
<string name="safety_center_gear_label" msgid="5175877094379694098">"Configurações"</string>
<string name="safety_center_info_label" msgid="8993181584061825412">"Informações"</string>
</resources>
diff --git a/PermissionController/res/values-pt/strings.xml b/PermissionController/res/values-pt/strings.xml
index f0a018192..ce9b285e2 100644
--- a/PermissionController/res/values-pt/strings.xml
+++ b/PermissionController/res/values-pt/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Mais inform."</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Permitir tudo"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Sempre permitir tudo"</string>
- <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Alguns vídeos e fotos"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Permitir acesso limitado"</string>
+ <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Selecionar fotos e vídeos"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Selecionar mais"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Não selecionar mais"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Não permitir mesmo assim"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Dispensar"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> de <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Sempre permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Permitir o acesso de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; a: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Sempre permitir o acesso de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; a: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Apenas ao usar o app"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Sempre"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Não permitir e não perguntar de novo"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Apps"</string>
<string name="app_permissions" msgid="3369917736607944781">"Permissões do app"</string>
<string name="unused_apps" msgid="2058057455175955094">"Apps não usados"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Editar fotos selecionadas para este app"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nenhum app não usado"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 app não usado"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Decisões recentes de permissão"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Todas as permissões"</string>
<string name="other_permissions" msgid="2901186127193849594">"Outros recursos do app"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Solicitação de permissão"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"As ações de instalar/desinstalar não são compatíveis com o Android Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Escolha o que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; terá permissão para acessar"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"O app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; foi atualizado. Escolha o que esse app terá permissão para acessar."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Cancelar"</string>
@@ -198,13 +198,15 @@
<string name="app_permission_title" msgid="2090897901051370711">"Permissão para acessar <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_header" msgid="2951363137032603806">"Permitir que este app acesse: <xliff:g id="PERM">%1$s</xliff:g>"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Ver todas as permissões do app <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Ver todos os apps que têm esta permissão"</string>
+ <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Mostrar todos os apps que têm esta permissão"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Mostrar uso de microfone pelo Assistente"</string>
<string name="unused_apps_category_title" msgid="2988455616845243901">"Configurações de apps não usados"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"Remover permissões se o app não for usado"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Remover permissões e liberar espaço"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pausar atividade no app quando não usado"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gerenciar o app quando não usado"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Remove permissões, exclui arquivos temporários e para notificações"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Remover permissões, excluir arquivos temporários, parar notificações e arquivar o app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Para proteger seus dados, as permissões serão removidas se o app não for usado por alguns meses."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Para proteger seus dados, se o app não for usado por alguns meses, as seguintes permissões serão removidas: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Para proteger seus dados, as permissões de apps que não foram usados nos últimos meses foram removidas."</string>
@@ -369,7 +371,7 @@
<string name="role_sms_search_keywords" msgid="8022048144395047352">"mensagem de texto, enviar mensagens de texto, mensagens"</string>
<string name="role_emergency_label" msgid="7028825857206842366">"App padrão de emergência"</string>
<string name="role_emergency_short_label" msgid="2388431453335350348">"App de emergência"</string>
- <string name="role_emergency_description" msgid="5051840234887686630">"Apps que permitem registrar informações médicas e disponibilizá-las para socorristas, receber alertas sobre eventos climáticos graves e desastres e notificar outras pessoas se você precisar de ajuda"</string>
+ <string name="role_emergency_description" msgid="5051840234887686630">"Apps que permitem registrar informações de saúde e disponibilizá-las para socorristas, receber alertas sobre eventos climáticos graves e desastres e notificar outras pessoas se você precisar de ajuda"</string>
<string name="role_emergency_request_title" msgid="8469579020654348567">"Definir <xliff:g id="APP_NAME">%1$s</xliff:g> como app padrão de emergência?"</string>
<string name="role_emergency_request_description" msgid="131645948770262850">"Nenhuma permissão necessária"</string>
<string name="role_emergency_search_keywords" msgid="1920007722599213358">"em emergências"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"App de notas"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Apps que permitem a criação de notas no dispositivo"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notas"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Padrão atual"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Não perguntar novamente"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Definir como padrão"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Mostrar detecção de gatilho do assistente"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Mostrar ícone na barra de status quando o microfone for usado para ativar o assistente por voz"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos e mídia no seu dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos e arquivos de mídia no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse seus contatos?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os contatos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse a localização deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse o local do seu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"O app só terá acesso ao local enquanto estiver sendo usado"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse a localização deste dispositivo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse o local do seu &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Este app pode querer acessar sua localização o tempo todo, mesmo quando não estiver em uso. "<annotation id="link">"Permita o acesso nas configurações"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Mudar o acesso que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem à localização?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem ao local no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Este app quer acessar sua localização o tempo todo, mesmo quando não estiver em uso. "<annotation id="link">"Permita o acesso nas configurações"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, conecte-se e determine a posição relativa de dispositivos por perto?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, se conecte e saiba o pos. relativo de dsps. por perto no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; encontre, conecte-se e determine a posição relativa de dispositivos por perto? "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Permitir a troca para que o app <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> acesse o local exato (em vez do aproximado)?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Mudar o acesso ao local do <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; de aproximado para exato?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse o local aproximado deste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse o local aproximado do seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exata"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aproximada"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse sua agenda?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse a agenda no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse e envie mensagens SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envie e acesse mensagens SMS no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos, mídia e arquivos no seu dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos, arquivos de mídia e outros arquivos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse &lt;b&gt;fotos, vídeos, músicas e áudios&lt;/b&gt; neste dispositivo?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse &lt;b&gt;fotos, vídeos, músicas, áudios e outros arquivos&lt;/b&gt; neste dispositivo?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse músicas e áudios neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse músicas e áudios no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos e vídeos neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse fotos e vídeos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse mais fotos e vídeos neste dispositivo?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse mais fotos e vídeos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"O app poderá gravar áudio apenas quando estiver em uso"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; grave áudio no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Este app pode querer gravar áudio a qualquer momento, mesmo quando não estiver em uso. "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem ao microfone?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem ao microfone no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Este app quer gravar áudio a qualquer momento, mesmo quando não estiver em uso. "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse sua atividade física?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os dados de atividade física no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"O app poderá tirar fotos e gravar vídeos apenas quando estiver em uso"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Este app pode querer tirar fotos e gravar vídeos a qualquer momento, mesmo quando não estiver em uso. "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem à câmera?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Mudar o acesso que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tem à câmera no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Este app quer tirar fotos e gravar vídeos a qualquer momento, mesmo quando não estiver em uso. "<annotation id="link">"Permita nas configurações."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse seu registro de chamadas telefônicas?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os registros de chamadas do smartphone no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gerencie e faça chamadas telefônicas?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faça e gerencie ligações telefônicas no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os dados do sensor sobre seus sinais vitais?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse dados do sensor sobre os sinais vitais do usuário no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Este app quer acessar os dados do sensor sobre seus sinais vitais o tempo todo, mesmo quando não estiver em uso. Para fazer essa mudança, "<annotation id="link">"acesse as configurações"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os dados do sensor sobre seus sinais vitais?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse os dados do sensor sobre os sinais vitais do usuário no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Para permitir que o app tenha acesso a dados do sensor corporal a qualquer momento, mesmo quando não estiver em uso, "<annotation id="link">"acesse as configurações"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Continuar permitindo que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse dados do sensor corporal enquanto estiver em uso?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Continuar permitindo que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse dados do sensor corporal durante o uso no &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envie notificações?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envie notificações no seu &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Permissões controladas"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> tem acesso à localização"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Sua organização permite que o app <xliff:g id="APP_NAME">%1$s</xliff:g> tenha acesso à sua localização"</string>
@@ -508,7 +547,7 @@
<string name="privdash_label_camera" msgid="1426440033626198096">"Câmera"</string>
<string name="privdash_label_microphone" msgid="8415035835803511693">"Microfone"</string>
<string name="privdash_label_location" msgid="6882400763866489291">"Localização"</string>
- <string name="privdash_label_other" msgid="3710394147423236033">"Outra"</string>
+ <string name="privdash_label_other" msgid="3710394147423236033">"Outras"</string>
<string name="privdash_label_none" msgid="5991866260360484858">"Nenhuma"</string>
<string name="privdash_label_24h" msgid="1512532123865375319">"Últimas\n24 horas"</string>
<string name="privdash_label_7d" msgid="5645301995348656931">"Nos últimos\nsete dias"</string>
@@ -532,7 +571,7 @@
<string name="security_settings" msgid="3808106921175271317">"Configurações de segurança"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"Permissões"</string>
<string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Segurança e privacidade"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Ver status"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Checar status"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Seus controles de privacidade"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Mais configurações"</string>
<string name="camera_toggle_label_qs" msgid="3880261453066157285">"Acesso à câmera"</string>
@@ -547,7 +586,7 @@
<string name="active_call_usage_qs" msgid="8559974395932523391">"Em uso pela chamada telefônica"</string>
<string name="recent_call_usage_qs" msgid="743044899599410935">"Usada recentemente em uma chamada telefônica"</string>
<string name="active_app_usage_qs" msgid="4063912870936464727">"Em uso por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="recent_app_usage_qs" msgid="6650259601306212327">"Usada recentemente por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="recent_app_usage_qs" msgid="6650259601306212327">"Uso recente por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="active_app_usage_1_qs" msgid="4325136375823357052">"Em uso por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Usada recentemente por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="active_app_usage_2_qs" msgid="6107866785243565283">"Em uso por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
@@ -575,7 +614,7 @@
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Revisar apps com acesso à localização em segundo plano"</string>
<string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Este app sempre pode acessar sua localização, mesmo quando está fechado.\n\nAlguns apps de segurança e emergência exigem acesso à sua localização em segundo plano para funcionar corretamente."</string>
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"O acesso foi mudado"</string>
- <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Ver o uso recente da localização"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Verificar o uso recente da localização"</string>
<string name="privacy_controls_title" msgid="7605929972256835199">"Controles de privacidade"</string>
<string name="camera_toggle_title" msgid="1251201397431837666">"Acesso à câmera"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Acesso ao microfone"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Este app declarou que pode compartilhar dados de local com terceiros"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Local e compartilhamento de dados"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"De onde vêm as informações do compartilhamento de dados"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"O desenvolvedor forneceu informações para o fabricante do dispositivo sobre como este app compartilha dados. O desenvolvedor pode atualizar essas informações com o tempo."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"O desenvolvedor forneceu informações para "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" sobre como esse app compartilha dados. O desenvolvedor pode atualizar essas informações com o tempo."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Esse app pode compartilhar dados de local para:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"O compartilhamento de dados varia"</string>
@@ -606,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Segurança dos dados"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Os dados de local podem ser compartilhados"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Este app indicou que pode compartilhar seus dados de local com terceiros"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Não é possível abrir esse link"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Atualizações no compartilhamento de dados de local"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"Revise os apps que mudaram a forma de compartilhar os dados de local"</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"Conferir apps que mudaram a forma de compartilhar dados de local"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Esses apps mudaram a forma de compartilhar os dados de local. É possível que eles não tenham compartilhado antes ou que agora compartilhem para fins de publicidade ou marketing."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Os desenvolvedores desses apps oferecem informações sobre as práticas deles de compartilhamento de dados com uma app store. Eles podem atualizar essas informações com o tempo.\n\nAs práticas de compartilhamento de dados podem variar de acordo com a versão do app e com a idade, o uso e a região do usuário."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Saiba mais sobre o compartilhamento de dados"</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Atualizações do compartilhamento de dados"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Alguns apps mudaram a forma como podem compartilhar seus dados de local"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Configurações"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Último acesso: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Último acesso: ontem, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Último acesso: <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-ro-v33/strings.xml b/PermissionController/res/values-ro-v33/strings.xml
index 3715a4414..a32a32db5 100644
--- a/PermissionController/res/values-ro-v33/strings.xml
+++ b/PermissionController/res/values-ro-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Mai multe alerte"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alerte respinse"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Extinde și mai vezi o alertă}few{Extinde și mai vezi # alerte}other{Extinde și mai vezi # de alerte}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alertă. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Acțiune încheiată"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Verifică setările care pot spori protecția dispozitivului"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Setări rapide privind securitatea și confidențialitatea"</string>
diff --git a/PermissionController/res/values-ro/strings.xml b/PermissionController/res/values-ro/strings.xml
index d0a18327a..c11841619 100644
--- a/PermissionController/res/values-ro/strings.xml
+++ b/PermissionController/res/values-ro/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Mai multe info."</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Permite-le pe toate"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Permite-le întotdeauna pe toate"</string>
- <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Alege fotografii și videoclipuri."</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Permite cu acces limitat"</string>
+ <string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Alege fotografii și videoclipuri"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Selectează mai multe"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nu selecta mai multe"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Nu permite în nicio situație"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Închide"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> din <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="permission_warning_template" msgid="2247087781222679458">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Permiți întotdeauna &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Permiți întotdeauna ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Doar când folosești aplicația"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Mereu"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Nu permite și nu mai întreba"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplicații"</string>
<string name="app_permissions" msgid="3369917736607944781">"Permisiuni pentru aplicații"</string>
<string name="unused_apps" msgid="2058057455175955094">"Aplicații nefolosite"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Editează fotografiile selectate pentru această aplicație"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nu există aplicații nefolosite"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 aplicații nefolosite"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Decizii recente privind permisiunile"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Toate permisiunile"</string>
<string name="other_permissions" msgid="2901186127193849594">"Alte funcții ale aplicației"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Solicitare de permisiune"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Acțiunile Instalează/Dezinstalează nu sunt acceptate pe Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Alege ce va putea accesa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Aplicația &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; a fost actualizată. Alege ce va putea accesa această aplicație."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Anulează"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Elimină permisiunile dacă aplicația nu este folosită"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Revocă permisiunile și eliberează spațiu"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Întrerupe activitatea în aplicațiile nefolosite"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Gestionează aplicația dacă nu e folosită"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Revocă permisiunile, șterge fișierele temporare și oprește notificările"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Elimină permisiunile, șterge fișierele temporare, oprește notificările și arhivează aplicația"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Pentru a-ți proteja datele, se vor elimina permisiunile pentru această aplicație dacă nu este folosită câteva luni."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Pentru a-ți proteja datele, dacă aplicația nu este folosită câteva luni, se vor elimina următoarele permisiuni: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Pentru a-ți proteja datele, s-au eliminat permisiunile din aplicațiile pe care nu le-ai folosit de câteva luni."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplicația pentru note"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplicații cu ajutorul cărora poți să iei notițe pe dispozitiv"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notițe"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Aplicația prestabilită actuală"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Nu mai întreba"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Setează ca prestabilită"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Afișează detectarea declanșării asistentului"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Afișează pictograma în bara de stare când microfonul este folosit pentru a activa asistentul vocal"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze fotografiile și conținutul media de pe dispozitiv?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Permiți accesul &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; la fotografiile și conținutul media de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să-ți acceseze agenda?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze agenda de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze locația acestui dispozitiv?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Permiți accesul &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; la locația de pe &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplicația va avea acces la locație doar când o folosești"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze locația acestui dispozitiv?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze locația de pe &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"E posibil ca aplicația să dorească să-ți acceseze în permanență locația, chiar și când nu o folosești. "<annotation id="link">"Acordă această permisiune din setări."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Modifici accesul la locație pentru &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Modifici accesul la locație pentru &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Aplicația dorește să-ți acceseze în permanență locația, chiar și când nu o folosești. "<annotation id="link">"Acordă această permisiune din setări."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să găsească, să se conecteze la și să afle poziția relativă a dispozitivelor apropiate?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; poate să găsească, să se conecteze la, să determine poziția relativă a dispozitivelor apropiate pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să găsească, să se conecteze la și să determine poziția relativă a dispozitivelor apropiate? "<annotation id="link">"Permite în setări."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Schimbi permisiunile privind accesul la locație pentru <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> de la locația aproximativă la cea exactă?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Schimbi accesul la locația de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; pentru <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> de la aproximativă la exactă?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze locația aproximativă a acestui dispozitiv?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze locația aproximativă de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exactă"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Aproximativă"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze calendarul?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze calendarul de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să trimită și să vadă mesaje SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să trimită și să vadă mesajele SMS de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze fotografiile, conținutul media și fișierele de pe dispozitiv?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Permiți accesul &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; la fotografiile, conținutul media și fișierele de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Permiți accesul &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; la &lt;b&gt;fotografii, clipuri, conținut audio și muzică&lt;/b&gt; de pe dispozitiv?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Permiți accesul &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; la &lt;b&gt;fotografii, clipuri, conținut audio, muzică și alte fișiere&lt;/b&gt; de pe dispozitiv?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Permiți accesul &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; la muzică și fișiere audio de pe acest dispozitiv?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Permiți accesul &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; la muzică și conținut audio de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze fotografiile și videoclipurile de pe dispozitiv?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze fotografii și videoclipuri de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze mai multe fotografii și videoclipuri de pe dispozitiv?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze mai multe fotografii și videoclipuri de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să înregistreze audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să înregistreze conținut audio pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplicația va putea să înregistreze conținut audio doar când o folosești"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să înregistreze audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să înregistreze conținut audio pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Aplicația poate dori să înregistreze conținut audio permanent, chiar și când nu o folosești. "<annotation id="link">"Acordă această permisiune din setări."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Modifici accesul la microfon pentru &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Modifici accesul la microfon pentru &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Aplicația dorește să înregistreze conținut audio permanent, chiar și când nu o folosești. "<annotation id="link">"Acordă această permisiune din setări."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Permiți aplicației &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să-ți acceseze activitatea fizică?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze activitatea fizică de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să fotografieze și să înregistreze video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să facă fotografii și să înregistreze videoclipuri pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplicația va putea să fotografieze și să înregistreze videoclipuri doar când o folosești"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să facă fotografii și să înregistreze videoclipuri?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să facă fotografii și să înregistreze videoclipuri pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Aplicația poate dori să fotografieze și să înregistreze videoclipuri permanent, chiar când nu o folosești. "<annotation id="link">"Acordă această permisiune din setări."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Modifici accesul la camera foto pentru &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Modifici accesul la camera foto pentru &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Aplicația dorește să fotografieze și să înregistreze videoclipuri permanent, chiar și când nu o folosești. "<annotation id="link">"Acordă această permisiune din setări."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să-ți acceseze jurnalele de apeluri?"</string>
- <string name="permgrouprequest_phone" msgid="1829234136997316752">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să facă și să gestioneze apeluri telefonice?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze jurnalele de apeluri de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_phone" msgid="1829234136997316752">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să dea și să gestioneze apeluri telefonice?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să inițieze și să gestioneze apeluri telefonice pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze datele de la senzori despre semnele vitale?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze datele de la senzori despre semnele vitale de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Aplicația solicită acces permanent la datele de la senzori despre semnele vitale, chiar și când nu o folosești. Pentru a face această modificare, "<annotation id="link">"accesează setările"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze datele de la senzori despre semnele vitale?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze datele de la senzori despre semnele vitale de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Pentru a permite accesul permanent al aplicației la datele de la senzorii corporali, chiar și atunci când nu o folosești, "<annotation id="link">"accesează setările"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Permiți în continuare accesul &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; la datele de la senzorii corporali în timpul folosirii aplicației?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; poate accesa în continuare date de la senzorii corporali de pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; în timpul folosirii aplicației?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să-ți trimită notificări?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Permiți ca &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să trimită notificări pe &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Permisiuni controlate"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> are acces la locație"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Organizația ta permite ca <xliff:g id="APP_NAME">%1$s</xliff:g> să-ți acceseze locația"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Alte permisiuni"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permisiuni folosite de sistem"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permisiuni folosite numai de aplicațiile sistemului."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Aplicația afirmă că poate trimite terților date privind locațiile"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Locația și permiterea accesului la date"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"De unde provin informațiile despre permiterea accesului la date"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Dezvoltatorul a trimis producătorului acestui dispozitiv informații despre modul în care această aplicație permite accesul la date. Dezvoltatorul poate actualiza informațiile în timp."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Dezvoltatorul a trimis la "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" informații despre modul în care această aplicație permite accesul la date. Dezvoltatorul poate actualiza informațiile în timp."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Aplicația poate permite accesul la date pentru:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Permiterea accesului la date variază"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Siguranța datelor"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Se poate permite accesul la datele privind locațiile tale"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Aplicația afirmă că le poate trimite terților date privind locațiile tale"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Linkul nu poate fi deschis"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Actualizări privind permiterea accesului la date pentru locație"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Examinează aplicațiile care au schimbat modul în care pot permite accesul la datele tale privind locațiile"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Aceste aplicații au schimbat modul în care pot permite accesul la datele tale privind locațiile. Este posibil să nu fi permis accesul la ele anterior sau să-l permită acum în scopuri de publicitate sau de marketing."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Actualizări privind permiterea accesului la date"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Unele aplicații au schimbat modul în care pot permite accesul la datele tale privind locațiile"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Setări"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Data accesării: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Data accesării: ieri, <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Data accesării: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-ru-v33/strings.xml b/PermissionController/res/values-ru-v33/strings.xml
index 9f74baf9a..a13e4e8d5 100644
--- a/PermissionController/res/values-ru-v33/strings.xml
+++ b/PermissionController/res/values-ru-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Другие оповещения"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Закрытые оповещения"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Разверните, чтобы увидеть ещё одно оповещение}one{Разверните, чтобы увидеть ещё # оповещение}few{Разверните, чтобы увидеть ещё # оповещения}many{Разверните, чтобы увидеть ещё # оповещений}other{Разверните, чтобы увидеть ещё # оповещения}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Оповещение. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Действие выполнено"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Изучите настройки, позволяющие усилить защиту устройства"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Быстрые настройки безопасности и конфиденциальности"</string>
diff --git a/PermissionController/res/values-ru-v34/strings.xml b/PermissionController/res/values-ru-v34/strings.xml
index 931ebb6d5..64a927b69 100644
--- a/PermissionController/res/values-ru-v34/strings.xml
+++ b/PermissionController/res/values-ru-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Защита и конфиденциальность"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Настройки"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Здоровье и спорт"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Настроить доступ приложения к данным о здоровье"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Настроить доступ приложений к данным о здоровье"</string>
<string name="location_settings" msgid="8863940440881290182">"Доступ к геоданным"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"Для приложений и сервисов. Даже если эта функция отключена, данные микрофона могут передаваться при звонке на номер экстренной службы."</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Для приложений и сервисов"</string>
diff --git a/PermissionController/res/values-ru/strings.xml b/PermissionController/res/values-ru/strings.xml
index c276dd5cf..1abcc1826 100644
--- a/PermissionController/res/values-ru/strings.xml
+++ b/PermissionController/res/values-ru/strings.xml
@@ -32,11 +32,12 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Оставить доступ только в активном режиме"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Оставить \"Только в этот раз\""</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Подробнее"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Разрешить все"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Разрешить ко всем"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Постоянный полный доступ"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Разрешить ограниченный доступ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Выбрать фотографии и видео"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Выбрать больше"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Больше не выбирать"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Не выбирать"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Все равно запретить"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Закрыть"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> из <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Приложения"</string>
<string name="app_permissions" msgid="3369917736607944781">"Разрешения приложений"</string>
<string name="unused_apps" msgid="2058057455175955094">"Неиспользуемые приложения"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Изменить список фото для этого приложения"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Неиспользуемых приложений нет"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Нет неиспользуемых приложений"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Действия с разрешениями"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Разрешить в любом режиме"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Только во время использования"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Разрешить только во время использования приложения"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Запретить"</string>
<string name="loading" msgid="4789365003890741082">"Загрузка…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Все разрешения"</string>
<string name="other_permissions" msgid="2901186127193849594">"Что ещё может приложение"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Запрос разрешений"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Wear OS"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Установка и удаление не поддерживаются в Wear OS."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Выберите разрешения для приложения &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Приложение &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; обновлено. Выберите разрешения для него."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Отмена"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Отзывать разрешения, если приложение не используется"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Удалять разрешения и освобождать место"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Приостановить работу в неактивный период"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Приостановить работу в неактивный период"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Удалить разрешения и временные файлы, прекратить отправку уведомлений"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Удалить разрешения и временные файлы, прекратить отправку уведомлений и перенести приложение в архив"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Для защиты ваших данных мы отзовем разрешения, предоставленные этому приложению, если вы не будете пользоваться им несколько месяцев."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Если вы не будете пользоваться приложением несколько месяцев, в целях защиты ваших данных мы отзовем следующие разрешения: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"В целях защиты ваших данных мы отозвали разрешения для приложений, которыми вы не пользовались несколько месяцев."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Использовалось <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Если вы разрешите приложению управлять всеми файлами, оно сможет просматривать, изменять и удалять любые файлы в общем хранилище на этом устройстве, а также на подключенных запоминающих устройствах. При этом оно сможет получать доступ к файлам без вашего ведома."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Разрешить этому приложению просматривать, изменять и удалять любые файлы на этом устройстве, а также на подключенных запоминающих устройствах? Приложение сможет получать доступ к файлам без вашего ведома."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Приложения с разрешением <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Приложения с этим разрешением <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Приложения с этим разрешением могут получать доступ к данным о вашей физической активности, включая количество пройденных шагов и продолжительность прогулок и поездок на велосипеде."</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Приложения с этим разрешением могут получать доступ к календарю."</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Приложения с этим разрешением могут читать список вызовов и создавать записи в нем."</string>
@@ -263,7 +265,7 @@
<string name="auto_revoke_permission_reminder_notification_content" msgid="4492228990462107487">"Разрешения отозваны для защиты конфиденциальности ваших данных. Нажмите, чтобы узнать больше."</string>
<string name="auto_revoke_permission_notification_title" msgid="2629844160853454657">"У неиспользуемых приложений отозваны разрешения"</string>
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Вы уже несколько месяцев не используете некоторые приложения. Нажмите, чтобы посмотреть подробности."</string>
- <string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# неиспользуемое приложение}one{# неиспользуемое приложение}few{# неиспользуемого приложения}many{# неиспользуемых приложений}other{# неиспользуемого приложения}}"</string>
+ <string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# неиспользуемое приложение}one{# неиспользуемое приложение}few{# неиспользуемых приложения}many{# неиспользуемых приложений}other{# неиспользуемого приложения}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Мы отозвали разрешения, удалили временные файлы и отключили уведомления. Нажмите, чтобы узнать подробности."</string>
<string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Проверьте приложения с отозванными разрешениями"</string>
<string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Мы отозвали разрешения, удалили временные файлы и отключили уведомления для приложений, которые вы давно не использовали."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Приложение для заметок"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Приложения для написания заметок на вашем устройстве"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"заметки"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Используется по умолчанию"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Больше не спрашивать"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"По умолчанию"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Показывать значок активации голосового помощника"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Показывать значок в строке состояния, когда для активации голосового помощника используется микрофон"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к фото и мультимедиа на устройстве?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к фото и мультимедиа на устройстве &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к контактам на устройстве &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"Разрешить приложению &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Разрешить приложению &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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Этому приложению может потребоваться доступ к вашему местоположению, даже когда вы им не пользуетесь. Предоставьте разрешение в "<annotation id="link">"настройках"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Изменить настройки доступа к данным о местоположении для приложения &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Изменить для приложения &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным о местоположении на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Этому приложению требуется доступ к вашему местоположению, даже когда вы им не пользуетесь. Предоставьте разрешение в "<annotation id="link">"настройках"</annotation>"."</string>
- <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Разрешить приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" находить устройства поблизости, подключаться к ним и определять их относительное положение?"</string>
- <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Разрешить приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" находить устройства поблизости, подключаться к ним и определять их относительное позиционирование? "<annotation id="link">"Открыть настройки"</annotation></string>
+ <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; находить устройства поблизости, подключаться к ним и определять их относительное положение?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; находить устройства поблизости, подключаться к ним и определять их относительное местоположение на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; находить устройства поблизости, подключаться к ним и определять их относительное положение? "<annotation id="link">"Открыть настройки"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Изменить местоположение в приложении \"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>\" с приблизительного на точное?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Разрешить приложению \"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>\" доступ к данным о точном местоположении устройства &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным о приблизительном положении устройства &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к календарю на устройстве &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; отправлять и просматривать SMS на устройстве &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к фото, мультимедиа и файлам на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к &lt;b&gt;фото, видео, музыке и аудио&lt;/b&gt; на устройстве?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к &lt;b&gt;фото, видео, аудио и другим файлам&lt;/b&gt; на устройстве?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к музыке и аудио на устройстве?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к музыке и аудио на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к фото и видео на устройстве?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к фотографиям и видео на этом устройстве?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к фото и видео на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к другим фото и видео на этом устройстве?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к другим фото и видео на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записывать аудио?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записывать аудио на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Приложение будет записывать аудио, только когда вы им пользуетесь."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записывать аудио?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записывать аудио на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Это приложение может записывать аудио в любое время, даже когда вы им не пользуетесь. "<annotation id="link">"Предоставьте разрешение в настройках."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Изменить настройки доступа к микрофону для приложения &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Изменить для приложения &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; настройки доступа к микрофону на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Это приложение записывает аудио в любое время, даже когда вы им не пользуетесь. "<annotation id="link">"Предоставьте разрешение в настройках."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным о физической активности?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным о физической активности на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снимать фото и видео?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снимать фото и видео на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Приложение будет делать фотографии и снимать видео, только когда вы им пользуетесь."</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снимать фото и видео?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снимать фото и видео на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Это приложение может делать фотографии и снимать видео в любое время, даже когда вы им не пользуетесь. "<annotation id="link">"Предоставьте разрешение в настройках."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Изменить настройки доступа к камере для приложения &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Изменить для приложения &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; настройки доступа к камере на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Это приложение делает фотографии и снимает видео в любое время, даже когда вы им не пользуетесь. "<annotation id="link">"Предоставьте разрешение в настройках."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к списку вызовов?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к списку вызовов на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; совершать звонки и управлять ими?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; совершать звонки и управлять ими на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным датчиков о состоянии организма?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным нательных датчиков на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Этому приложению требуется доступ к данным нательных датчиков, даже когда вы им не пользуетесь. Предоставить разрешение можно в "<annotation id="link">"настройках"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Разрешить приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" доступ к данным датчиков на теле?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным нательных датчиков на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Чтобы предоставить приложению доступ к данным нательных датчиков, даже когда вы им не пользуетесь, "<annotation id="link">"измените настройки"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Предоставлять приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным нательных датчиков, только когда оно используется?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Разрешить прил. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным нат. датчиков на устр. &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; только при использ.?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Разрешить <xliff:g id="APP_NAME">%1$s</xliff:g> отправлять уведомления?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; отправлять уведомления на устройстве &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Контролируемые разрешения"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"У приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" есть доступ к геоданным"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"В вашей организации приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" разрешен доступ к геоданным."</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Другие разрешения"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Разрешения, используемые системой"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Разрешения, используемые только системными приложениями"</string>
@@ -577,7 +614,7 @@
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Проверьте приложение с доступом к геоданным в фоновом режиме"</string>
<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="safety_center_view_recent_location_access" msgid="3524391299490678243">"Показать недавнее использование геоданных"</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>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Это приложение может передавать третьим лицам данные о местоположении."</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Передача данных и местоположение"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Источник сведений о передаче данных"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Разработчик предоставил производителю устройства информацию о том, как приложение передает данные. Со временем он может ее обновить."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Разработчик предоставил "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" информацию о том, как приложение передает данные. Со временем она может обновляться."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Цели передачи данных о местоположении:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Варианты передачи данных"</string>
@@ -608,9 +646,7 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Безопасность данных"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Возможна передача геоданных"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Это приложение уведомило, что оно может передавать данные о вашем местоположении третьим лицам."</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Не удалось открыть ссылку"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
- <string name="data_sharing_updates_title" msgid="7996933386875213859">"Обновление сведений о передаче данных о местоположении"</string>
+ <string name="data_sharing_updates_title" msgid="7996933386875213859">"Обновления в передаче данных о местоположении"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Проверить приложения, которые изменили подход к передаче данных о вашем местоположении"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Эти приложения изменили подход к передаче данных о вашем местоположении. Возможно, такие сведения ранее не передавались или теперь передаются в рекламных или маркетинговых целях."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Разработчики этих приложений предоставили магазину информацию о своем подходе к передаче данных. Эти сведения могут обновляться.\n\nПодход к передаче данных может зависеть от версии приложения, способа его использования, а также от вашего региона и возраста."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Обновление сведений о передаче данных"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Некоторые приложения изменили подход к передаче данных о вашем местоположении."</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Настройки"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Последний доступ: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Последний доступ вчера: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Последний доступ: <xliff:g id="TIME_DATE_0">%1$s</xliff:g>, <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-si-v33/strings.xml b/PermissionController/res/values-si-v33/strings.xml
index e7eb6d8fb..b3d1ab958 100644
--- a/PermissionController/res/values-si-v33/strings.xml
+++ b/PermissionController/res/values-si-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"තවත් ඇඟවීම්"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"අස් කළ ඇඟවීම්"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{පුළුල් කර තවත් එක් ඇඟවීමක් බලන්න}one{පුළුල් කර තවත් ඇඟවීම් #ක් බලන්න}other{පුළුල් කර තවත් ඇඟවීම් #ක් බලන්න}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"ඇඟවීම. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"ක්‍රියාමාර්ගය සම්පූර්ණයි"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"ඔබේ උපාංගයට ආරක්ෂණය එක් කළ හැකි සැකසීම් පරීක්ෂා කරන්න"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"ආරක්ෂාව සහ පෞද්ගලිකත්වය ඉක්මන් සැකසීම්"</string>
diff --git a/PermissionController/res/values-si/strings.xml b/PermissionController/res/values-si/strings.xml
index 04b2545ba..4dc920fdc 100644
--- a/PermissionController/res/values-si/strings.xml
+++ b/PermissionController/res/values-si/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"තවත් තතු"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"සියල්ලට ඉඩ දෙන්න"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"සැම විටම සියල්ලට ඉඩ දෙන්න"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"සීමිත ප්‍රවේශයට ඉඩ දෙන්න"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ඡායාරූප සහ වීඩියෝ තෝරන්න"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"තවත් තෝරන්න"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"තවත් තෝරා නොගන්න"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"යෙදුම්"</string>
<string name="app_permissions" msgid="3369917736607944781">"යෙදුම් අවසර"</string>
<string name="unused_apps" msgid="2058057455175955094">"භාවිත නොකළ යෙදුම්"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"මෙම යෙදුම සඳහා තෝරන ලද ඡායාරූප සංස්කරණය කරන්න"</string>
<string name="no_unused_apps" msgid="12809387670415295">"භාවිත නොකළ යෙදුම් නැත"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"භාවිත නොකළ යෙදුම් 0"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"මෑත අවසර තීරණ"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"සියලු අවසර"</string>
<string name="other_permissions" msgid="2901186127193849594">"වෙනත් යෙදුම් හැකියාවන්"</string>
<string name="permission_request_title" msgid="8790310151025020126">"අවසර ඉල්ලීම"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear මත ස්ථාපන/අස්ථාපනය ක්‍රියා සහාය දක්වන්නේ නැත."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට පිවිසීමට ඉඩ දෙන දේ තෝරන්න"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; යාවත්කාලීන කර ඇත. මෙම යෙදුමට පිවිසීමට ඉඩ දෙන දේ තෝරන්න."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"අවලංගු කරන්න"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"යෙදුම භාවිත කර නැති නම් අවසර ඉවත් කරන්න"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"අවසර ඉවත් කරන්න සහ ඉඩ හිස් කරන්න"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"භාවිත නොකළේ නම් යෙදුම් ක්‍රියාකාරකම් විරාම කරන්න"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"යෙදුම භාවිතා නොකළේ නම් කළමනාකරණය කරන්න"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"අවසර ඉවත් කරන්න, තාවකාලික ගොනු මකන්න සහ දැනුම්දීම් නවත්වන්න"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"අවසර ඉවත් කරන්න, තාවකාලික ගොනු මකා දමන්න, දැනුම්දීම් නවත්වන්න, සහ යෙදුම ලේඛනාරක්ෂණය කරන්න"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"ඔබගේ දත්ත ආරක්ෂා කිරීම සඳහා, යෙදුම මාස කිහිපයක් භාවිතා නොකරන්නේ නම් මෙම යෙදුම සඳහා අවසර ඉවත් කරනු ලැබේ."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"ඔබගේ දත්ත ආරක්ෂා කිරීම සඳහා, යෙදුම මාස කිහිපයක් භාවිතා නොකරන්නේ නම් පහත අවසර ඉවත් කරනු ලැබේ: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"ඔබේ දත්ත ආරක්ෂා කිරීමට, ඔබ මාස කීපයක් තුළ භාවිත කර නැති යෙදුම්වලින් අවසර ඉවත් කර ඇත"</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"අවසාන විවෘත කළේ <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"ඔබ සියලු ගොනු කළමනාකරණය කිරීමට ඉඩ දෙන්නේ නම්, මෙම යෙදුමට මෙම උපාංගයේ හෝ සම්බන්ධිත ගබඩා උපාංගවල පොදු ගබඩාවේ ඇති ඕනෑම ගොනුවක් වෙත ප්‍රවේශ වීමට, වෙනස් කිරීමට සහ මැකීටම හැකිය. යෙදුම ඔබෙන් විමසීමෙන් තොරව ගොනු වෙත ප්‍රවේශ විය හැකිය."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"මෙම යෙදුමට උපාංගයේ හෝ ඕනෑම සම්බන්ධිත ගබඩා උපාංගයක ඇති ගොනු වෙත ප්‍රවේශ වීමට, වෙනස් කිරීමට සහ මැකීමට ඉඩ දෙන්නද? මෙම යෙදුම ඔබෙන් විමසීමෙන් තොරව ගොනු වෙත ප්‍රවේශ විය හැකිය."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"මෙම අවසරය සහිත යෙදුම්වලට <xliff:g id="DESCRIPTION">%1$s</xliff:g> කළ හැක"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"මෙම අවසරය ඇති යෙදුම් වලට මෙය කළ හැක: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"මෙම අවසරය සහිත යෙදුම්වලට ඇවිදීම, බයිසිකල් පැදීම, රිය පැදවීම, පියවර ගණනය සහ තවත් දෑ වැනි, ඔබේ ශාරීරික ක්‍රියාකාරකම්වලට ප්‍රවේශ විය හැක"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"මෙම අවසරය සහිත යෙදුම්වලට ඔබේ දින දර්ශනය වෙත ප්‍රවේශ විය හැක"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"මෙම අවසරය සහිත යෙදුම්වලට දුරකථන ඇමතුම් ලොගය කියවීමටත් ලිවීමටත් හැකි ය"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"සටහන් යෙදුම"</string>
<string name="role_notes_description" msgid="8496852798616883551">"ඔබේ උපාංගයෙහි සටහන් ගැනීමට ඔබට ඉඩ දෙන යෙදුම්"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"සටහන්"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"වත්මන් පෙරනිමිය"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"නැවත නොඅසන්න"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"පෙරනිමි ලෙස සකසන්න"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"සහායක ප්‍රේරකය අනාවරණය පෙන්වන්න"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"හඬ සහායක සක්‍රිය කිරීමට මයික්‍රෆෝනය භාවිතා කරන විට තත්ත්ව තීරුවේ නිරූපකය පෙන්වන්න"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; වෙත ඔබගේ උපාංගය තුළ ඇති ඡායාරූප, මාධ්‍ය, සහ ගොනු වෙත ප්‍රවේශ වීමට ඉඩ දෙන්නේද?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&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>ගේ ස්ථානයට ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"මෙයට ඔබ යෙදුම භාවිත නොකරමින් සිටින විට පවා සියලු අවස්ථාවල ඔබේ ස්ථානය වෙත ප්‍රවේශ වීමට අවශ්‍ය විය හැකිය. "<annotation id="link">"සැකසීම්වල ඉඩ දෙන්න."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; සඳහා ස්ථාන ප්‍රවේශය වෙනස් කරන්නද?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"මෙම යෙදුමට ඔබ යෙදුම භාවිත නොකරමින් සිටින විට පවා සියලු අවස්ථාවල ඔබේ ස්ථානය වෙත ප්‍රවේශ වීමට අවශ්‍යයි. "<annotation id="link">"සැකසීම්වල ඉඩ දෙන්න."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට අවට උපාංග සොයා ගැනීමට, සම්බන්ධ වීමට සහ ඒවායේ සාපේක්ෂ ස්ථානය සොයා ගැනීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත අවට උපාංගවල සාපේක්ෂ පිහිටීම සොයා ගැනීමට, සම්බන්ධ කිරීමට, සහ තීරණය කිරීමට ඉඩ දෙන්න ද?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට අවට උපාංග සොයා ගැනීමට, සම්බන්ධ වීමට සහ ඒවායේ සාපේක්ෂ ස්ථානය සොයා ගැනීමට ඉඩ දෙන්නද? "<annotation id="link">"සැකසීම් තුළ ඉඩ දෙන්න."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> හි ස්ථානය ආසන්න සිට නිවැරදි දක්වා වෙනස් කරන්නද?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>ගේ ස්ථාන ප්‍රවේශය ආසන්නයේ සිට නිරවද්‍ය ලෙස වෙනස් කරන්න ද?"</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="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත SMS පණිවිඩ යැවීමට සහ බැලීමට ඉඩ දෙන්න ද?"</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="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත ඡායාරූප, මාධ්‍ය, සහ ගොනු වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට මෙම උපාංගයේ &lt;b&gt;ඡායාරූප, වීඩියෝ, සංගීතය සහ ශ්‍රව්‍ය&lt;b&gt; වෙත ප්‍රවේශ වීමට ඉඩ දෙන්නද?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට මෙම උපාංගයේ &lt;b&gt;ඡායාරූප, වීඩියෝ, සංගීතය, ශ්‍රව්‍ය සහ වෙනත් ගොනු&lt;b&gt; වෙත ප්‍රවේශ වීමට ඉඩ දෙන්නද?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට මෙම උපාංගයේ සංගීතය සහ ශ්‍රව්‍ය වෙත ප්‍රවේශ වීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත සංගීතය සහ ශ්‍රව්‍ය වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට මෙම උපාංගයේ ඇති ඡායාරූප සහ වීඩියෝ වෙත ප්‍රවේශ වීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත ඡායාරූප සහ වීඩියෝ වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට මෙම උපාංගයෙහි ඇති තවත් ඡායාරූප සහ වීඩියෝ වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත තවත් ඡායාරූප සහ වීඩියෝ වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; වෙත ශබ්දය පටි ගත කිරීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත ශ්‍රව්‍ය පටිගත කිරීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"යෙදුමට ඔබ යෙදුම භාවිත කරන අතරතුර ඕඩියෝ පටිගත කිරීමට පමණක් හැකි වනු ඇත"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඕඩියෝ පටිගත කිරීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත ශ්‍රව්‍ය පටිගත කිරීමට ඉඩ දෙන්න ද?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"මෙම යෙදුමට ඔබ යෙදුම භාවිත කරමින් නොසිටින විට පවා මුළු කාලය පුරාම ඕඩියෝ පටිගත කිරීමට අවශ්‍ය විය හැකිය. "<annotation id="link">"සැකසීම්වල ඉඩ දෙන්න."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; සඳහා මයික්‍රෆෝන ප්‍රවේශය වෙනස් කරන්නද?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"මෙම යෙදුමට ඔබ යෙදුම භාවිත කරමින් නොසිටින විට පවා මුළු කාලය පුරාම ඕඩියෝ පටිගත කිරීමට අවශ්‍යයි. "<annotation id="link">"සැකසීම්වල ඉඩ දෙන්න."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ ශාරීරික ක්‍රියාකාරකමට ප්‍රවේශ වීමට ඉඩ දෙන්නේද?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත ඔබේ ශාරීරික ක්‍රියාකාරකම් වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; වෙත පින්තූර සහ වීඩියෝ ගැනීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"යෙදුමට ඔබ යෙදුම භාවිත කරන අතරතුර පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට පමණක් හැකි වනු ඇත"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට ඉඩ දෙන්න ද?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"මෙම යෙදුමට ඔබ යෙදුම භාවිත කරමින් නොසිටින විට පවා මුළු කාලය පුරාම පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට අවශ්‍ය විය හැකිය. "<annotation id="link">"සැකසීම්වල ඉඩ දෙන්න."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; සඳහා කැමරා ප්‍රවේශය වෙනස් කරන්නද?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"මෙම යෙදුමට ඔබ යෙදුම භාවිත කරමින් නොසිටින විට පවා මුළු කාලය පුරාම පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට අවශ්‍යයි. "<annotation id="link">"සැකසීම්වල ඉඩ දෙන්න."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; ඔබේ ඇමතුම් ලොග වෙත පිවිසීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත ඔබේ දුරකථන ඇමතුම් ලොග වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; වෙත දුරකථන ඇමතුම් ලබා ගැනීමට සහ කළමනාකරණය කිරීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත දුරකථන ඇමතුම් ලබා ගැනීමට සහ කළමනාකරණය කිරීමට ඉඩ දෙන්න ද?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; වෙත ඔබගේ ජෛව ලක්ෂණ පිළිබඳ සංවේදක දත්ත වෙත ප්‍රවේශ වීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත ඔබේ ජීව සලකුණු පිළිබඳ සංවේදක දත්ත වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"මෙම යෙදුමට ඔබ යෙදුම භාවිත නොකරමින් සිටින විට පවා, සියලු අවස්ථාවල ඔබගේ ජෛව ලක්ෂණ පිළිබඳ සංවේදක දත්තවලට ප්‍රවේශය අවශ්‍යයි. මෙම වෙනස් කිරීම සිදු කිරීමට, "<annotation id="link">"සැකසීම් වෙත යන්න."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට ඔබගේ ජෛව ලක්ෂණ පිළිබඳ සංවේදක දත්ත වෙත ප්‍රවේශ වීමට ඉඩ දෙන්නද?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත ඔබේ ජීව සලකුණු පිළිබඳ සංවේදක දත්ත වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"ඔබ යෙදුම භාවිත නොකරන විට පවා, මෙම යෙදුමට ශරීර සංවේදක දත්තවලට ප්‍රවේශ වීමට ඉඩ දීමට, "<annotation id="link">"සැකසීම් වෙත යන්න."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"යෙදුම භාවිතයේ ඇති අතරතුර ශරීර සංවේදක දත්ත වෙත ප්‍රවේශ වීමට &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට ඉඩ දෙන්නද?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"යෙදුම භාවිතයේ පවතින අතරේ ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%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_notifications" msgid="6396739062335106181">"ඔබට දැනුම්දීම් එවීමට &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt; හට ඉඩ දෙන්නද?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; හට ඔබේ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; මත දැනුම්දීම් යැවීමට ඉඩ දෙන්න ද?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"පාලිත අවසර"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> හට ස්ථාන ප්‍රවේශය ඇත"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"ඔබේ සංවිධානය <xliff:g id="APP_NAME">%1$s</xliff:g> හට ඔබේ ස්ථානයට ප්‍රවේශ වීමට ඉඩ දෙයි"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"වෙනත් අවසර"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"පද්ධතිය මගින් භාවිත කරන අවසරය"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"පද්ධති යෙදුම් මගින් පමණක් භාවිත කරන අවසර."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"මෙම යෙදුම තෙවන පාර්ශ්වයන් සමග ස්ථාන දත්ත බෙදා ගත හැකි බව ප්‍රකාශ කර ඇත"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"දත්ත බෙදා ගැනීම සහ ස්ථානය"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"දත්ත බෙදා ගැනීමේ තතු පැමිණෙන තැන"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"සංවර්ධකයා මෙම යෙදුම දත්ත බෙදා ගන්නා ආකාරය පිළිබඳ තතු මෙම උපාංගයේ නිෂ්පාදකයාට ලබා දුන්නේ ය. සංවර්ධකයා මෙම තතු කාලයත් සමග යාවත්කාලීන කිරීමට ඉඩ ඇත."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"මෙම යෙදුම දත්ත බෙදා ගන්නා ආකාරය පිළිබඳව සංවර්ධකයා "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" වෙත තතු සපයා ඇත. සංවර්ධකයා මෙම තතු කාලයත් සමග යාවත්කාලීන කළ හැක."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"මෙම යෙදුම මේ සඳහා ස්ථාන දත්ත බෙදා ගත හැක:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"දත්ත බෙදා ගැනීම වෙනස් වේ"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"දත්ත ආරක්ෂාව"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"ස්ථාන දත්ත බෙදා ගත හැක"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"මෙම යෙදුම තෙවන පාර්ශ්වයන් සමග ඔබේ ස්ථාන දත්ත බෙදා ගත හැකි බව ප්‍රකාශ කර ඇත"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"මෙම සබැඳිය විවෘත කළ නොහැක"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"ස්ථානය සඳහා දත්ත බෙදා ගැනීමේ යාවත්කාලීන"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ඒවා ඔබේ ස්ථාන දත්ත බෙදා ගත හැකි ආකාරය වෙනස් කළ යෙදුම් සමාලෝචනය කරන්න"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"මෙම යෙදුම් ඔබේ ස්ථාන දත්ත බෙදා ගත හැකි ආකාරය වෙනස් කර ඇත. ඒවා එය කලින් බෙදා ගෙන නොතිබිය හැක, නැතහොත් දැන් එය වෙළඳ ප්‍රචාරණ හෝ අලෙවිකරණ අරමුණු සඳහා බෙදා ගත හැක."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"දත්ත බෙදා ගැනීමේ යාවත්කාලීන"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"සමහර යෙදුම් ඒවා ඔබේ ස්ථාන දත්ත බෙදා ගත හැකි ආකාරය වෙනස් කර ඇත"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"සැකසීම්"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"ප්‍රවේශ වූයේ <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"ප්‍රවේශ වූයේ ඊයේ <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"ප්‍රවේශ වූයේ <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-sk/strings.xml b/PermissionController/res/values-sk/strings.xml
index 014feced7..7684cb672 100644
--- a/PermissionController/res/values-sk/strings.xml
+++ b/PermissionController/res/values-sk/strings.xml
@@ -34,13 +34,14 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Ďalšie info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Povoliť všetko"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Vždy povoliť všetko"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Povoliť obmedzený prístup"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Vybrať fotky a videá"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Vybrať ďalšie"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Nevybrať ďalšie"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Aj tak nepovoliť"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Zavrieť"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> z <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; vykonať akciu <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="permission_add_background_warning_template" msgid="1812914855915092273">"Vždy povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Iba počas používania aplikácie"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Vždy"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikácie"</string>
<string name="app_permissions" msgid="3369917736607944781">"Povolenia aplikácií"</string>
<string name="unused_apps" msgid="2058057455175955094">"Nepoužívané aplikácie"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Upraviť vybrané fotky pre túto aplikáciu"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Žiadne nepoužívané aplikácie"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Žiadne nepoužívané aplikácie"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nedávne rozhodnutia o povolení"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Všetky povolenia"</string>
<string name="other_permissions" msgid="2901186127193849594">"Ďalšie možnosti aplikácie"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Žiadosť o povolenie"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear nepodporuje akciu inštalácie/odinštalovania."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Vyberte, k čomu môže pristupovať aplikácia &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Aplikácia &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; bola aktualizovaná. Vyberte, k čomu bude mať prístup."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Zrušiť"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Odstrániť povolenia, ak sa aplikácia nepoužíva"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Odstraňovať povol. a uvoľňovať priestor"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pozastaviť aktivitu v nepoužívaných apl."</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Spravovať aplikáciu, ak sa nepoužíva"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Odstrániť povolenia, vymazať dočasné súbory a zastaviť upozornenia"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Odstráňte povolenia, vymažte dočasné súbory, zastavte upozornenia a archivujte aplikáciu"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Ak túto aplikáciu niekoľko mesiacov nepoužijete, v záujme ochrany vašich údajov budú odstránené jej povolenia."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Ak túto aplikáciu niekoľko mesiacov nepoužijete, v záujme ochrany vašich údajov budú odstránené tieto povolenia: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"V záujme ochrany vašich údajov boli odobrané povolenia aplikáciám, ktoré ste niekoľko mesiacov nepoužívali."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikácia na poznámky"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplikácie, ktoré vám v zariadení umožňujú písať poznámky"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"poznámky"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Aktuálne predvolená"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Nabudúce sa nepýtať"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Nastav. ako predvol."</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Zobrazovať detekciu spustenia asistenta"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Zobrazovať v stavovom riadku ikonu, keď bude pomocou mikrofónu aktivovaný hlasový asistent"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k fotkám a médiám v zariadení?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k fotkám a médiám v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup ku kontaktom?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup ku kontaktom v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k polohe tohto zariadenia?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k polohe zariadenia &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikácia bude mať prístup k polohe iba vtedy, keď ju budete používať"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k polohe tohto zariadenia?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k polohe zariadenia &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Táto aplikácia môže požadovať nepretržitý prístup k vašej polohe, aj keď ju nepoužívate. "<annotation id="link">"Povolíte ho v nastaveniach."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Chcete zmeniť prístup k polohe pre aplikáciu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Chcete zmeniť prístup k polohe pre &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Táto aplikácia požaduje nepretržitý prístup k vašej polohe, aj keď ju nepoužívate. "<annotation id="link">"Povolíte ho v nastaveniach."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Chcete aplikácii <xliff:g id="APP_NAME">%1$s</xliff:g> povoliť vyhľadávať zariadenia v okolí, pripájať sa k nim a určovať ich relatívnu polohu?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; vyhľadávať zariadenia v okolí, určovať ich relatívnu polohu a pripájať sa k nim v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Chcete aplikácii <xliff:g id="APP_NAME">%1$s</xliff:g> povoliť vyhľadávať zariadenia v okolí, pripájať sa k nim a určovať ich vzájomnú polohu? "<annotation id="link">"Urobte to v nastaveniach."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Chcete zmeniť prístup k polohe aplikácie <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> z približnej polohy na presnú?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Chcete zmeniť prístup k polohe pre aplikáciu <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; z približnej na presnú?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k približnej polohe tohto zariadenia?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k približnej polohe zariadenia &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Presná"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Približná"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup ku kalendáru?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup ku kalendáru v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; odosielať a zobrazovať správy SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť odosielať a zobrazovať správy SMS v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k fotkám, médiám a súborom v zariadení?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k fotkám, médiám a súborom v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k &lt;b&gt;fotkám, videám, hudbe a zvuku&lt;/b&gt; v tomto zariadení?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k &lt;b&gt;fotkám, videám, hudbe, zvuku a ďalším súborom&lt;/b&gt; v tomto zariadení?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k hudbe a zvuku v tomto zariadení?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k hudbe a zvuku v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k fotkám a videám v tomto zariadení?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k fotkám a videám v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k ďalším fotkám a videám v tomto zariadení?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k ďalším fotkám a videám v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nahrávať zvuk?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť nahrávať zvuk v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Táto aplikácia bude môcť nahrávať zvuk iba vtedy, keď ju budete používať"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; nahrávať zvuk?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť nahrávať zvuk v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Táto aplikácia môže požadovať nepretržitý prístup k nahrávaniu zvuku, aj keď ju nepoužívate. "<annotation id="link">"Povolíte ho v nastaveniach."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; zmeniť prístup k mikrofónu?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Chcete zmeniť prístup k mikrofónu pre &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Táto aplikácia požaduje nepretržitý prístup k nahrávaniu zvuku, aj keď ju nepoužívate. "<annotation id="link">"Povolíte ho v nastaveniach."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k vašej fyzickej aktivite?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k údajom o fyzickej aktivite v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotiť a nahrávať video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť snímať fotky a nahrávať videá v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Táto aplikácia bude môcť fotiť a nahrávať videá iba vtedy, keď ju budete používať"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotiť a nahrávať videá?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť snímať fotky a nahrávať videá v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Táto aplikácia môže požadovať nepretržitý prístup k foteniu a nahrávaniu videí, aj keď ju nepoužívate. "<annotation id="link">"Povolíte ho v nastaveniach."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; zmeniť prístup k fotoaparátu?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Zmeniť prístup ku kamere pre &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Táto aplikácia požaduje nepretržitý prístup k foteniu a nahrávaniu videí, aj keď ju nepoužívate. "<annotation id="link">"Povolíte ho v nastaveniach."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k zoznamu tel. hovorov?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť prístup k zoznamu hovorov telefónu v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uskutočňovať a spravovať telefonické hovory?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uskutočňovať a spravovať telefonické hovor v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; používať údaje senzorov o vašich životných funkciách?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k dátam senzora o životných funkciách v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Táto aplikácia požaduje nepretržitý prístup k dátam senzorov o vašich životných funkciách, a to aj vtedy, keď ju nepoužívate. Povolíte to "<annotation id="link">"v nastaveniach"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; používať dáta senzorov o vašich životných funkciách?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k dátam senzora o životných funkciách v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Ak chcete tejto aplikácii povoliť nepretržitý prístup k údajom telového senzora, a to aj v prípade, že ju nepoužívate, "<annotation id="link">"prejdite do nastavení."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k dátam telových senzorov počas jej používania?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Má mať &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; počas používania naďalej prístup k dátam telových senzorov v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; posielať vám upozornenia?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Chcete aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; povoliť odosielať upozornenia v zariadení &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Ovládané povolenia"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> má prístup k polohe"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Vaša organizácia povoľuje aplikácii <xliff:g id="APP_NAME">%1$s</xliff:g> prístup k vašej polohe"</string>
@@ -583,12 +622,13 @@
<string name="mic_toggle_description" msgid="9163104307990677157">"Pre aplikácie a služby. Keď je toto nastavenie vypnuté a zavoláte na tiesňovú linku, údaje mikrofónu sa môžu stále zdieľať."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Zobraziť aplikácie a služby, ktoré majú prístup k polohe"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Zobrazovať prístup k schránke"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Zobrazovať správu, keď sa aplikácie získajú pristup k textu, obrázkom alebo inému obsahu, ktorý ste skopírovali"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Zobrazovať správu, keď aplikácie získajú pristup k textu, obrázkom alebo inému obsahu, ktorý ste skopírovali"</string>
<string name="show_password_title" msgid="2877269286984684659">"Zobrazovať heslá"</string>
<string name="show_password_summary" msgid="1110166488865981610">"Pri písaní nakrátko zobrazovať zadávané znaky"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"V tejto aplikácii bolo uvedené, že môže zdieľať údaje o polohe s tretími stranami"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Zdieľanie údajov a poloha"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Odkiaľ pochádzajú informácie o zdieľaní údajov"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Vývojár poskytol výrobcovi tohto zariadenia informácie, ako táto aplikácia zdieľa údaje. Priebežne môže dané informácie aktualizovať."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Vývojár poskytol v sekcii "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" informácie o tom, ako táto aplikácia zdieľa údaje. Priebežne môže dané informácie aktualizovať."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Aplikácia môže zdieľať údaje o polohe na účely:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Zdieľanie údajov sa líši"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Zabezpečenie údajov"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Môžu sa zdieľať údaje o polohe"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"V tejto aplikácii je uvedené, že môže zdieľať údaje o polohe s tretími stranami"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Tento odkaz sa nedá otvoriť"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Aktualizácie zdieľania údajov o polohe"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Skontrolujte aplikácie, ktoré zmenili spôsob zdieľania údajov o vašej polohe"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Tieto aplikácie zmenili spôsob zdieľania údajov o vašej polohe. Možno ich v minulosti nezdieľali alebo ich teraz zdieľajú na účely reklamy a marketingu."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Aktualizácie zdieľania údajov"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Niektoré aplikácie zmenili spôsob zdieľania údajov o polohe"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Nastavenia"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Otvorené <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Otvorené včera <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Otvorené <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-sl-v33/strings.xml b/PermissionController/res/values-sl-v33/strings.xml
index 6d250edb4..6bc0748fb 100644
--- a/PermissionController/res/values-sl-v33/strings.xml
+++ b/PermissionController/res/values-sl-v33/strings.xml
@@ -20,7 +20,7 @@
<string name="role_sms_request_description" msgid="1506966389698625395">"Ta aplikacija vam bo lahko pošiljala obvestila ter bo imela dostop do fotoaparata, stikov, datotek, mikrofona, telefona in sporočil SMS."</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikacije s tem dovoljenjem lahko dostopajo do vseh datotek v tej napravi."</string>
<string name="work_policy_title" msgid="832967780713677409">"Podatki o službenem pravilniku"</string>
- <string name="work_policy_summary" msgid="3886113358084963931">"Nastavitve upravlja skrbnik za IT"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Nastavitve upravlja skrbnik za IT."</string>
<string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Razširi in prikaži seznam"</string>
<string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Strni seznam in skrij nastavitve"</string>
<string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Seznam. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
@@ -40,7 +40,7 @@
<string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Stikalo. <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">"Preklop"</string>
<string name="safety_center_qs_open_action" msgid="2760200829912423728">"Odpri"</string>
- <string name="safety_center_review_settings_button" msgid="938981137942443930">"Pregled nastavitev"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Preglejte nastavitve"</string>
<string name="safety_center_gear_label" msgid="5175877094379694098">"Nastavitve"</string>
<string name="safety_center_info_label" msgid="8993181584061825412">"Informacije"</string>
</resources>
diff --git a/PermissionController/res/values-sl-v34/strings.xml b/PermissionController/res/values-sl-v34/strings.xml
index a616b355e..18afff3d1 100644
--- a/PermissionController/res/values-sl-v34/strings.xml
+++ b/PermissionController/res/values-sl-v34/strings.xml
@@ -20,8 +20,8 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Varnost in zasebnost"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kontrolniki"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Upravljajte dostop aplikacij do podatkov o zdravju"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Upravljajte dostop aplikacij do podatkov o zdravju."</string>
<string name="location_settings" msgid="8863940440881290182">"Dostop do lokacije"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"Za aplikacije in storitve. Če je ta nastavitev izklopljena, bodo podatki mikrofona morda še vedno deljeni, ko pokličete številko za klic v sili."</string>
- <string name="location_settings_subtitle" msgid="6846532794702613851">"Za aplikacije in storitve"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Za aplikacije in storitve."</string>
</resources>
diff --git a/PermissionController/res/values-sl/strings.xml b/PermissionController/res/values-sl/strings.xml
index 9b6cbf369..80fa38f28 100644
--- a/PermissionController/res/values-sl/strings.xml
+++ b/PermissionController/res/values-sl/strings.xml
@@ -34,13 +34,14 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Več informacij"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Dovoli vse"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Vedno dovoli vse"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Dovoli omejen dostop"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Izberi fotografije in videoposnetke"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Izberi več"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Brez izbire dodatnih"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ne dovoli kljub temu"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Opusti"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> od <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Ali dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; izvesti to dejanje: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; izvesti to dejanje: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="permission_add_background_warning_template" msgid="1812914855915092273">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; vedno dovoliti to dejanje: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Samo med uporabo aplikacije"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Vedno"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikacije"</string>
<string name="app_permissions" msgid="3369917736607944781">"Dovoljenja za aplikacije"</string>
<string name="unused_apps" msgid="2058057455175955094">"Neuporabljene aplikacije"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Urejanje izbranih fotografij za to aplikacijo"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Ni neuporabljenih aplikacij."</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 neuporabljenih aplikacij"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Nedavne odločitve o dovoljenjih"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Vedno dovoli"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Dovoli samo med uporabo aplik."</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Dovoli samo med uporabo aplikacije"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Ne dovoli"</string>
<string name="loading" msgid="4789365003890741082">"Nalaganje …"</string>
<string name="all_permissions" msgid="6911125611996872522">"Vsa dovoljenja"</string>
<string name="other_permissions" msgid="2901186127193849594">"Druge zmožnosti aplikacije"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Zahteva za dovoljenje"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Dejanja namestitve in odstranitve v sistemu Android Wear niso podprta."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Izberite, do česa aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovolite dostop"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; je posodobljena. Izberite, do česa tej aplikaciji dovolite dostop."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Prekliči"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Odstrani dovoljenja, če aplikacija ni v uporabi"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Odstrani dovoljenja in sprosti prostor"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Zaustavi dejavnost aplikacije ob neuporabi"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Upravljanje aplikacije ob neuporabi"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Dovoljenja se odstranijo, začasne datoteke se izbrišejo in prikazovanje obvestil se ustavi."</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Odstranitev dovoljenj, izbris začasnih datotek, ustavitev prikazovanja obvestil in arhiviranje aplikacije"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Z namenom zaščite podatkov bodo dovoljenja za to aplikacijo odstranjena, če je več mesecev ne boste uporabljali."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Če aplikacije več mesecev ne boste uporabljali, bodo z namenom zaščite podatkov odstranjena ta dovoljenja: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Z namenom zaščite podatkov so bila odstranjena dovoljenja za aplikacije, ki jih več mesecev niste uporabljali."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Nazadnje odprto: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Če dovolite upravljanje vseh datotek, lahko ta aplikacija dostopa do vseh datotek, ki so v skupni shrambi v tej napravi ali povezanih napravah za shranjevanje, ter jih ureja in briše. Aplikacija lahko do datotek dostopa brez vaše vednosti."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Ali tej aplikaciji dovolite dostop do datotek, ki so v napravi ali drugih povezanih napravah za shranjevanje, ter njihovo spreminjanje in brisanje? Ta aplikacija lahko do datotek dostopa brez vaše vednosti."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacije s tem dovoljenjem imajo te možnosti: <xliff:g id="DESCRIPTION">%1$s</xliff:g>."</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacije s tem dovoljenjem lahko izvedejo to dejanje: <xliff:g id="DESCRIPTION">%1$s</xliff:g>."</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Aplikacije s tem dovoljenjem lahko dostopajo do podatkov o vaši telesni dejavnosti, na primer hoji, kolesarjenju, vožnji, številu korakov itd."</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Aplikacije s tem dovoljenjem lahko dostopajo do koledarja."</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Aplikacije s tem dovoljenjem lahko berejo dnevnik klicev v telefonu in zapisujejo vanj."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikacija za zapiske"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplikacije, ki vam omogočajo ustvarjanje zapiskov v napravi."</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"zapiski"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Trenutna privzeta nastavitev"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ne vprašaj me več"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Nastavi kot privzeto"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Prikaz zaznavanja sprožilca za pomočnika"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Prikaz ikone v vrstici stanja, ko z mikrofonom aktivirate glasovnega pomočnika"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do fotografij in predstavnosti v napravi?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do fotografij in predstavnosti v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do stikov?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do stikov v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do lokacije te naprave?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do lokacije naprave &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikacija bo imela dostop do lokacije samo, ko aplikacijo uporabljate"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do lokacije te naprave?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do lokacije naprave &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Ta aplikacija bo morda želela imeti stalen dostop do vaše lokacije, tudi ko aplikacije ne boste uporabljali. "<annotation id="link">"Omogočite v nastavitvah."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Želite spremeniti dostop do lokacije za aplikacijo &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Želite spremeniti dostop do lokacije za aplikacijo &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Ta aplikacija želi imeti stalen dostop do vaše lokacije, tudi ko aplikacije ne uporabljate. "<annotation id="link">"Omogočite v nastavitvah."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Ali apl. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovolite iskanje naprav v bližini, povezovanje z njimi in določanje njihove rel. lokacije?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Žel. apl. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti isk. napr. v bliž., pov. z njimi in določ. rel. lok. v napr. &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Ali aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovolite iskanje naprav v bližini, povezovanje z njimi in določanje njihove rel. lokacije? "<annotation id="link">"Omogočite v nastavitvah."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Ali želite aplikaciji <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> omogočiti dostop do natančne lokacije namesto približne?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Želite dostop do lokacije za aplikacijo <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; spremeniti iz približnega v natančnega?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do približne lokacije te naprave?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do približne lokacije naprave &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Natančna"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Približna"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do koledarja?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do koledarja v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pošiljanje in ogled sporočil SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti pošiljanje in ogled sporočil SMS v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do fotografij, predstavnosti in datotek v svoji napravi?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Želite aplik. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do fotografij, predstavnosti in datotek v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do &lt;b&gt;fotografij, videoposnetkov, glasbe in zvočnih datotek&lt;/b&gt; v tej napravi?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do &lt;b&gt;fotografij, videoposnetkov, glasbe, zvočnih datotek in drugih datotek&lt;/b&gt; v tej napravi?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do glasbe in zvočnih datotek v tej napravi?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do glasbe in zvočnih datotek v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do fotografij in videoposnetkov v tej napravi?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do fotografij in videoposnetkov v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do več fotografij in videoposnetkov v tej napravi?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do več fotografij in videoposnetkov v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snemanje zvoka?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti snemanje zvoka v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikacija bo lahko snemala zvok le med vašo uporabo aplikacije."</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; omogočiti snemanje zvoka?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti snemanje zvoka v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Ta aplikacija bo morda želela vseskozi snemati zvok, tudi ko aplikacije ne uporabljate. "<annotation id="link">"To omogočite v nastavitvah."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Želite spremeniti dostop do mikrofona za aplikacijo &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Želite spremeniti dostop do mikrofona za aplikacijo &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Ta aplikacija želi vseskozi snemati zvok, tudi ko aplikacije ne uporabljate. "<annotation id="link">"To omogočite v nastavitvah."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do svoje telesne dejavnosti?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do telesne dejavnosti v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotografiranje in snemanje videoposnetkov?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti snemanje fotografij in videoposnetkov v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikacija bo lahko snemala fotografije in videoposnetke le med vašo uporabo aplikacije."</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; omogočiti fotografiranje in snemanje videoposnetkov?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti snemanje fotografij in videoposnetkov v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Ta aplikacija bo morda želela vseskozi snemati fotografije in videoposnetke, tudi ko aplikacije ne uporabljate. "<annotation id="link">"To omogočite v nastavitvah."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Želite spremeniti dostop do fotoaparata za aplikacijo &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Želite spremeniti dostop do fotoaparata za aplikacijo &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Ta aplikacija želi vseskozi snemati fotografije in videoposnetke, tudi ko aplikacije ne uporabljate. "<annotation id="link">"To omogočite v nastavitvah."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do dnevnikov klicev v telefonu?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do dnevnikov telefonskih klicev v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; opravljanje in upravljanje telefonskih klicev?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Želite aplik. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti opravljanje in upravljanje telefonskih klicev v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Dovolite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dostop do podatkov tipala o vitalnih znakih?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do podatkov tipal o vitalnih znakih v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Ta aplikacija želi stalen dostop do podatkov tipal vitalnih znakov, tudi ko aplikacije ne uporabljate. Če želite izvesti to spremembo, "<annotation id="link">"pojdite v nastavitve"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; omogočiti dostop do podatkov tipal o vitalnih znakih?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti dostop do podatkov tipal o vitalnih znakih v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Če želite tej aplikaciji omogočiti stalen dostop do podatkov tipal telesnih funkcij, tudi ko je ne uporabljate, "<annotation id="link">"pojdite v nastavitve"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Ali želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; še naprej dovoliti dostop do podatkov tipal telesnih funkcij, ko je v uporabi?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Žel. apl. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; še napr. dov. dost. do pod. tip. tel. funkc., ko je v upor.?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; omogočiti, da vam pošilja obvestila?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Želite aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dovoliti pošiljanje obvestil v napravi &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Zunanje upravljana dovoljenja"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ima dostop do lokacije"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Vaša organizacija aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> dovoljuje dostop do vaše lokacije."</string>
@@ -579,7 +618,7 @@
<string name="privacy_controls_title" msgid="7605929972256835199">"Nastavitve zasebnosti"</string>
<string name="camera_toggle_title" msgid="1251201397431837666">"Dostop do fotoaparata"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Dostop do mikrofona"</string>
- <string name="perm_toggle_description" msgid="7801326363741451379">"Za aplikacije in storitve"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Za aplikacije in storitve."</string>
<string name="mic_toggle_description" msgid="9163104307990677157">"Za aplikacije in storitve. Če je ta nastavitev izklopljena, bodo podatki mikrofona morda še vedno deljeni, ko pokličete številko za klic v sili."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Oglejte si aplikacije in storitve, ki imajo dostop do lokacije."</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Pokaži dostop do odložišča"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Ta aplikacija navaja, da bo lokacijske podatke morda delila s tretjimi osebami."</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Deljenje podatkov in lokacija"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Vir informacij o deljenju podatkov"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Razvijalec je z informacijami o tem, kako ta aplikacija deli podatke, seznanil proizvajalca naprave. Razvijalec bo morda te informacije občasno posodobil."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Razvijalec je z informacijami o tem, kako ta aplikacija deli podatke, seznanil trgovino z aplikacijami "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". Razvijalec bo morda te informacije občasno posodobil."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Ta aplikacija lahko deli lokacijske podatke za:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Načini deljenja podatkov se med seboj razlikujejo"</string>
@@ -606,10 +646,8 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Varnost podatkov"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Lokacijski podatki so morda deljeni z drugimi"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Ta aplikacija navaja, da bo vaše lokacijske podatke morda delila s tretjimi osebami."</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Te povezave ni mogoče odpreti"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Posodobitve deljenja podatkov o lokaciji"</string>
- <string name="data_sharing_updates_summary" msgid="764113985772233889">"Pregled aplikacij s spremembami v načinu deljenja vaših lokacijskih podatkov"</string>
+ <string name="data_sharing_updates_summary" msgid="764113985772233889">"Pregled aplikacij s spremembami v načinu deljenja vaših lokacijskih podatkov."</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Te aplikacije so spremenile način deljenja vaših lokacijskih podatkov. Prej jih morda sploh niso delile ali pa jih zdaj delijo za namene oglaševanja ali trženja."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Razvijalci teh aplikacij so trgovino z aplikacijami seznanili z informacijami o svojih postopkih deljenja podatkov. Te informacije bodo občasno morda posodobljene.\n\nPostopki deljenja podatkov se lahko razlikujejo glede na različico aplikacije, njeno uporabo, regijo ali vašo starost."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Preberite več o deljenju podatkov."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Posodobitve deljenja podatkov"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Nekatere aplikacije so spremenile način deljenja vaših lokacijskih podatkov."</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Nastavitve"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Zadnji dostop: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Zadnji dostop včeraj: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Zadnji dostop: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-sq-v33/strings.xml b/PermissionController/res/values-sq-v33/strings.xml
index 6bbdb8b5b..bbe8e9a89 100644
--- a/PermissionController/res/values-sq-v33/strings.xml
+++ b/PermissionController/res/values-sq-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Sinjalizime të tjera"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Sinjalizime të shpërfillura"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Zgjero dhe shiko një sinjalizim tjetër}other{Zgjero dhe shiko # sinjalizime të tjera}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Sinjalizim. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Veprimi përfundoi"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Shiko cilësimet që mund të shtojnë mbrojtjen e pajisjes sate"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Cilësimet e shpejta të sigurisë dhe të privatësisë"</string>
diff --git a/PermissionController/res/values-sq/strings.xml b/PermissionController/res/values-sq/strings.xml
index 806dd572e..ad8afdc36 100644
--- a/PermissionController/res/values-sq/strings.xml
+++ b/PermissionController/res/values-sq/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Më shumë info."</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Lejoji të gjitha"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Lejoji gjithmonë të gjitha"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Lejo qasjen e kufizuar"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Zgjidh fotografi dhe video"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Zgjidh më shumë"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Mos zgjidh të tjera"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Mos lejo gjithsesi"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Hiqe"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> nga <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Të lejohet &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; që të <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Të lejohet gjithmonë &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; që <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Të lejohet &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të kryejë këtë veprim: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Të lejohet gjithmonë &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të kryejë këtë veprim: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Vetëm gjatë përdorimit të aplikacionit"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Gjithmonë"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Mos lejo dhe mos pyet përsëri"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Aplikacionet"</string>
<string name="app_permissions" msgid="3369917736607944781">"Lejet e aplikacionit"</string>
<string name="unused_apps" msgid="2058057455175955094">"Aplikacionet e papërdorura"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Modifiko fotografitë e zgjedhura për këtë aplikacion"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Nuk ka aplikacione të papërdorura"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 aplikacione të papërdorura"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Vendimet e fundit për lejet"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Të gjitha lejet"</string>
<string name="other_permissions" msgid="2901186127193849594">"Kapacitete të tjera të aplikacionit"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Kërkesa e lejes"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Instalo/çinstalo veprimet që nuk mbështeten në Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Zgjidh se ku do të lejohet të ketë qasje &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; është përditësuar. Zgjidh se ku do të lejohet të ketë qasje ky aplikacion."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Anulo"</string>
@@ -195,8 +195,8 @@
<string name="approximate_image_description" msgid="938803699637069884">"Vendndodhja e përafërt"</string>
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"Përdor vendndodhjen e saktë"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Kur është joaktive vendndodhja e saktë, aplikacionet mund të qasen te vendndodhja jote e përafërt"</string>
- <string name="app_permission_title" msgid="2090897901051370711">"Leje për te <xliff:g id="PERM">%1$s</xliff:g>"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"Qasja te <xliff:g id="PERM">%1$s</xliff:g> për këtë aplikacion"</string>
+ <string name="app_permission_title" msgid="2090897901051370711">"Leje për te \"<xliff:g id="PERM">%1$s</xliff:g>\""</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"Qasja te \"<xliff:g id="PERM">%1$s</xliff:g>\" për këtë aplikacion"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Shiko të gjitha lejet e aplikacionit \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Shiko të gjitha aplikacionet me këtë leje"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Shfaq përdorimin e mikrofonit të \"Asistentit\""</string>
@@ -204,14 +204,16 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Hiq lejet nëse aplikacioni nuk është përdorur"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Hiq lejet dhe liro hapësirën"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Ndërprit aktivitetin nëse nuk përdoret"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Menaxho aplikacionin nëse nuk përdoret"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Hiq lejet, fshi skedarët e përkohshëm dhe ndalo njoftimet"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Hiq lejet, fshi skedarët e përkohshëm, ndalo njoftimet dhe arkivo aplikacionin"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Për të mbrojtur të dhënat e tua, lejet për këtë aplikacion do të hiqen nëse aplikacioni nuk përdoret për disa muaj."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Për të mbrojtur të dhënat e tua, nëse aplikacioni nuk është përdorur për disa muaj, lejet e mëposhtme do të hiqen: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Për të mbrojtur të dhënat e tua, lejet janë hequr nga aplikacionet që nuk i ke përdorur për disa muaj."</string>
<string name="auto_revoke_open_app_message" msgid="8075556291711205039">"Nëse dëshiron t\'i lejosh përsëri lejet, hap aplikacionin."</string>
<string name="auto_revoke_disabled" msgid="8697684442991567188">"Heqja automatike aktualisht është çaktivizuar për këtë aplikacion."</string>
<string name="auto_revocable_permissions_none" msgid="8334929619113991466">"Aktualisht nuk janë dhënë leje të revokueshme automatikisht"</string>
- <string name="auto_revocable_permissions_one" msgid="5299112369449458176">"Leja për \"<xliff:g id="PERM">%1$s</xliff:g>\" do të hiqet."</string>
+ <string name="auto_revocable_permissions_one" msgid="5299112369449458176">"Leja për te \"<xliff:g id="PERM">%1$s</xliff:g>\" do të hiqet."</string>
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Lejet <xliff:g id="PERM_0">%1$s</xliff:g> dhe <xliff:g id="PERM_1">%2$s</xliff:g> do të hiqen."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Lejet që do të hiqen: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Menaxho automatikisht lejet"</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Hapur së fundi më <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Nëse lejon menaxhimin e të gjithë skedarëve, ky aplikacion mund të ketë qasje, modifikojë dhe fshijë çdo skedar në hapësirën ruajtëse të përbashkët në këtë pajisje ose pajisjet me hapësirë ruajtëse të lidhur. Aplikacioni mund të ketë qasje te skedarët pa të pyetur."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Të lejohet që ky aplikacion të qaset, modifikojë dhe fshijë skedarët në pajisje ose në çdo pajisje me hapësirë ruajtëse të lidhur? Ky aplikacion mund të ketë qasje te skedarët pa të pyetur."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacioneve me këtë leje u lejohet <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Aplikacioneve me këtë leje u lejohet ky veprim: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Aplikacionet me këtë leje mund të kenë qasje tek aktiviteti yt fizik, si: ecja në këmbë, me biçikletë, me makinë, numërimi i hapave etj."</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Aplikacionet me këtë leje mund të kenë qasje te kalendari yt"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Aplikacionet me këtë leje mund të lexojnë dhe të shkruajnë në evidencën e telefonatave të telefonit"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Aplikacioni për shënime"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Aplikacione që të lejojnë të mbash shënime në pajisjen tënde"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"shënime"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Parazgjedhja aktuale"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Mos pyet më"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Cakto si parazgjedhje"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Shfaq zbulimin e aktivizimit të asistentit"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Shfaq ikonën në shiritin e statusit kur përdoret mikrofoni për të aktivizuar asistentin me zë"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te fotografitë dhe media në pajisjen tënde?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te fotografitë dhe media në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te kontaktet e tua?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te kontaktet e tua në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te vendndodhja e kësaj pajisjeje?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te vendndodhja e &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Aplikacioni do të ketë qasje te vendndodhja vetëm kur po e përdor aplikacionin"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te vendndodhja e kësaj pajisjeje?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te vendndodhja e &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Ky aplikacion mund të dëshirojë të ketë qasje në vendndodhjen tënde gjatë gjithë kohës, edhe kur nuk po e përdor aplikacionin. "<annotation id="link">"Lejoje te cilësimet"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Do ta ndryshosh qasjen për vendndodhjen për &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Të ndryshohet qasje te vendndodhja për &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Ky aplikacion dëshiron të ketë qasje në vendndodhjen tënde gjatë gjithë kohës, edhe kur nuk po e përdor aplikacionin. "<annotation id="link">"Lejoje te cilësimet"</annotation>"."</string>
- <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Të lejohet &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të gjejë, lidhet dhe përcaktojë pozicionin relativ të pajisjeve në afërsi?"</string>
- <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Të lejohet &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të gjejë, lidhet dhe përcaktojë pozicionin relativ të pajisjeve në afërsi? "<annotation id="link">"Lejoje te cilësimet."</annotation></string>
+ <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Të lejohet &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të gjejë, të lidhet dhe të përcaktojë pozicionin relativ të pajisjeve në afërsi?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të gjejë, të lidhet dhe të përcaktojë pozicionin e përafërt të pajisjeve në afërsi në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Të lejohet &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të gjejë, të lidhet dhe të përcaktojë pozicionin relativ të pajisjeve në afërsi? "<annotation id="link">"Lejoje te cilësimet."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Të ndryshohet qasja që ka <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> te vendndodhja nga \"e përafërt\" në \"e saktë\"?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Të ndryshohet qasja e <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> te vendndodhja në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; nga e përafërt në e saktë?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te vendndodhja e përafërt e kësaj pajisjeje?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te vendndodhja e përafërt e &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"E saktë"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"E përafërt"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te kalendari yt?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te kalendari yt në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të dërgojë dhe të shikojë mesazhet SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të dërgojë dhe të shikojë mesazhet SMS në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te fotografitë, media dhe skedarët në pajisjen tënde?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te fotografitë, media dhe skedarët në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te &lt;b&gt;fotografitë, videot, muzika dhe audioja&lt;/b&gt; në këtë pajisje?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Të lejohet që &lt;b&amp;gt<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te &lt;b&gt;fotografitë, videot, muzika, audioja e të tjera&lt;/b&gt; në pajisje?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te muzika dhe te audioja në këtë pajisje?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te muzika dhe audioja në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te fotografitë dhe videot në këtë pajisje?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te fotografitë dhe videot në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të qaset te më shumë fotografi dhe video në pajisje?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje në më shumë fotografi dhe video në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të regjistrojë audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të regjistrojë audio në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikacioni do të mund të regjistrojë audion vetëm kur ti po e përdor aplikacionin"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të regjistrojë audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të regjistrojë audio në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Ky aplikacion mund të dëshirojë të regjistrojë audion gjatë gjithë kohës, edhe kur ti nuk po e përdor aplikacionin. "<annotation id="link">"Lejoje te cilësimet"</annotation>"."</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Të ndryshohet qasja për mikrofonin për &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Të ndryshohet qasja te mikrofoni për &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Ky aplikacion dëshiron të regjistrojë audion gjatë gjithë kohës, edhe kur ti nuk po e përdor aplikacionin. "<annotation id="link">"Lejoje te cilësimet"</annotation>"."</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje në aktivitetin tënd fizik?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje tek aktiviteti yt fizik në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të nxjerrë fotografi dhe të regjistrojë video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të nxjerrë fotografi dhe të regjistrojë video në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Aplikacioni do të mund të nxjerrë fotografi dhe të regjistrojë video vetëm kur ti po e përdor aplikacionin"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të nxjerrë fotografi dhe të regjistrojë video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të nxjerrë fotografi dhe të regjistrojë video në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Ky aplikacion mund të dëshirojë të nxjerrë fotografi dhe video gjatë gjithë kohës, edhe kur ti nuk po e përdor aplikacionin. "<annotation id="link">"Lejoje te cilësimet"</annotation>"."</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Të ndryshohet qasja për kamerën për &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Të ndryshohet qasja te kamera për &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Ky aplikacion dëshiron të nxjerrë fotografi dhe video gjatë gjithë kohës, edhe kur ti nuk po e përdor aplikacionin. "<annotation id="link">"Lejoje te cilësimet"</annotation>"."</string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Të lejohet &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje në evidencat e tua të telefonatave?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje tek evidencat e telefonatave të telefonit në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të kryejë dhe të menaxhojë telefonata?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të bëjë dhe të menaxhojë telefonatat në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te të dhënat e sensorëve rreth shenjave të tua jetësore?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te të dhënat e sensorëve rreth shenjave jetësore në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Aplikacioni kërkon qasje te të dhënat e sensorëve rreth shenjave të tua jetësore gjithmonë, edhe kur nuk e përdor aplikacionin. Për ta bërë këtë ndryshim, "<annotation id="link">"shko te cilësimet."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te të dhënat e sensorëve rreth shenjave të tua jetësore?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te të dhënat e sensorëve rreth shenjave jetësore në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Për të lejuar këtë aplikacion që të ketë qasje te të dhënat e sensorit të trupit gjithmonë, edhe kur nuk e përdor aplikacionin, "<annotation id="link">"shko te cilësimet."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Të lejohet akoma që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te të dhënat e sensorit të trupit kur aplikacioni përdoret?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Të lejohet akoma që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te të dhënat e sensorëve të trupit në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; kur aplikacioni është në përdorim?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të të dërgojë njoftime?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të të dërgojë njoftime në &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Lejet e kontrolluara"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ka qasje te vendndodhja"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Organizata jote lejon që <xliff:g id="APP_NAME">%1$s</xliff:g> të ketë qasje te vendndodhja jote"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Leje të tjera"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Lejet e përdorura nga sistemi"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Lejet e përdorura vetëm nga aplikacionet e sistemit."</string>
@@ -591,7 +628,8 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Ky aplikacion deklaroi se mund të ndajë të dhënat e vendndodhjes me palë të treta"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Ndarja e të dhënave dhe vendndodhja"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Nga vijnë informacionet rreth ndarjes së të dhënave"</string>
- <string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Zhvilluesi i ofroi informacione "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" rreth mënyrës se si ky aplikacion ndan të dhënat. Zhvilluesi mund t\'i përditësojë këto informacione me kalimin e kohës."</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Zhvilluesi i ka dhënë informacione prodhuesit të kësaj pajisjeje rreth mënyrës se si ky aplikacion ndan të dhënat. Zhvilluesi mund t\'i përditësojë këto informacione me kalimin e kohës."</string>
+ <string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Zhvilluesi i ka dhënë informacione "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" rreth mënyrës se si ky aplikacion ndan të dhënat. Zhvilluesi mund t\'i përditësojë këto informacione me kalimin e kohës."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Apl. mund të ndajë të dhënat e vendndodhjes për:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Ndarja e të dhënave ndryshon"</string>
<string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Veprimet me të dhënat mund të ndryshojnë bazuar në versionin e aplikacionit, përdorimin, rajonin dhe moshën tënde. "<annotation id="link">"Më shumë rreth ndarjes së të dhënave"</annotation></string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Siguria e të dhënave"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Të dhënat e vendndodhjes mund të ndahen"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Ky aplikacion deklaroi se mund të ndajë të dhënat e vendndodhjes sate me palë të treta"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Kjo lidhje nuk mund të hapet"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Përditësime për ndarjen e të dhënave për vendndodhjen"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Shqyrto aplikacionet që ndryshuan mënyrën se si mund të ndajnë të dhënat e vendndodhjes sate"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Këto aplikacione kanë ndryshuar mënyrën se si mund të ndajnë të dhënat e vendndodhjes sate. Ato mund të mos i kenë ndarë më parë ose mund t\'i ndajnë tani për qëllime reklamimi dhe marketingu."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Përditësimet për ndarjen e të dhënave"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Disa aplikacione ndryshuan mënyrën se si mund të ndajnë të dhënat e vendndodhjes sate"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Cilësimet"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Qasja e fundit në <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Qasja e fundit dje në <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Qasja e fundit më <xliff:g id="TIME_DATE_0">%1$s</xliff:g> në <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-sr-v33/strings.xml b/PermissionController/res/values-sr-v33/strings.xml
index c169467d3..1fe22cee5 100644
--- a/PermissionController/res/values-sr-v33/strings.xml
+++ b/PermissionController/res/values-sr-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Још обавештења"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Одбачена обавештења"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Проширите и видите још једно обавештење}one{Проширите и видите још # обавештење}few{Проширите и видите још # обавештења}other{Проширите и видите још # обавештења}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Обавештење. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Радња је довршена"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Проверите подешавања која могу да додају заштиту уређају"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Брза подешавања безбедности и приватности"</string>
diff --git a/PermissionController/res/values-sr/strings.xml b/PermissionController/res/values-sr/strings.xml
index 689ad201d..8b3bbf0ce 100644
--- a/PermissionController/res/values-sr/strings.xml
+++ b/PermissionController/res/values-sr/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Више информација"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Дозволи све"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Увек дозволи све"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Дозволи ограничен приступ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Изаберите слике и видео снимке"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Изаберите још"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Не бирај више"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ништа више"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ионако не дозволи"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Одбаци"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> од <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Апликације"</string>
<string name="app_permissions" msgid="3369917736607944781">"Дозволе за апликације"</string>
<string name="unused_apps" msgid="2058057455175955094">"Апликације које се не користе"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Мењај изабране слике за ову апликацију"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Нема аплик. које се не користе"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 апликац. које се не користе"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Недавне одлуке о дозволама"</string>
@@ -93,7 +95,7 @@
<string name="location_warning" msgid="2381649060929040962">"<xliff:g id="APP_NAME">%1$s</xliff:g> пружа услуге локације за овај уређај. Приступ локацији можете да измените у подешавањима локације."</string>
<string name="system_warning" msgid="1173400963234358816">"Ако одбијете ову дозволу, основне функције уређаја можда неће више исправно радити."</string>
<string name="deny_read_media_visual_warning" msgid="3982586279917232827">"Ова апликација је дизајнирана за старију верзију Android-а. Ако овој апликацији одбијете приступ за слике и видео снимке, повлачи се и приступ музици и другим аудио снимцима."</string>
- <string name="deny_read_media_aural_warning" msgid="8928699919508646732">"Ова апликација је дизајнирана за старију верзију Android-а. Ако овој апликацији одбијете приступ за музику и друге аудио снимке, повлачи се и приступ сликама и видео снимцима."</string>
+ <string name="deny_read_media_aural_warning" msgid="8928699919508646732">"Ова апликација је дизајнирана за старију верзију Android-а. Ако овој апликацији одбијете приступ за музику и друге аудио снимке, повлачи се и приступ сликама и видеима."</string>
<string name="cdm_profile_revoke_warning" msgid="4443893270719106700">"Ако одбијете ову дозволу, неке функције уређаја којима управља ова апликација можда неће више исправно радити."</string>
<string name="permission_summary_enforced_by_policy" msgid="4443598170942950519">"Примењује се у складу са смерницама"</string>
<string name="permission_summary_disabled_by_policy_background_only" msgid="221995005556362660">"Приступ у позадини је онемогућен смерницама"</string>
@@ -108,14 +110,12 @@
<!-- no translation found for background_access_chooser_dialog_choices:1 (9127301153688725448) -->
<!-- no translation found for background_access_chooser_dialog_choices:2 (4305536986042401191) -->
<string name="permission_access_always" msgid="1474641821883823446">"Дозволи увек"</string>
- <string name="permission_access_only_foreground" msgid="7801170728159326195">"Дозв. само док се апл. користи"</string>
+ <string name="permission_access_only_foreground" msgid="7801170728159326195">"Дозволи само док се апл. користи"</string>
<string name="permission_access_never" msgid="4647014230217936900">"Не дозволи"</string>
<string name="loading" msgid="4789365003890741082">"Учитава се…"</string>
<string name="all_permissions" msgid="6911125611996872522">"Све дозволе"</string>
<string name="other_permissions" msgid="2901186127193849594">"Остале могућности апликације"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Захтев за дозволу"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Радње Инсталирај/Деинсталирај нису подржане у Wear-у."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Изаберите чему &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; може да приступа"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Апликација &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; је ажурирана. Изаберите чему ова апликација може да приступа."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Откажи"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Уклони дозволе ако се апликација не користи"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Уклони дозволе и ослободи простор"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Паузирај активности ако се не користи"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Управљајте апликацијом ако се не користи"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Уклоните дозволе, избришите привремене фајлове и зауставите обавештења"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Уклоните дозволе, избришите привремене фајлове, зауставите обавештења и архивирајте апликацију"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Ради заштите података, дозволе за ову апликацију се уклањају ако се апликација не користи пар месеци."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Ради заштите података, следеће дозволе се уклањају ако се апликација не користи пар месеци: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Ради заштите података, дозволе су уклоњене из апликација које нисте користили пар месеци."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Последњи пут отворено: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ако омогућите управљање свим датотекама, ова апликација може да приступа свим датотекама у заједничком меморијском простору на овом уређају или повезаним уређајима за складиштење и да мења и брише те датотеке. Апликација може да приступа датотекама без питања."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Желите ли да дозволите да ова апликација приступа датотекама на уређају или свим повезаним уређајима за складиштење и да мења и брише те датотеке? Ова апликација може да приступа датотекама без питања."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Апликације са овом дозволом могу <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Апликације са том дозволом имају ове могућности: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Апликације са овом дозволом могу да приступају подацима о физичким активностима, попут ходања, вожње бицикла, вожње аутомобила, броја корака и друго"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Апликације са овом дозволом могу да приступају календару"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Апликације са овом дозволом могу да читају и додају ставке у евиденцију позива на телефону"</string>
@@ -240,7 +242,7 @@
<string name="permission_description_summary_sms" msgid="725999468547768517">"Апликације са овом дозволом могу да шаљу и прегледају SMS-ове"</string>
<string name="permission_description_summary_storage" msgid="6575759089065303346">"Апликације са овом дозволом могу да приступају сликама, медијском садржају и фајловима на уређају"</string>
<string name="permission_description_summary_read_media_aural" msgid="3354728149930482199">"Апликације са овом дозволом могу да приступају музици и другим аудио фајловима на овом уређају"</string>
- <string name="permission_description_summary_read_media_visual" msgid="4991801977881732641">"Апликације са овом дозволом могу да приступају сликама и видео снимцима на овом уређају"</string>
+ <string name="permission_description_summary_read_media_visual" msgid="4991801977881732641">"Апликације са овом дозволом могу да приступају сликама и видеима на овом уређају"</string>
<string name="app_permission_most_recent_summary" msgid="4292074449384040590">"Последњи приступ: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_most_recent_denied_summary" msgid="7659497197737708112">"Тренутно одбијено/последњи приступ: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
<string name="app_permission_never_accessed_summary" msgid="401346181461975090">"Без приступа"</string>
@@ -397,10 +399,20 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и стримовање апликација на повезаном уређају."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ова услуга дели слике, медијски садржај и обавештења са телефона на другим уређајима."</string>
- <string name="role_notes_label" msgid="7451627001058089536">"Подразумевана аплик за белешке"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Подразумевана апл. за белешке"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"Апликација за белешке"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Апликације које вам омогућавају да правите белешке на уређају"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"белешке"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Тренутно подразумевана"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Не питај поново"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Подеси као подразум."</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Приказуј откривање активирања помоћника"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Приказује икону на статусној траци када се микрофон користи за активирање гласовног помоћника"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Желите ли да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа сликама и медијима на уређају?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа сликама и медијима на уређају &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа контактима на уређају &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"Дозвољавате да &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Дозвољавате да &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>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Ова апликација можда жели да приступа локацији све време, чак и када не користите апликацију. "<annotation id="link">"Дозволите у подешавањима."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Желите ли да промените приступ локацији за апликацију &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Мењате приступ локацији за апликацију &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Ова апликација жели да приступа локацији све време, чак и када не користите апликацију. "<annotation id="link">"Дозволите у подешавањима."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; проналази уређаје у близини, повезује се с њима и одређује им релативан положај?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; може да налази уређаје у близини, повезује се са њима и утврђује релативни положај на: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; проналази уређаје у близини, повезује се с њима и одређује им релативан положај? "<annotation id="link">"Дозволите у подешавањима."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Желите ли да промените приступ апликације <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> из приближне локације на прецизну?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Мењате приступ апликације <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> локацији уређаја &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа приближној локацији уређаја &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа календару на уређају &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; шаље и прегледа SMS поруке на уређају &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа сликама, медијима и фајловима на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Приступ &lt;b&gt;сликама, видеу, музици и звуку&lt;/b&gt; на уређају за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Приступ сликама, видеу, музици, звуку и другом на уређају за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Дозвољавате ли приступ музици и звуку на овом уређају за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа музици и аудио садржају на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Дозвољавате ли приступ сликама и видеу на овом уређају за &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Дозвољавате ли да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа и другим сликама и видео снимцима на овом уређају?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа сликама и видеима на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"Дозвољавате ли да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа и другим сликама и видеима на овом уређају?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа и другим сликама и видеима на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снима звук?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снима аудио садржај на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Апликација ће моћи да снима звук само док користите апликацију"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снима звук?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снима аудио садржај на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Ова апликација можда жели да снима звук све време, чак и када не користите апликацију. "<annotation id="link">"Дозволите у подешавањима."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Желите да промените приступ микрофону за апликацију &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Мењате приступ микрофону за апликацију &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Ова апликација жели да снима звук све време, чак и када не користите апликацију. "<annotation id="link">"Дозволите у подешавањима."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Желите ли да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа физичким активностима?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа подацима о физичким активностима на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снима слике и видео снимке?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Дозволићете да апликација &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снима слике и видео снимке на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Апликација ће моћи да снима слике и видео снимке само док користите апликацију"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снима слике и видео снимке?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снима слике и видео снимке на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Ова апликација можда жели да снима слике и видео снимке све време, чак и када не користите апликацију. "<annotation id="link">"Дозволите у подешавањима."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Желите да промените приступ камери за апликацију &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Мењате приступ камери за апликацију &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Ова апликација жели да снима слике и видео снимке све време, чак и када не користите апликацију. "<annotation id="link">"Дозволите у подешавањима."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа евиденцијама позива на телефону?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа евиденцијама телефонских позива на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; упућује позиве и управља њима?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; упућује телефонске позиве и управља њима на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Желите да дозволите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа подацима сензора о виталним функцијама?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа подацима сензора о виталним знацима на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Ова апликација жели да све време приступа подацима сензора о виталним функцијама, чак и када не користите апликацију. Да бисте обавили ову измену, "<annotation id="link">"идите у подешавања."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Желите да омогућите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа подацима сензора о виталним функцијама?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; приступа подацима сензора о виталним знацима на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Да бисте дозволили овој апликацији да све време приступа подацима сензора за тело, чак и када не користите апликацију, "<annotation id="link">"идите у подешавања."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Желите да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; и даље приступа подацима сензора за тело док се апликација користи?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Дозвољавате да &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; током коришћења и даље приступа подацима сензора за тело на: &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Желите да дозволите да вам &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; шаље обавештења?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Дозвољавате да вам &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; шаље обавештења на уређају &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Контролисане дозволе"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> има приступ локацији"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Организација дозвољава да <xliff:g id="APP_NAME">%1$s</xliff:g> приступа локацији"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Друге дозволе"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Дозволе које користи систем"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Дозволе које користе само системске апликације."</string>
@@ -560,18 +597,18 @@
<string name="media_confirm_dialog_title_a_to_p_aural_deny" msgid="7841428716317307685">"Ни приступ другим фајловима неће бити дозвољен"</string>
<string name="media_confirm_dialog_title_a_to_p_visual_allow" msgid="6469086448310893751">"Биће дозвољен приступ и другим фајловима"</string>
<string name="media_confirm_dialog_title_a_to_p_visual_deny" msgid="5767849609024384226">"Ни приступ другим фајловима неће бити дозвољен"</string>
- <string name="media_confirm_dialog_title_q_to_s_aural_allow" msgid="3191904399336990537">"Биће дозвољен приступ и сликама и видео снимцима"</string>
- <string name="media_confirm_dialog_title_q_to_s_aural_deny" msgid="3128147568953297969">"Ни приступ сликама и видео снимцима неће бити дозвољен"</string>
+ <string name="media_confirm_dialog_title_q_to_s_aural_allow" msgid="3191904399336990537">"Биће дозвољен приступ и сликама и видеима"</string>
+ <string name="media_confirm_dialog_title_q_to_s_aural_deny" msgid="3128147568953297969">"Ни приступ сликама и видеима неће бити дозвољен"</string>
<string name="media_confirm_dialog_title_q_to_s_visual_allow" msgid="6310682466493330434">"Биће дозвољен приступ и музици и аудио фајловима"</string>
<string name="media_confirm_dialog_title_q_to_s_visual_deny" msgid="1123845663785900471">"Ни приступ музици и аудио фајловима неће бити дозвољен"</string>
- <string name="media_confirm_dialog_message_a_to_p_aural_allow" msgid="7865167246140107623">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација може да приступа музици и аудио фајловима, биће јој дозвољено и да приступа сликама, видео снимцима и другим фајловима."</string>
- <string name="media_confirm_dialog_message_a_to_p_aural_deny" msgid="287502523664804786">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација не може да приступа музици и аудио фајловима, неће јој бити дозвољено ни да приступа сликама, видео снимцима и другим фајловима."</string>
- <string name="media_confirm_dialog_message_a_to_p_visual_allow" msgid="4952410892939590487">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација може да приступа сликама и видео снимцима, биће јој дозвољено и да приступа музици, аудио и другим фајловима."</string>
- <string name="media_confirm_dialog_message_a_to_p_visual_deny" msgid="6609500525590757681">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација не може да приступа сликама и видео снимцима, неће јој бити дозвољено ни да приступа музици, аудио и другим фајловима."</string>
- <string name="media_confirm_dialog_message_q_to_s_aural_allow" msgid="1702402580147536160">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација може да приступа музици и аудио фајловима, биће јој дозвољено и да приступа сликама и видео снимцима."</string>
- <string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација не може да приступа музици и аудио фајловима, неће јој бити дозвољено ни да приступа сликама и видео снимцима."</string>
- <string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација може да приступа сликама и видео снимцима, биће јој дозвољено и да приступа музици и аудио фајловима."</string>
- <string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација не може да приступа музици и аудио фајловима, неће јој бити дозвољено ни да приступа сликама и видео снимцима."</string>
+ <string name="media_confirm_dialog_message_a_to_p_aural_allow" msgid="7865167246140107623">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација може да приступа музици и аудио фајловима, биће јој дозвољено и да приступа сликама, видеима и другим фајловима."</string>
+ <string name="media_confirm_dialog_message_a_to_p_aural_deny" msgid="287502523664804786">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација не може да приступа музици и аудио фајловима, неће јој бити дозвољено ни да приступа сликама, видеима и другим фајловима."</string>
+ <string name="media_confirm_dialog_message_a_to_p_visual_allow" msgid="4952410892939590487">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација може да приступа сликама и видеима, биће јој дозвољено и да приступа музици, аудио и другим фајловима."</string>
+ <string name="media_confirm_dialog_message_a_to_p_visual_deny" msgid="6609500525590757681">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација не може да приступа сликама и видеима, неће јој бити дозвољено ни да приступа музици, аудио и другим фајловима."</string>
+ <string name="media_confirm_dialog_message_q_to_s_aural_allow" msgid="1702402580147536160">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација може да приступа музици и аудио фајловима, биће јој дозвољено и да приступа сликама и видеима."</string>
+ <string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација не може да приступа музици и аудио фајловима, неће јој бити дозвољено ни да приступа сликама и видеима."</string>
+ <string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација може да приступа сликама и видеима, биће јој дозвољено и да приступа музици и аудио фајловима."</string>
+ <string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ова апликација не подржава најновију верзију Android-а. Ако ова апликација не може да приступа музици и аудио фајловима, неће јој бити дозвољено ни да приступа сликама и видеима."</string>
<string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Прегледајте апликацију са приступом локацији у позадини"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> увек може да приступа вашој локацији, чак и кад је апликација затворена"</string>
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Прегледајте апликацију са приступом локацији у позадини"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Ова апликација наводи да може да дели податке са трећим странама"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Дељење података и локација"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Одакле информације о дељењу података потичу"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Програмер је навео информације произвођачу овог уређаја о томе како ова апликација дели податке. Програмер може временом да ажурира ове податке."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Програмер је навео информације о томе како ова апликација дели податке за:"<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". Програмер може временом да ажурира ове податке."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Ова апликација може да дели податке о локацији за:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Дељење података варира"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Безбедност података"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Подаци о локацији могу да се деле"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Ова апликација наводи да може да дели податке о локацији са трећим странама"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Не можемо да отворимо овај линк"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Ажурирања дељења података за локацију"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Прегледајте апликације које су промениле начин на који могу да деле податке о локацији"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Апликације су промениле начин на који могу да деле податке о локацији. Можда их нису делиле раније или их сада деле у сврхе оглашавања или маркетинга."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Ажурирања за дељење података"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Неке апликације су промениле начин на који могу да деле податке о локацији"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Подешавања"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Приступано: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Приступано јуче: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Приступано: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-sv-v33/strings.xml b/PermissionController/res/values-sv-v33/strings.xml
index cc2c40543..e661efeb0 100644
--- a/PermissionController/res/values-sv-v33/strings.xml
+++ b/PermissionController/res/values-sv-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Fler varningar"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Ignorerade varningar"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Utöka för att visa en varning till}other{Utöka för att visa # varningar till}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Varning. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Åtgärd slutförd"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Kontrollera inställningar som kan skydda enheten"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Snabbinställningar för säkerhet och integritet"</string>
diff --git a/PermissionController/res/values-sv-v34/strings.xml b/PermissionController/res/values-sv-v34/strings.xml
index aa81c12ec..09e204e2e 100644
--- a/PermissionController/res/values-sv-v34/strings.xml
+++ b/PermissionController/res/values-sv-v34/strings.xml
@@ -20,7 +20,7 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Säkerhet och integritet"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kontroller"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Hantera appens åtkomst till din hälsodata"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Hantera appars åtkomst till din hälsodata"</string>
<string name="location_settings" msgid="8863940440881290182">"Platsåtkomst"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"För appar och tjänster. Om inställningen är inaktiverad kan mikrofondata fortfarande delas när du ringer ett nödnummer"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"För appar och tjänster"</string>
diff --git a/PermissionController/res/values-sv/strings.xml b/PermissionController/res/values-sv/strings.xml
index c5039d891..b9638f39e 100644
--- a/PermissionController/res/values-sv/strings.xml
+++ b/PermissionController/res/values-sv/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Mer info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Tillåt alla"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Tillåt alltid alla"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Tillåt begränsad åtkomst"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Välj foton och videor"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Välj fler"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Välj inte fler"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Appar"</string>
<string name="app_permissions" msgid="3369917736607944781">"Appbehörigheter"</string>
<string name="unused_apps" msgid="2058057455175955094">"Appar som inte används"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Redigera urvalet av foton för appen"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Inga appar som inte används"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 appar som inte används"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Senaste behörighetsbesluten"</string>
@@ -113,9 +115,7 @@
<string name="loading" msgid="4789365003890741082">"Läser in …"</string>
<string name="all_permissions" msgid="6911125611996872522">"Alla behörigheter"</string>
<string name="other_permissions" msgid="2901186127193849594">"Andra appbehörigheter"</string>
- <string name="permission_request_title" msgid="8790310151025020126">"Begäran om behörighet"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Åtgärder för att installera/avinstallera stöds inte på Wear."</string>
+ <string name="permission_request_title" msgid="8790310151025020126">"Behörighetsbegäran"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Välj vad du vill ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; har uppdaterats. Välj vad du vill ge appen åtkomst till."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Avbryt"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Ta bort behörigheter om en app inte används"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Ta bort behörigheter och frigör utrymme"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Pausa appaktivitet om appen inte används"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Hantera appen om den är oanvänd"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Ta bort behörigheter, radera tillfälliga filer och hindra aviseringar"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Ta bort behörigheter, radera tillfälliga filer, hindra aviseringar och arkivera appen"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Behörigheter tas bort av säkerhetsskäl från den här appen om den inte används på några månader."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Följande behörigheter tas bort av säkerhetsskäl från appen om den inte används på några månader: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Behörigheter har tagits bort av säkerhetsskäl från appar som inte har använts på några månader."</string>
@@ -399,8 +401,18 @@
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Den här tjänsten delar dina foton, videor och aviseringar på telefonen med andra enheter."</string>
<string name="role_notes_label" msgid="7451627001058089536">"Standardapp för anteckningar"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"Anteckningsapp"</string>
- <string name="role_notes_description" msgid="8496852798616883551">"Appar som låter dig ta anteckningar på enheten"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"Appar som låter dig göra anteckningar på enheten"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"anteckningar"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Nuvarande standardapp"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Fråga inte igen"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Ange som standard"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Visa när enheten lyssnar efter ord som aktiverar assistenten"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Visa en ikon i statusfältet när mikrofonen används för att aktivera röstassistenten"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomstbehörighet till foton och media på enheten?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till foton och media på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till dina kontakter?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till kontakter på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till enhetens plats?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till platsen för &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Appen får endast åtkomst till din plats när du använder den"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till enhetens plats?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till platsen för &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Appen kanske vill få åtkomst till din plats hela tiden, även när du inte använder den. "<annotation id="link">"Tillåt i inställningarna."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Vill du ändra platsåtkomsten för &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Vill du ändra platsåtkomsten för &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Appen vill få åtkomst till din plats hela tiden, även när du inte använder den. "<annotation id="link">"Tillåt i inställningarna."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Vill du tillåta att &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kan hitta, ansluta till och fastställa relativ position för enheter i närheten?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Tillåt &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; att hitta, ansluta till och avgöra relativ plats för enheter i närheten på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Vill du tillåta att &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kan hitta, ansluta till och fastställa relativ position för enheter i närheten? "<annotation id="link">"Tillåt i inställningarna."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Vill du ändra platsåtkomsten för <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> från ungefärlig till exakt?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Vill du ändra <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>s platsåtkomst på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; från ungefärlig till exakt?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till enhetens ungefärliga plats?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till den ungefärliga platsen för &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Exakt"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Ungefärlig"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till din kalender?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till kalendern på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att skicka och visa sms?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att skicka och visa sms på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till foton, mediefiler och andra filer på enheten?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till foton, media och filer på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till &lt;b&gt;foton, videor, musik och ljud&lt;/b&gt; på enheten?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till &lt;b&gt;foton, videor, musik, ljud och andra filer&lt;/b&gt; på enheten?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till musik och ljud på enheten?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till musik och ljud på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till foton och videor på enheten?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till foton och videor på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till fler foton och videor på enheten?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till fler foton och videor på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att spela in ljud?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att spela in ljud på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Appen kan bara spela in ljud medan du använder den"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att spela in ljud?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att spela in ljud på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Appen kanske vill spela in ljud hela tiden, även när du inte använder appen. "<annotation id="link">"Tillåt i inställningarna."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Vill du ändra mikrofonåtkomsten för &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Vill du ändra mikrofonåtkomsten för &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Appen vill ha behörighet att spela in ljud hela tiden, även när du inte använder appen. "<annotation id="link">"Tillåt i inställningarna."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till data om fysisk aktivitet?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till din fysiska aktivitet på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att ta bilder och spela in video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att ta bilder och spela in video på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Appen kan bara ta bilder och spela in video medan du använder den"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att ta bilder och spela in video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att ta bilder och spela in video på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Appen kanske vill ta bilder och spela in videor hela tiden, även när du inte använder appen. "<annotation id="link">"Tillåt i inställningarna."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Vill du ändra kameraåtkomsten för &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Vill du ändra kameraåtkomsten för &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Appen vill ha behörighet att ta bilder och spela in videor hela tiden, även när du inte använder appen. "<annotation id="link">"Tillåt i inställningarna."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till samtalsloggarna?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till dina samtalsloggar på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att ringa och hantera telefonsamtal?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att ringa och hantera telefonsamtal på&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till sensordata om vitalparametrar?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till sensordata om dina vitalparametrar på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Appen vill ha åtkomst till sensordata om vitalparametrar hela tiden, även när du inte använder den. "<annotation id="link">"Öppna inställningarna"</annotation>" om du vill tillåta detta."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomstbehörighet till sensordata om vitalparametrar?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till sensordata om dina vitalparametrar på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501"><annotation id="link">"Öppna inställningarna"</annotation>" om du vill ge appen åtkomst till data från kroppssensorer hela tiden, även när du inte använder appen."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Ska &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ha åtkomst till data från kroppssensorer medan appen används även i fortsättningen?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Vill du fortsätta ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; åtkomst till kroppssensorsdata på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; medan appen används?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att skicka aviseringar?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Vill du ge &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; behörighet att skicka aviseringar på &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Styrda behörigheter"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> har platsåtkomst"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Din organisation tillåter att <xliff:g id="APP_NAME">%1$s</xliff:g> får åtkomst till din plats"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Andra behörigheter"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Behörighet som används av systemet"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Behörigheter som bara används av systemappar."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Appen har angett att den kan dela platsdata med tredje part"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Datadelning och plats"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Härifrån kommer informationen om datadelning"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Utvecklaren har gett enhetens tillverkare information om hur appen delar data. Utvecklaren kan uppdatera den här informationen med tiden."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Utvecklaren har angett information om hur appen delar data i "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>". Utvecklaren kan uppdatera den här informationen med tiden."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Appen kan dela platsdata för följande:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Datadelningen varierar"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Datasäkerhet"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Platsdata kan delas"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Appen har angett att den kan dela din platsdata med tredje part"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Det gick inte att öppna den här länken"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Uppdatering av datadelning för plats"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Granska appar som har ändrat hur de kan dela din platsdata"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Dessa appar har ändrat hur de kan dela din platsdata. De kanske inte har delat datan tidigare eller så delas den nu i annons- och marknadsföringssyfte."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Uppdateringar av datadelning"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"En del appar har ändrat hur de kan dela din platsdata"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Inställningar"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Öppnades <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Öppnades i går <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Öppnades <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-sw-v33/strings.xml b/PermissionController/res/values-sw-v33/strings.xml
index 818d596a4..db02c110b 100644
--- a/PermissionController/res/values-sw-v33/strings.xml
+++ b/PermissionController/res/values-sw-v33/strings.xml
@@ -19,7 +19,7 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Programu hii itaruhusiwa kukutumia Arifa na itapewa uwezo wa kufikia Kamera, Anwani, Maikrofoni, Simu na SMS kwenye kifaa chako"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Programu hii itaruhusiwa kukutumia Arifa na itapewa uwezo wa kufikia Kamera, Anwani, Faili, Maikrofoni, Simu na SMS kwenye kifaa chako"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Programu zenye ruhusa hii zinaweza kufikia faili zote kwenye kifaa hiki"</string>
- <string name="work_policy_title" msgid="832967780713677409">"Maelezo ya sera yako ya kazini"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Maelezo ya sera ya kazini"</string>
<string name="work_policy_summary" msgid="3886113358084963931">"Mipangilio inayodhibitiwa na msimamizi wako wa TEHAMA"</string>
<string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Panua na uonyeshe orodha"</string>
<string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Kunja orodha na ufiche mipangilio"</string>
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Arifa zaidi"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Arifa zilizoondolewa"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Panua na uangalie arifa moja zaidi}other{Panua na uangalie arifa # zaidi}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Tahadhari. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Kitendo kimekamilika"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Angalia mipangilio inayoweza kuongeza usalama wa kifaa chako"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Mipangilio ya haraka ya usalama na faragha"</string>
diff --git a/PermissionController/res/values-sw-v34/strings.xml b/PermissionController/res/values-sw-v34/strings.xml
index c4107efea..52a1c7ceb 100644
--- a/PermissionController/res/values-sw-v34/strings.xml
+++ b/PermissionController/res/values-sw-v34/strings.xml
@@ -20,8 +20,8 @@
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Usalama na faragha"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Vidhibiti"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Kudhibiti uwezo wa programu wa kufikia data ya afya"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Dhibiti uwezo wa programu wa kufikia data ya afya"</string>
<string name="location_settings" msgid="8863940440881290182">"Uwezo wa kufikia mahali"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Kwenye programu na huduma. Mipangilio hii ikizimwa, huenda data ya maikrofoni ikaendelea kushirikiwa unapopiga nambari ya dharura"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Kwenye programu na huduma. Mipangilio hii ikizimwa, data ya maikrofoni bado inaweza ikashirikiwa unapopiga namba ya dharura"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Kwenye programu na huduma"</string>
</resources>
diff --git a/PermissionController/res/values-sw/strings.xml b/PermissionController/res/values-sw/strings.xml
index ded75a6e1..ae35dbdc6 100644
--- a/PermissionController/res/values-sw/strings.xml
+++ b/PermissionController/res/values-sw/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Maelezo zaidi"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Ruhusu zote"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Ruhusu zote kila wakati"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Ruhusu kufikia baadhi ya vipengele"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Chagua picha na video"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Chagua zaidi"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Usichague zaidi"</string>
@@ -60,12 +61,13 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Programu"</string>
<string name="app_permissions" msgid="3369917736607944781">"Ruhusa za programu"</string>
<string name="unused_apps" msgid="2058057455175955094">"Programu zisizotumika"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Badilisha picha ulizochagua za programu hii"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Hakuna programu zisizotumika"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Hakuna programu zisizotumika"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Uamuzi wa ruhusa wa hivi majuzi"</string>
<string name="review_permission_decisions_view_all" msgid="90391040431566130">"Angalia uamuzi wa ruhusa zote za hivi majuzi"</string>
<string name="review_permission_decisions_empty" msgid="8120775336417279806">"Hakuna uamuzi wa ruhusa wa hivi majuzi"</string>
- <string name="auto_permission_manager_summary" msgid="9157438376234301354">"Dhibiti ufikiaji wa data kwenye kalenda, rekodi za nambari za simu na zaidi"</string>
+ <string name="auto_permission_manager_summary" msgid="9157438376234301354">"Dhibiti ufikiaji wa data kwenye kalenda, rekodi za namba za simu na zaidi"</string>
<string name="granted_permission_decision" msgid="7824827491551861365">"Umeipa <xliff:g id="APP_NAME">%1$s</xliff:g> ruhusa ya kufikia <xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
<string name="denied_permission_decision" msgid="5308961501779563781">"Umeinyima <xliff:g id="APP_NAME">%1$s</xliff:g> ruhusa ya kufikia <xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{Leo}=1{Siku moja iliyopita}other{Siku # zilizopita}}"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Ruhusa zote"</string>
<string name="other_permissions" msgid="2901186127193849594">"Uwezo mwingine wa programu"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Ombi la idhini"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Huduma ya Android Wear haiwezi kutekeleza vitendo vya Kusakinisha au Kuondoa vipengee."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Chagua vipengee ambavyo unaruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; imesasishwa. Chagua vipengee unavyoruhusu programu hii ifikie."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Ghairi"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Ondoa ruhusa ikiwa programu haitumiki"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Ondoa ruhusa na upate nafasi"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Simamisha shughuli kwenye programu ikiwa haitumiki"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Dhibiti programu iwapo haitumiki"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Ondoa ruhusa, futa faili za muda na usitishe arifa"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Ondoa ruhusa, futa faili za muda, komesha arifa na uweke programu kwenye kumbukumbu"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Ili kulinda data yako, ruhusa za programu hii zitaondolewa programu isipotumika kwa miezi michache."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Ili kulinda data yako, programu isipotumika kwa miezi michache, ruhusa zifuatazo zitaondolewa: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Ili kulinda data yako, ruhusa zimeondolewa kwenye programu ambazo hujatumia kwa miezi michache."</string>
@@ -221,7 +223,7 @@
<string name="unused_apps_page_title" msgid="6986983535677572559">"Programu zisizotumika"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Programu isipotumika kwa miezi kadhaa:\n\n• Ruhusa huondolewa ili kulinda data yako \n• Arifa husimamishwa ili kuokoa betri\n• Faili za muda huondolewa ili upate nafasi\n\nIli uidhinishe ruhusa na arifa tena, fungua programu."</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Programu isipotumika kwa mwezi mmoja:\n\n• Ruhusa huondolewa ili kulinda data yako\n• Faili za muda huondolewa ili upate nafasi\n\nIli uidhinishe ruhusa tena, fungua programu."</string>
- <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Zilifunguliwa mara ya mwisho zaidi ya mwezi # uliopita}other{Zilifunguliwa mara ya mwisho zaidi ya miezi # iliyopita}}"</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Zilifunguliwa mwisho zaidi ya mwezi # uliopita}other{Zilifunguliwa mwisho zaidi ya miezi # iliyopita}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Ilifunguliwa mara ya mwisho tarehe <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Ilifunguliwa mara ya mwisho <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ukiruhusu udhibiti wa faili zote, programu hii inaweza kufikia, kubadilisha na kufuta faili zozote zilizo katika hifadhi kwenye kifaa hiki au vifaa vilivyounganishwa vya kuhifadhi. Programu inaweza kufikia faili bila kukuomba ruhusa."</string>
@@ -347,8 +349,8 @@
<string name="accessibility_service_dialog_title_multiple" msgid="5527879210683548175">"Programu <xliff:g id="NUM_SERVICES">%s</xliff:g> za ufikivu zina idhini kamili ya kufikia kifaa chako"</string>
<string name="accessibility_service_dialog_bottom_text_single" msgid="1128666197822205958">"<xliff:g id="SERVICE_NAME">%s</xliff:g> inaweza kuona skrini, vitendo na maudhui unayoweka, kutekeleza vitendo na kudhibiti onyesho."</string>
<string name="accessibility_service_dialog_bottom_text_multiple" msgid="7009848932395519852">"Programu hizi zinaweza kuona skrini, vitendo na maudhui unayoweka, kutekeleza vitendo na kudhibiti onyesho."</string>
- <string name="role_assistant_label" msgid="4727586018198208128">"Programu msingi dijitali ya usaidizi"</string>
- <string name="role_assistant_short_label" msgid="3369003713187703399">"Programu dijitali ya usaidizi"</string>
+ <string name="role_assistant_label" msgid="4727586018198208128">"Programu msingi ya usaidizi wa kidijitali"</string>
+ <string name="role_assistant_short_label" msgid="3369003713187703399">"Programu saidizi ya kidijitali"</string>
<string name="role_assistant_description" msgid="6622458130459922952">"Programu za usaidizi zinaweza kukusaidia kulingana na maelezo kutoka skrini unayotazama. Baadhi ya programu zinaweza kutumia huduma za kifungua programu na kuweka data kwa kutamka ili kukupa usaidizi wa pamoja."</string>
<string name="role_browser_label" msgid="2877796144554070207">"Programu kuu ya kivinjari"</string>
<string name="role_browser_short_label" msgid="6745009127123292296">"Programu ya kivinjari"</string>
@@ -363,7 +365,7 @@
<string name="role_dialer_search_keywords" msgid="3324448983559188087">"kipiga simu"</string>
<string name="role_sms_label" msgid="8456999857547686640">"Programu chaguomsingi ya SMS"</string>
<string name="role_sms_short_label" msgid="4371444488034692243">"Programu ya SMS"</string>
- <string name="role_sms_description" msgid="3424020199148153513">"Programu zinazokuruhusu kutumia nambari yako ya simu kutuma na kupokea ujumbe mfupi, picha, video na zaidi"</string>
+ <string name="role_sms_description" msgid="3424020199148153513">"Programu zinazokuruhusu kutumia namba yako ya simu kutuma na kupokea ujumbe mfupi, picha, video na zaidi"</string>
<string name="role_sms_request_title" msgid="7953552109601185602">"Ungependa kuweka <xliff:g id="APP_NAME">%1$s</xliff:g> iwe programu yako chaguomsingi ya SMS?"</string>
<string name="role_sms_request_description" msgid="2691004766132144886">"Programu hii itapewa uwezo wa kufikia Kamera, Anwani, Faili na maudhui, Maikrofoni, Simu na SMS kwenye kifaa chako"</string>
<string name="role_sms_search_keywords" msgid="8022048144395047352">"SMS, kutuma SMS, ujumbe, kutuma ujumbe"</string>
@@ -381,12 +383,12 @@
<string name="role_home_search_keywords" msgid="3830755001192666285">"kifungua programu"</string>
<string name="role_call_redirection_label" msgid="5785304207206147590">"Programu chaguomsingi ya kuelekeza simu kwingine"</string>
<string name="role_call_redirection_short_label" msgid="7568143419571217757">"Programu ya kuelekeza simu"</string>
- <string name="role_call_redirection_description" msgid="6091669882014664420">"Programu zinazokuruhusu usambaze simu unazopiga kwenye nambari nyingine ya simu"</string>
+ <string name="role_call_redirection_description" msgid="6091669882014664420">"Programu zinazokuruhusu usambaze simu unazopiga kwenye namba nyingine ya simu"</string>
<string name="role_call_redirection_request_title" msgid="2816244455003562925">"Je, ungependa kuweka <xliff:g id="APP_NAME">%1$s</xliff:g> iwe programu yako chaguomsingi ya kuelekeza simu kwingine?"</string>
<string name="role_call_redirection_request_description" msgid="3118895714178527164">"Hakuna ruhusa zinazohitajika"</string>
<string name="role_call_screening_label" msgid="883935222060878724">"Kutambua taka na anayepiga: programu msingi"</string>
<string name="role_call_screening_short_label" msgid="2048465565063130834">"Kutambua anayepiga na taka"</string>
- <string name="role_call_screening_description" msgid="2349431420497468981">"Programu zinazokuruhusu utambue simu zinazoingia na kuzuia taka, simu zinazopigwa kiotomatiki au nambari zisizohitajika"</string>
+ <string name="role_call_screening_description" msgid="2349431420497468981">"Programu zinazokuruhusu utambue simu zinazoingia na kuzuia taka, simu zinazopigwa kiotomatiki au namba zisizohitajika"</string>
<string name="role_call_screening_request_title" msgid="7358309224566977290">"Je, ungependa kuweka <xliff:g id="APP_NAME">%1$s</xliff:g> iwe programu chaguomsingi ya kukagua kitambulisho cha anayepiga na taka?"</string>
<string name="role_call_screening_request_description" msgid="7338511921032446006">"Hakuna ruhusa zinazohitajika"</string>
<string name="role_automotive_navigation_label" msgid="2701890757955474751">"Programu chaguomsingi ya maelekezo"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Programu ya madokezo"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Programu zinazokuruhusu uandike madokezo kwenye kifaa chako"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"madokezo"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Chaguomsingi ya sasa"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Isiniulize tena"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Weka iwe chaguomsingi"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Onyesha utambuzi wa kuwashwa/kuzimwa kwa mratibu"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Onyesha aikoni kwenye sehemu ya kuonyesha hali wakati maikrofoni inatumika kuwasha kipengele cha maagizo ya sauti"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha na maudhui kwenye kifaa chako?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha na maudhui kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie anwani zako?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie anwani zako kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie mahali kilipo kifaa hiki?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie maelezo ya mahali ya &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Programu itafikia data ya mahali ulipo unapoitumia tu"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie mahali kilipo kifaa hiki?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie maelezo ya mahali ya &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> yako?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Huenda programu hii ikataka kufikia maelezo ya mahali ulipo kila wakati, hata wakati huitumii."<annotation id="link">"Iruhusu katika mipangilio."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Ungependa kubadilisha ruhusa za &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; za kufikia maelezo ya mahali?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Ungependa kubadilisha idhini ya kufikia maelezo ya mahali ya &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Programu hii inataka kufikia maelezo ya mahali ulipo kila wakati, hata wakati huitumii."<annotation id="link">"Iruhusu katika mipangilio."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; itafute, iunganishe kwenye na ibaini mahali vilipo vifaa vilivyo karibu?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; itafute, iunganishe na kubaini nafasi ya makadirio ya vifaa vilivyo karibu kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; itafute, iunganishe kwenye na ibaini mahali vilipo vifaa vilivyo karibu? "<annotation id="link">"Ruhusu katika mipangilio."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Ungependa kubadilisha ufikiaji wa maelezo ya mahali kwenye <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> kutoka eneo lililokadiriwa utumie eneo mahususi?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Ungependa kubadilisha ufikiaji wa maelezo ya mahali ya <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako kutoka makadirio kuwa mahususi?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie mahali palipokadiriwa kilipo kifaa hiki?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie maelezo ya mahali pa kukadiria pa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Mahususi"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Palipokadiriwa"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie kalenda yako?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie kalenda yako kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; itume na ione ujumbe wa SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; itume na kuona ujumbe wa SMS kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Ungependa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha, maudhui na faili kwenye kifaa chako?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha, maudhui na faili kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie &lt;b&gt;picha, video, muziki na sauti&lt;/b&gt; kwenye kifaa hiki?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie &lt;b&gt;picha, video, muziki, sauti na faili zingine&lt;/b&gt; kwenye kifaa hiki?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie muziki na sauti kwenye kifaa hiki?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie muziki na sauti kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha na video kwenye kifaa hiki?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha na video kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha na video zaidi kwenye kifaa hiki?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha na video zaidi kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kurekodi sauti?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; irekodi sauti kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Programu itaweza kurekodi sauti unapoitumia tu"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; irekodi sauti?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; irekodi sauti kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Huenda programu hii ikataka kurekodi sauti kila wakati, hata wakati huitumii."<annotation id="link">"Ruhusu katika mipangilio."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Ungependa kubadilisha ruhusa za &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; za kufikia maikrofoni?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Ungependa kubadilisha idhini ya maikrofoni ya &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Programu hii inataka kurekodi sauti kila wakati, hata wakati huitumii."<annotation id="link">"Ruhusu katika mipangilio."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie shughuli zako za kimwili?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie shughuli yako ya mazoezi ya mwili kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kupiga picha na kurekodi video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ipige picha na kurekodi video kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Programu itaweza kupiga picha na kurekodi video unapoitumia tu"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ipige picha na kurekodi video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ipige picha na kurekodi video kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Huenda programu hii ikataka kupiga picha na kurekodi video kila wakati, hata wakati huitumii."<annotation id="link">"Ruhusu katika mipangilio."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Ungependa kubadilisha ruhusa za &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; za kufikia kamera?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Ungependa kubadilisha idhini ya kufikia ya kamera ya &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Programu hii inataka kupiga picha na kurekodi video kila wakati, hata wakati huitumii."<annotation id="link">"Ruhusu katika mipangilio."</annotation></string>
- <string name="permgrouprequest_calllog" msgid="2065327180175371397">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie rekodi zako za nambari za simu?"</string>
+ <string name="permgrouprequest_calllog" msgid="2065327180175371397">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie rekodi zako za namba za simu?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie rekodi za namba za simu yako kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; kupiga na kudhibiti simu?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ipige na kudhibiti simu kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie data ya vitambuzi kuhusu viashiria muhimu vya mwili wako?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie data ya vitambuzi inayohusu viashiria muhimu vya mwili wako kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Programu hii inataka kufikia data ya vitambuzi ya viashiria muhimu vya mwili wako kila wakati, hata wakati huitumii. Ili ufanye mabadiliko haya, "<annotation id="link">"nenda kwenye mipangilio."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie data ya vitambuzi inayohusu viashiria muhimu vya mwili wako?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie data ya vitambuzi inayohusu viashiria muhimu vya mwili wako kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Ili uruhusu programu hii ifikie data ya vitambuzi vya shughuli za mwili kila wakati, hata wakati hutumii programu, "<annotation id="link">"nenda kwenye mipangilio."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Ungependa kuendelea kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie data ya vitambuzi vya shughuli za mwili wakati programu inatumika?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Ungependa kuendelea kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie data ya vitambuzi shughuli za mwili kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako wakatii programu inatumika?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Ungependa kuruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ikutumie arifa?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ikutumie arifa kwenye &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yako?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Ruhusa zinazodhibitiwa"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ina idhini ya kufikia maelezo ya mahali kilipo kifaa"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Shirika lako limeruhusu <xliff:g id="APP_NAME">%1$s</xliff:g> kufikia maelezo ya mahali kilipo kifaa chako"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Ruhusa nyinginezo"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Ruhusa zinazotumiwa na mfumo"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Ruhusa zinazotumiwa tu na programu za mfumo."</string>
@@ -520,7 +557,7 @@
<string name="blocked_microphone_title" msgid="1631517143648232585">"Maikrofoni ya kifaa imezuiwa"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"Utambuzi wa mahali kifaa kilipo umezimwa"</string>
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Kwa ajili ya programu na huduma"</string>
- <string name="blocked_mic_summary" msgid="8960466941528458347">"Huenda bado data ya maikrofoni ikashirikiwa unapopigia nambari ya dharura."</string>
+ <string name="blocked_mic_summary" msgid="8960466941528458347">"Huenda bado data ya maikrofoni ikashirikiwa unapopigia namba ya dharura."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Badilisha"</string>
<string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Usalama na faragha"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"Kagua kifaa"</string>
@@ -572,9 +609,9 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Programu hii haiwezi kutumia toleo jipya zaidi la Android. Iwapo programu hii haitaweza kufikia faili za muziki na sauti, haitaruhusiwa pia kufikia picha na video."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Programu hii haiwezi kutumia toleo jipya zaidi la Android. Iwapo programu hii itaweza kufikia picha na video, itaruhusiwa pia kufikia muziki na faili za sauti."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Programu hii haiwezi kutumia toleo jipya zaidi la Android. Iwapo programu hii haitaweza kufikia faili za muziki na sauti, haitaruhusiwa pia kufikia picha na video."</string>
- <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Kagua programu yenye ufikiaji wa ruhusa ya kubainisha mahali chinichini"</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Kagua programu yenye ufikiaji wa mahali chinichini"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> inaweza kufikia mahali ulipo kila wakati, hata kama programu imefungwa"</string>
- <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Kagua programu yenye ufikiaji wa ruhusa ya kubainisha mahali chinichini"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Kagua programu yenye ufikiaji wa mahali chinichini"</string>
<string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Programu hii inaweza kufikia data ya mahali ulipo kila wakati, hata kama imefungwa.\n\nBaadhi ya programu za usalama na dharura zinahitaji ufikiaji wa data ya mahali ulipo chinichini ili kufanya kazi ipasavyo."</string>
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Ruhusa ya ufikiaji imebadilishwa"</string>
<string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Angalia matumizi ya hivi karibuni ya maelezo ya mahali"</string>
@@ -582,7 +619,7 @@
<string name="camera_toggle_title" msgid="1251201397431837666">"Ufikiaji wa kamera"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Ufikiaji wa maikrofoni"</string>
<string name="perm_toggle_description" msgid="7801326363741451379">"Kwenye programu na huduma"</string>
- <string name="mic_toggle_description" msgid="9163104307990677157">"Kwenye programu na huduma. Mipangilio hii ikizimwa, huenda data ya maikrofoni ikaendelea kushirikiwa unapopiga nambari ya dharura."</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Kwenye programu na huduma. Mipangilio hii ikizimwa, huenda data ya maikrofoni ikaendelea kushirikiwa unapopiga namba ya dharura."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Angalia huduma na programu zenye uwezo wa kufikia mipangilio ya mahali"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Onyesha ufikiaji wa ubao wa kunakili"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Onyesha ujumbe programu zinapofikia maandishi, picha au maudhui mengine uliyonakili"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Maelezo ya programu yanasema kuwa inaweza kushiriki data na kampuni za wengine"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Kushiriki data na mahali"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Maelezo ya kushiriki data yanakotokea"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Msanidi programu ametoa maelezo kwa mtengenezaji wa kifaa hiki kuhusu jinsi programu hii inavyoshiriki data. Msanidi programu anaweza kusasisha maelezo haya kadiri muda unavyosonga."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Wasanidi programu wametoa maelezo kwenye "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" kuhusu jinsi programu hii inavyoshiriki data. Msanidi programu anaweza kusasisha maelezo haya kadiri muda unavyosonga."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Programu hii inaweza kushiriki data ya mahali ili:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Kanuni za kushiriki data hutofautiana"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Usalama wa data"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Data ya mahali inaweza kushirikiwa"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Programu hii ilitaja kuwa inaweza kushiriki data yako ya mahali na washirika wengine"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Huwezi kufungua kiungo hiki"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Masasisho ya kushiriki data ya mahali"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Kagua programu zilizobadilisha jinsi zinavyoweza kushiriki data ya mahali ulipo"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Programu hizi zimebadilisha jinsi zinavyoweza kushiriki data ya mahali ulipo. Huenda zilikuwa haziishiriki hapo awali au sasa zinaweza kuishiriki kwa madhumuni ya utangazaji au uuzaji."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Masasisho ya kushiriki data"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Baadhi ya programu zimebadilisha jinsi zinavyoweza kushiriki data ya mahali ulipo"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Mipangilio"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Kilifunguliwa <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Kilifunguliwa jana <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Kilifunguliwa <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-ta-v33/strings.xml b/PermissionController/res/values-ta-v33/strings.xml
index cdb8a15f5..41b6d0923 100644
--- a/PermissionController/res/values-ta-v33/strings.xml
+++ b/PermissionController/res/values-ta-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"கூடுதல் விழிப்பூட்டல்கள்"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"நிராகரிக்கப்பட்ட விழிப்பூட்டல்கள்"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{விரிவாக்கி மேலும் ஒரு விழிப்பூட்டலைப் பாருங்கள்}other{விரிவாக்கி மேலும் # விழிப்பூட்டல்களைப் பாருங்கள்}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"விழிப்பூட்டும். <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"செயல் நிறைவடைந்தது"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"உங்கள் சாதனத்திற்குப் பாதுகாப்பைச் சேர்க்கக்கூடிய அமைப்புகளைப் பாருங்கள்"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"பாதுகாப்பு &amp; தனியுரிமை விரைவு அமைப்புகள்"</string>
diff --git a/PermissionController/res/values-ta/strings.xml b/PermissionController/res/values-ta/strings.xml
index d62e0d481..fee1404ac 100644
--- a/PermissionController/res/values-ta/strings.xml
+++ b/PermissionController/res/values-ta/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"மேலும் தகவல்"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"அனைத்தையும் அனுமதி"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"எப்போதும் அனைத்தையும் அனுமதி"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"வரம்பிற்குட்பட்ட அணுகலை அனுமதி"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"படங்களையும் வீடியோக்களையும் தேர்ந்தெடுங்கள்"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"இன்னும் தேர்ந்தெடுங்கள்"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"கூடுதலாகத் தேர்ந்தெடுக்க வேண்டாம்"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ஆப்ஸ்"</string>
<string name="app_permissions" msgid="3369917736607944781">"ஆப்ஸ் அனுமதிகள்"</string>
<string name="unused_apps" msgid="2058057455175955094">"பயன்படுத்தாத ஆப்ஸ்"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"இந்த ஆப்ஸுக்கெனத் தேர்ந்தெடுத்த படங்களை மாற்றுங்கள்"</string>
<string name="no_unused_apps" msgid="12809387670415295">"பயன்படுத்தாத ஆப்ஸ் எதுவுமில்லை"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 பயன்படுத்தாத ஆப்ஸ்"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"அனுமதி தொடர்பான முடிவுகள்"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"அனைத்து அனுமதிகளும்"</string>
<string name="other_permissions" msgid="2901186127193849594">"ஆப்ஸிற்கான பிற அனுமதிகள்"</string>
<string name="permission_request_title" msgid="8790310151025020126">"அனுமதி கோரிக்கை"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"நிறுவல்/நிறுவல் நீக்குதலை Wearரில் செய்ய இயலாது."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; எவற்றையெல்லாம் அணுகலாம் என்பதைத் தேர்வுசெய்யவும்"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; புதுப்பிக்கப்பட்டது. இந்த ஆப்ஸ் எவற்றையெல்லாம் அணுகலாம் என்பதைத் தேர்வுசெய்யவும்."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"வேண்டாம்"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"இந்த ஆப்ஸ் பயன்படுத்தப்படவில்லை என்றால் அனுமதிகளை அகற்றவும்"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"அனுமதிகளை அகற்றி இடத்தைக் காலியாக்கு"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"செயலில் இல்லாதபோது ஆப்ஸை இடைநிறுத்துதல்"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"ஆப்ஸைப் பயன்படுத்தாதபோது நிர்வகித்தல்"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"அனுமதிகளை அகற்றும், தற்காலிக ஃபைல்களை நீக்கும், அறிவிப்புகளை நிறுத்தும்"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"அனுமதிகளை அகற்றும், தற்காலிக ஃபைல்களை நீக்கும், அறிவிப்புகளை நிறுத்தும், ஆப்ஸைக் காப்பிடும்"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"இந்த ஆப்ஸைச் சில மாதங்கள் பயன்படுத்தவில்லை என்றால் உங்கள் தரவைப் பாதுகாப்பதற்காக இதற்கான அனுமதிகள் அகற்றப்படும்."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"இந்த ஆப்ஸைச் சில மாதங்கள் பயன்படுத்தவில்லை என்றால் உங்கள் தரவைப் பாதுகாப்பதற்காக பின்வரும் அனுமதிகள் அகற்றப்படும்: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"உங்கள் தரவைப் பாதுகாப்பதற்காக, கடந்த சில மாதங்களில் நீங்கள் பயன்படுத்தாத ஆப்ஸில் இருந்து அனுமதிகள் அகற்றப்பட்டன."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"கடைசியாகத் திறந்தது: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"அனைத்து ஃபைல்களையும் நிர்வகிப்பதற்கு அனுமதி வழங்கினால் இந்தச் சாதனத்தின் பொதுவான சேமிப்பகத்திலோ இணைக்கப்பட்டுள்ள சேமிப்பகச் சாதனங்களிலோ உள்ள ஃபைல்களை அணுகவும் நீக்கவும் அவற்றில் மாற்றங்களைச் செய்யவும் இந்த ஆப்ஸால் முடியும். உங்களிடம் கேட்காமலேயே ஃபைல்களை ஆப்ஸ் அணுகக்கூடும்."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"இந்தச் சாதனத்திலோ இணைக்கப்பட்டுள்ள சேமிப்பகச் சாதனங்களிலோ உள்ள ஃபைல்களை அணுகவும் நீக்கவும் அவற்றில் மாற்றங்களைச் செய்யவும் இந்த ஆப்ஸை அனுமதிக்கவா? உங்களிடம் கேட்காமலேயே ஃபைல்களை இந்த ஆப்ஸ் அணுகக்கூடும்."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"இந்த அனுமதியைக் கொண்டுள்ள ஆப்ஸானது <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"இந்த அனுமதியைக் கொண்டுள்ள ஆப்ஸால் இதைச் செய்ய முடியும்: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"இந்த அனுமதியைக் கொண்டுள்ள ஆப்ஸால் நடத்தல், சைக்கிள் ஓட்டுதல், வாகனம் ஓட்டுதல், படிகளில் ஏறி இறங்குதல் மற்றும் பல உடல்ரீதியான செயல்பாடுகளை அணுக இயலும்"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"இந்த அனுமதியைக் கொண்டுள்ள ஆப்ஸால் உங்கள் கேலெண்டரை அணுக இயலும்"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"இந்த அனுமதியைக் கொண்டுள்ள ஆப்ஸ் மொபைல் அழைப்புப் பதிவைப் படிக்கும், எழுதும்"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"குறிப்பு எடுப்பதற்கான ஆப்ஸ்"</string>
<string name="role_notes_description" msgid="8496852798616883551">"உங்கள் சாதனத்தில் குறிப்புகள் எடுக்க அனுமதிக்கும் ஆப்ஸ்"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"குறிப்புகள்"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"தற்போதைய இயல்பான ஆப்ஸ்"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"மீண்டும் கேட்காதே"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"இயல்பு ஆப்ஸாக அமை"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"அசிஸ்டண்ட் இயக்கப்படுவதைக் கண்டறியும் ஐகானைக் காட்டு"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"குரல் உதவியை இயக்க மைக்ரோஃபோனைப் பயன்படுத்தும்போது நிலைப் பட்டியில் ஐகானைக் காட்டு"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"இந்தச் சாதனத்திலுள்ள படங்களையும் மீடியாவையும் அணுகுவதற்கு &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_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="2270563860206654757">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_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="6641436550953715107">"உங்கள் &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="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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> சாதனத்தின் இருப்பிடத்தை அணுக &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"இந்த ஆப்ஸை நீங்கள் பயன்படுத்தாதபோதும்கூட உங்கள் இருப்பிடத்தை எந்நேரமும் அணுக இது விரும்பக்கூடும். "<annotation id="link">"அமைப்புகளில் அனுமதிக்கவும்"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸிற்கு இருப்பிட அணுகலை மாற்றவா?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"இந்த ஆப்ஸை நீங்கள் பயன்படுத்தாதபோதும்கூட உங்கள் இருப்பிடத்தை எந்நேரமும் அணுக இது விரும்பக்கூடும். "<annotation id="link">"அமைப்புகளில் அனுமதிக்கவும்"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"அருகிலுள்ள சாதனங்களைக் கண்டறியவும் அவற்றுடன் இணையவும் அவற்றின் தூரத்தைத் தீர்மானிக்கவும் &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"அருகிலுள்ள சாதனங்களைக் கண்டறியவும் அவற்றுடன் இணையவும் அவற்றின் தூரத்தைத் தீர்மானிக்கவும் &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா? "<annotation id="link">"அமைப்புகளில் அனுமதி."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ஆப்ஸின் இருப்பிட அணுகலைத் தோராயத்திலிருந்து துல்லியத்திற்கு மாற்றவா?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; சாதனத்தில் <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ஆப்ஸின் இருப்பிட அணுகலைத் தோராயமானதிலிருந்து துல்லியமானதாக மாற்றவா?"</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="9001956706241104626">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_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="3103987548035171850">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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">"மெசேஜ்களை அனுப்பவும், பார்க்கவும் &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_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="872629037299467086">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_storage_q_to_s" msgid="8213701872983685505">"சாதனத்திலுள்ள &lt;b&gt;படங்கள், வீடியோக்கள், இசை &amp; ஆடியோவுக்கான&lt;/b&gt; அணுகலை &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸுக்கு வழங்கவா?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"சாதனத்திலுள்ள &lt;b&gt;படம், வீடியோ, இசை, ஆடியோ &amp; பிற ஃபைல்களின்&lt;/b&gt; அணுகலை &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸுக்கு வழங்கவா?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"இந்தச் சாதனத்திலுள்ள இசை மற்றும் ஆடியோவுக்கான அணுகலை &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸுக்கு வழங்கவா?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_read_media_visual" msgid="5548780620779729975">"இந்தச் சாதனத்திலுள்ள படங்கள் மற்றும் வீடியோக்களுக்கான அணுகலை &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸுக்கு வழங்கவா?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_more_photos" msgid="128933814654231321">"இந்தச் சாதனத்திலுள்ள கூடுதல் படங்கள் மற்றும் வீடியோக்களுக்கான அணுகலை &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸுக்கு வழங்கவா?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_microphone" msgid="2825208549114811299">"ஆடியோ ரெக்கார்டு செய்ய &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_microphone" msgid="8510456971528228861">"இந்த ஆப்ஸை நீங்கள் உபயோகிக்கும்போது மட்டுமே ஆடியோ ரெக்கார்டு செய்யும்"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"ஆடியோ ரெக்கார்டு செய்ய &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"இந்த ஆப்ஸை உபயோகிக்காத போதும்கூட எந்நேரமும் ஆடியோ ரெக்கார்டு செய்ய அனுமதி கேட்கக்கூடும். "<annotation id="link">"அமைப்புகளில் அனுமதிக்கவும்."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸுக்கான மைக்ரோஃபோன் அணுகலை மாற்றவா?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"இந்த ஆப்ஸை உபயோகிக்காத போதும்கூட எந்நேரமும் ஆடியோ ரெக்கார்டு செய்ய அனுமதி கேட்கிறது. "<annotation id="link">"அமைப்புகளில் அனுமதிக்கவும்."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"உடல் செயல்பாட்டைக் கண்காணிக்க &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_camera" msgid="5123097035410002594">"படங்கள் எடுக்கவும் வீடியோ ரெக்கார்டு செய்யவும் &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_camera" msgid="9085323239764667883">"இந்த ஆப்ஸை நீங்கள் உபயோகிக்கும்போது மட்டுமே படங்கள் எடுக்கும், வீடியோ ரெக்கார்டு செய்யும்"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"படங்கள் எடுக்கவும் வீடியோ ரெக்கார்டு செய்யவும் &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"இந்த ஆப்ஸை உபயோகிக்காத போதும்கூட எந்நேரமும் படங்கள் எடுக்கவும் வீடியோ ரெக்கார்டு செய்யவும் அனுமதி கேட்கக்கூடும். "<annotation id="link">"அமைப்புகளில் அனுமதிக்கவும்."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸுக்கான கேமரா அணுகலை மாற்றவா?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"இந்த ஆப்ஸை உபயோகிக்காத போதும்கூட எந்நேரமும் படங்கள் எடுக்கவும் வீடியோ ரெக்கார்டு செய்யவும் அனுமதி கேட்கிறது. "<annotation id="link">"அமைப்புகளில் அனுமதிக்கவும்."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"உங்கள் மொபைல் அழைப்புப் பதிவுகளை அணுக, &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_phone" msgid="1829234136997316752">"மொபைல் அழைப்புகள் செய்யவும், அவற்றை நிர்வகிக்கவும், &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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_sensors" msgid="4397358316850652235">"உங்கள் உடலியக்கக் குறிகள் பற்றிய சென்சார் தரவை அணுகுவதற்கு &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"ஆப்ஸைப் பயன்படுத்தாதபோதும் உங்கள் உடலியக்க அளவீடுகள் பற்றிய சென்சார் தரவை எப்போதும் அணுக இந்த ஆப்ஸ் விரும்புகிறது. இந்த மாற்றத்தைச் செய்ய "<annotation id="link">"அமைப்புகளுக்குச் செல்லுங்கள்."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"உடலியக்க அளவீடுகள் பற்றிய சென்சார் தரவை அணுக &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"இந்த ஆப்ஸ் எல்லா நேரங்களிலும் உடல் சென்சார் தரவை அணுக (நீங்கள் ஆப்ஸைப் பயன்படுத்தாதபோதும்) "<annotation id="link">"அமைப்புகளுக்குச் செல்லுங்கள்."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"ஆப்ஸ் பயன்பாட்டில் இருக்கும்போது உடல் சென்சார் தரவை அணுக &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&amp;gt ஆப்ஸுக்குத் தொடர்ந்து அனுமதியளிக்கவா?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸ் உபயோகத்தில் இருக்கும்போது உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; இல் உடல் சென்சார் குறித்த தரவை அணுக தொடர்ந்து அனுமதிக்கவா?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"உங்களுக்கு அறிவிப்புகளை அனுப்ப &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"உங்கள் &lt;b&gt;<xliff:g id="DEVICE">%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="auto_granted_permissions" msgid="6009452264824455892">"கட்டுப்படுத்தப்பட்ட அனுமதிகள்"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு இருப்பிட அணுகல் உள்ளது"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"உங்கள் இருப்பிடத்தை <xliff:g id="APP_NAME">%1$s</xliff:g> அணுக உங்கள் நிறுவனம் அனுமதிக்கிறது"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"பிற அனுமதிகள்"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"சிஸ்டத்தால் பயன்படுத்தப்படும் அனுமதி"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"சிஸ்டம் ஆப்ஸால் மட்டுமே பயன்படுத்தப்படும் அனுமதிகள்."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"மூன்றாம் தரப்பினருடன் இருப்பிடத் தரவைப் பகிரலாம் என இந்த ஆப்ஸ் குறிப்பிடுகிறது"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"தரவுப் பகிர்வு மற்றும் இருப்பிடம்"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"தரவுப் பகிர்வு குறித்த தகவல்கள் எங்கிருந்து பெறப்படுகின்றன?"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"இந்த ஆப்ஸ் எப்படித் தரவைப் பகிர்கிறது என்பது குறித்த தகவல்களை டெவலப்பர் இந்தச் சாதனத்தின் உற்பத்தியாளருக்கு வழங்கியுள்ளார். டெவெலப்பர் காலப்போக்கில் இந்தத் தகவல்களைப் புதுப்பிக்கக்கூடும்."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"இந்த ஆப்ஸ் எப்படித் தரவைப் பகிர்கிறது என்பது குறித்த தகவல்களை டெவெலப்பர் "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" என்பதற்கு வழங்கியுள்ளார். டெவெலப்பர் காலப்போக்கில் இந்தத் தகவல்களை மாற்றக்கூடும்."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ஆப்ஸ் இவற்றுக்காக இருப்பிடத் தரவைப் பகிரக்கூடும்:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"தரவுப் பகிர்வு வேறுபடுகிறது"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"தரவுப் பாதுகாப்பு"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"இருப்பிடத் தரவு பகிரப்படலாம்"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"இந்த ஆப்ஸில் குறிப்பிட்டுள்ளபடி மூன்றாம் தரப்பினருடன் இருப்பிடத் தரவை இது பகிரலாம்"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"இந்த இணைப்பைத் திறக்க முடியவில்லை"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"இருப்பிடத்திற்கான தரவுப் பகிர்வு குறித்த அறிவிப்புகள்"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"உங்கள் இருப்பிடத் தரவைப் பகிரும் விதத்தை மாற்றிய ஆப்ஸ் எவை எனப் பாருங்கள்"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"உங்கள் இருப்பிடத் தரவைப் பகிரும் விதத்தை இந்த ஆப்ஸ் மாற்றியுள்ளன. இதற்குமுன் அவற்றைப் பகிராமல் இருந்திருக்கலாம் அல்லது விளம்பரப்படுத்தல், மார்கெட்டிங் போன்ற நோக்கங்களுக்காக இப்போது பகிரக்கூடும்."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"தரவுப் பகிர்வு குறித்த அறிவிப்புகள்"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"உங்கள் இருப்பிடத் தரவைப் பகிரும் விதத்தைச் சில ஆப்ஸ் மாற்றியுள்ளன"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"அமைப்புகள்"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"அணுகிய நேரம்: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"நேற்று அணுகிய நேரம்: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"அணுகிய நேரம்: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-te/strings.xml b/PermissionController/res/values-te/strings.xml
index 562b6f4cd..074f9589d 100644
--- a/PermissionController/res/values-te/strings.xml
+++ b/PermissionController/res/values-te/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"మరింత సమాచారం"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"అన్నీ అనుమతించండి"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"ఎల్లవేళలా అన్నీ అనుమతించండి"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"పరిమిత యాక్సెస్‌ను అనుమతించండి"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"ఫోటోలు, వీడియోలను ఎంచుకోండి"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"మరిన్ని ఫోటోలను ఎంచుకోండి"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"మరిన్ని ఫోటోలను ఎంచుకోవద్దు"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"ఏదేమైనా అనుమతించవద్దు"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"విస్మరించు"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> యొక్క <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని <xliff:g id="ACTION">%2$s</xliff:g> చేయడానికి అనుమతించాలా?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"<xliff:g id="ACTION">%2$s</xliff:g> చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను ఎల్లప్పుడూ అనుమతించాలా?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‌ను ఈ చర్య చేయడానికి అనుమతించాలా? - <xliff:g id="ACTION">%2$s</xliff:g>"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"ఈ చర్యను చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‌ను ఎల్లప్పుడూ అనుమతించాలా? - <xliff:g id="ACTION">%2$s</xliff:g>"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"యాప్‌ను ఉపయోగిస్తున్నప్పుడు మాత్రమే"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"ఎల్లప్పుడూ"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"అనుమతించవద్దు, మళ్లీ అడగవద్దు"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"యాప్‌లు"</string>
<string name="app_permissions" msgid="3369917736607944781">"యాప్ అనుమతులు"</string>
<string name="unused_apps" msgid="2058057455175955094">"ఉపయోగించని యాప్‌లు"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"ఈ యాప్ కోసం ఎంచుకున్న ఫోటోలను ఎడిట్ చేయండి"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ఉపయోగించని యాప్‌లు లేవు"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ఉపయోగించని యాప్‌లు"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"ఇటీవలి అనుమతి నిర్ణయాలు"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"అన్ని అనుమతులు"</string>
<string name="other_permissions" msgid="2901186127193849594">"ఇతర యాప్ సామర్థ్యాలు"</string>
<string name="permission_request_title" msgid="8790310151025020126">"అనుమతి రిక్వెస్ట్‌"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android వేర్"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wearలో ఇన్‌స్టాల్/అన్ఇన్‌స్టాల్ చర్యలకు మద్దతు లేదు."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; యాక్సెస్ చేయడానికి అనుమతించాల్సిన వాటిని ఎంచుకోండి"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; అప్‌డేట్ చేయబడింది. ఈ యాప్ యాక్సెస్ చేయడానికి అనుమతించాల్సిన వాటిని ఎంచుకోండి."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"రద్దు చేయండి"</string>
@@ -194,9 +194,9 @@
<string name="precise_image_description" msgid="6349638632303619872">"ఖచ్చితమైన లొకేషన్"</string>
<string name="approximate_image_description" msgid="938803699637069884">"సుమారు లొకేషన్"</string>
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"ఖచ్చితమైన లొకేషన్‌ను ఉపయోగించండి"</string>
- <string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"ఖచ్చితమైన లొకేషన్ ఆఫ్‌లో ఉన్నప్పుడు, యాప్‌లు మీ సుమారు లొకేషన్‌ను యాక్సెస్ చేయగలగవచ్చు"</string>
+ <string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"ఖచ్చితమైన లొకేషన్ అనే సెట్టింగ్ ఆఫ్‌లో ఉన్నప్పుడు, యాప్‌లు మీ సుమారు లొకేషన్‌ను యాక్సెస్ చేయగలవు"</string>
<string name="app_permission_title" msgid="2090897901051370711">"\'<xliff:g id="PERM">%1$s</xliff:g>\' అనుమతి"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"ఈ యాప్ కోసం \'<xliff:g id="PERM">%1$s</xliff:g>\' యాక్సెస్"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"ఈ యాప్ కోసం \'<xliff:g id="PERM">%1$s</xliff:g>\' యాక్సెస్‌ను ఇవ్వాలా? వద్దా"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"అన్ని \'<xliff:g id="APP">%1$s</xliff:g>\' అనుమతులను చూడండి"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"ఈ అనుమతి ఉన్న అన్ని యాప్‌లను చూడండి"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"అసిస్టెంట్ మైక్రోఫోన్ వినియోగాన్ని చూపు"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"యాప్‌ని ఉపయోగించకపోతే, అనుమతులను తీసివేయండి"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"అనుమతులను తీసివేసి స్పేస్‌ను ఖాళీ చేయండి"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"యాప్‌ను ఉపయోగించకపోతే దాని యాక్టివిటీని పాజ్ చేయండి"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"యాప్‌ను ఉపయోగించకపోతే, మేనేజ్ చేయండి"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"అనుమతులను తీసివేయండి, తాత్కాలిక ఫైళ్లను తొలగించండి, అలాగే నోటిఫికేషన్‌లను ఆపివేయండి"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"అనుమతులను తీసివేయండి, తాత్కాలిక ఫైళ్లను తొలగించండి, నోటిఫికేషన్‌లను ఆపివేయండి, యాప్‌ను ఆర్కైవ్ చేయండి"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"మీ డేటాను సురక్షితంగా ఉంచడానికి, ఈ యాప్ కొన్ని నెలలుగా వినియోగంలో లేకుంటే, దాని అనుమతులు తీసివేయబడతాయి."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"మీ డేటాను సురక్షితంగా ఉంచడానికి, ఈ యాప్ కొన్ని నెలలుగా వినియోగంలో లేకుంటే, దానికి ఇచ్చిన కింది అనుమతులు తీసివేయబడతాయి: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"మీ డేటాను సురక్షితంగా ఉంచడానికి, కొన్ని నెలలుగా వినియోగంలో లేని యాప్‌ల అనుమతులు తీసివేయబడ్డాయి."</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"చివరిగా తెరిచినది <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"మీరు అన్ని ఫైళ్ల మేనేజ్‌మెంట్‌కు అనుమతిస్తే,ఈ పరికరంలో లేదా కనెక్ట్ చేయబడిన స్టోరేజ్ పరికరాలలో ఉమ్మడి స్టోరేజ్‌లోని ఏ ఫైళ్లను అయినా ఈ యాప్ యాక్సెస్ చేయగలదు, సవరించగలదు, లేదా తొలగించగలదు. యాప్ మీ అనుమతి తీసుకోకుండానే ఫైళ్లను యాక్సెస్ చేయవచ్చు."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"ఈ పరికరంలో లేదా ఏవైనా కనెక్ట్ చేయబడిన స్టోరేజ్ పరికరాలలో ఫైళ్లను యాక్సెస్ చేయడానికి, ఎడిట్ చేయడానికి, లేదా తొలగించడానికి ఈ యాప్‌నకు అనుమతి ఇవ్వాలా? ఈ యాప్ మీ అనుమతి తీసుకోకుండానే ఫైళ్లను యాక్సెస్ చేయవచ్చు."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"ఈ యాప్‌ల‌కు ఈ అనుమ‌తి ఇస్తుంది- <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"ఈ అనుమ‌తి ఉన్న యాప్‌లు ఇది చేయగలవు- <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"వాకింగ్, బైకింగ్, సైక్లింగ్, అడుగులను లెక్కించడం మొదలైన శారీరక శ్రమను, ఇంకా మరిన్నింటిని ఈ అనుమతి ఉన్న యాప్‌లు యాక్సెస్ చేయగలవు"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"ఈ అనుమతి ఉన్న యాప్‌లు మీ క్యాలెండర్‌ను యాక్సెస్ చేయగలవు"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"ఈ అనుమతి ఉన్న యాప్‍‌లు ఫోన్ కాల్ లాగ్‌ను చదవగలుగుతాయి, దానిలో రాయగలుగుతాయి"</string>
@@ -250,7 +252,7 @@
<string name="allowed_foreground_header" msgid="6845655788447833353">"ఉపయోగించేటప్పుడు మాత్రమే అనుమతి ఇవ్వాలి"</string>
<string name="allowed_storage_scoped" msgid="5383645873719086975">"మీడియాకు మాత్రమే యాక్సెస్ అనుమతించబడినవి"</string>
<string name="allowed_storage_full" msgid="5356699280625693530">"ఫైల్స్ అన్నింటినీ మేనేజ్ చేసేందుకు అనుమతించబడినవి"</string>
- <string name="ask_header" msgid="2633816846459944376">"ప్రతిసారి అడుగు"</string>
+ <string name="ask_header" msgid="2633816846459944376">"ప్రతిసారి అడగాలి"</string>
<string name="denied_header" msgid="903209608358177654">"అనుమతించబడలేదు"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"అన్ని ఫైళ్లను యాక్సెస్ చేయగల మరిన్ని యాప్‌లను చూడండి"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 రోజు}other{# రోజులు}}"</string>
@@ -266,7 +268,7 @@
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ఉపయోగించని యాప్}other{# ఉపయోగించని యాప్‌లు}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"అనుమతులు, తాత్కాలిక ఫైళ్లు తీసివేయబడ్డాయి అలాగే నోటిఫికేషన్‌లు ఆపివేయబడ్డాయి. రివ్యూ చేయడానికి ట్యాప్ చేయండి."</string>
<string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"అనుమతులు తీసివేయబడిన యాప్‌లను రివ్యూ చేయండి"</string>
- <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"కొంతకాలంగా మీరు ఉపయోగించని యాప్‌లకు సంబంధించిన అనుమతులు, తాత్కాలిక ఫైల్‌లు తొలగించబడ్డాయి, అలాగే నోటిఫికేషన్‌లు నిలిపివేయబడ్డాయి."</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"కొంతకాలంగా మీరు ఉపయోగించని యాప్‌లకు సంబంధించిన అనుమతులు, తాత్కాలిక ఫైళ్లు తొలగించబడ్డాయి, అలాగే నోటిఫికేషన్‌లు నిలిపివేయబడ్డాయి."</string>
<string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"యాప్‌లను రివ్యూ చేయండి"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"ఇటీవలి అనుమతులను చెక్ చేయండి"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"డ్రైవింగ్‌లో ఉన్నప్పుడు, మీరు <xliff:g id="APP">%1$s</xliff:g> యాప్‌నకు <xliff:g id="PERMISSION">%2$s</xliff:g>‌కు యాక్సెస్‌ను ఇచ్చారు"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"నోట్స్ యాప్"</string>
<string name="role_notes_description" msgid="8496852798616883551">"మీ పరికరంలో నోట్స్ తీసుకోవడానికి మిమ్మల్ని అనుమతించే యాప్‌లు"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"నోట్స్"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"ప్రస్తుతం ఆటోమేటిక్‌గా ఉంది"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"మళ్లీ అడగవద్దు"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ఆటోమేటిక్ చేయండి"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Assistant ట్రిగ్గర్ గుర్తింపును చూపించడం"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"వాయిస్ అసిస్టెంట్‌ను యాక్టివేట్ చేయడానికి మైక్రోఫోన్‌ను ఉపయోగించినప్పుడు, స్టేటస్ బార్‌లో చిహ్నాన్ని చూపు"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"మీ పరికరంలో ఫోటోలు, మీడియా ఫైళ్లను యాక్సెస్ చేయగలిగేలా &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_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="2270563860206654757">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_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="6641436550953715107">"మీ &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="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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"మీ &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> లొకేషన్‌ను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‌కు అనుమతినివ్వాలా?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ఈ యాప్‌నకు మీ లొకేషన్ యాక్సెస్ అన్ని సమయాలలో, అంటే యాప్‌ను ఉపయోగించనప్పుడు కూడా, అవసరం ఉండవచ్చు. "<annotation id="link">"సెట్టింగ్‌లలో అనుమతించండి."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; కోసం లొకేష‌న్‌ యాక్సెస్‌ను మార్చాలా?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"మీరు యాప్ ఉపయోగించనప్పుడు కూడా ఈ యాప్ మీ లొకేష‌న్‌ను ఎప్పటికప్పుడు యాక్సెస్ చేయాల‌ని అనుకుంటోంది."<annotation id="link">"సెట్టింగ్‌లలో అనుమతించండి."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"సమీప పరికరాల సంబంధిత స్థానాన్ని కనుగొనడానికి, కనెక్ట్ చేయడానికి అలాగే నిర్ణయించడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"సమీప పరికరాల సంబంధిత స్థానాన్ని కనుగొనడానికి, కనెక్ట్ చేయడానికి అలాగే నిర్ణయించడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా? "<annotation id="link">"సెట్టింగ్‌లలో అనుమతించండి."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>కు సంబంధించిన లొకేషన్ యాక్సెస్‌ను సుమారు నుండి ఖచ్చితమైనదిగా మార్చాలా?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="9001956706241104626">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_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="3103987548035171850">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"మీ &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;‌లో SMSను పంపడానికి, చూడటానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$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="872629037299467086">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_storage_q_to_s" msgid="8213701872983685505">"ఈ పరికరంలో &lt;b&gt;ఫోటోలు, వీడియోలు, మ్యూజిక్, ఆడియో&lt;/b&gt;ను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"ఈపరికరంలో &lt;b&gt;ఫోటోలు, వీడియోలు, మ్యూజిక్, ఆడియో, ఇతర ఫైళ్ల&lt;/b&gt; యాక్సెస్‌కు &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"ఈ పరికరంలో మ్యూజిక్‌ను, ఆడియోను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‌ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_read_media_visual" msgid="5548780620779729975">"ఈ పరికరంలో ఫోటోలను, వీడియోలను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‌ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_more_photos" msgid="128933814654231321">"ఈ పరికరంలోని మరిన్ని ఫోటోలను, వీడియోలను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; యాప్‌ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_microphone" msgid="2825208549114811299">"ఆడియోను రికార్డ్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_microphone" msgid="8510456971528228861">"మీరు యాప్‌ను ఉపయోగిస్తున్నప్పుడు మాత్రమే ఈ యాప్, ఆడియోను రికార్డ్ చేయగలుగుతుంది"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"ఆడియోను రికార్డ్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"మీరు యాప్ ఉపయోగించనప్పుడు కూడా ఈ యాప్ ఎల్లప్పుడూ ఆడియోను రికార్డ్ చేయాలనుకోవచ్చు. "<annotation id="link">"సెట్టింగ్‌లలో అనుమతించండి."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; కోసం మైక్రోఫోన్ యాక్సెస్‌ను మార్చాలా?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"మీరు యాప్ ఉపయోగించనప్పుడు కూడా ఈ యాప్ ఎల్లప్పుడూ ఆడియోను రికార్డ్ చేయాలనుకుంటోంది. "<annotation id="link">"సెట్టింగ్‌లలో అనుమతించండి."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"మీ భౌతిక యాక్టివిటీని యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_camera" msgid="5123097035410002594">"ఫోటోలు తీయడానికి, వీడియో రికార్డ్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgrouprequestdetail_camera" msgid="9085323239764667883">"మీరు యాప్‌ను ఉపయోగిస్తున్నప్పుడు మాత్రమే ఈ యాప్, ఫోటోలను తీయగలుగుతుంది, వీడియోను రికార్డ్ చేయగలుగుతుంది"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"ఫోటోలు తీయడానికి, వీడియోను రికార్డ్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"మీరు యాప్ ఉపయోగించనప్పుడు కూడా ఈ యాప్ ఎల్లప్పుడూ ఫోటోలను తీయాలనుకోవచ్చు, వీడియోను రికార్డ్ చేయాలనుకోవచ్చు. "<annotation id="link">"సెట్టింగ్‌లలో అనుమతించండి."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; కోసం కెమెరా యాక్సెస్‌ను మార్చాలా?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"మీరు యాప్ ఉపయోగించనప్పుడు కూడా ఈ యాప్ ఎల్లప్పుడూ ఫోటోలను తీయాలనుకుంటోంది, వీడియోను రికార్డ్ చేయాలనుకుంటోంది. "<annotation id="link">"సెట్టింగ్‌లలో అనుమతించండి."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"మీ ఫోన్ కాల్ లాగ్‌లను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_phone" msgid="1829234136997316752">"ఫోన్‌ కాల్స్‌ చేయడానికి, మేనేజ్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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_sensors" msgid="4397358316850652235">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"ఈ యాప్‌ను మీరు ఉపయోగించని సమయంలో కూడా మీ ఆరోగ్యానికి సంబంధించి కీలకమైన కొలమానాల గురించిన సెన్సార్ డేటాను ఎల్లప్పుడూ యాక్సెస్ చేయగలిగేలా ఈ యాప్ అనుమతి కోరుతోంది. ఈ మార్పును ఆమోదించడానికి, "<annotation id="link">"సెట్టింగ్‌లకు వెళ్లండి."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"మీ ఆరోగ్యానికి సంబంధించి కీలకమైన కొలమానాల గురించిన సెన్సార్ డేటాను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"మీరు యాప్‌ను ఉపయోగించనప్పుడు కూడా, శరీర సెన్సార్ డేటాను ఎల్లప్పుడూ యాక్సెస్ చేయడానికి ఈ యాప్‌ను అనుమతించడానికి, "<annotation id="link">"సెట్టింగ్‌లకు వెళ్లండి."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"యాప్‌ను వినియోగిస్తున్నప్పుడు బాడీ సెన్సార్ డేటాను యాక్సెస్ చేయగలిగేలా &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‌కు ఉన్న అనుమతిని కొనసాగించాలా?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"యాప్ వినియోగంలో ఉన్నప్పుడు, మీ &lt;b&gt;<xliff:g id="DEVICE">%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_notifications" msgid="6396739062335106181">"మీకు నోటిఫికేషన్‌లను పంపడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"మీ &lt;b&gt;<xliff:g id="DEVICE">%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="auto_granted_permissions" msgid="6009452264824455892">"నియంత్రణలో ఉన్న అనుమతులు"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g>‌కు లొకేషన్ యాక్సెస్ ఉంది"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"మీ సంస్థ, మీ లొకేషన్‌ను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g>‌నకు అనుమతి ఇస్తుంది"</string>
@@ -572,7 +611,7 @@
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"ఈ యాప్ Android తాజా వెర్షన్‌కు సపోర్ట్ ఇవ్వదు. ఈ యాప్ మ్యూజిక్, ఆడియో ఫైల్స్‌ను యాక్సెస్ చేయలేకపోతే, ఫోటోలు, వీడియోలను యాక్సెస్ చేయడానికి కూడా ఇది అనుమతించబడదు."</string>
<string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Review app with background location access"</string>
<string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> can always access your location, even when the app is closed"</string>
- <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"బ్యాక్‌గ్రౌండ్ లొకేషన్‌కు యాక్సెస్‌ను కలిగి ఉన్న యాప్‌ను రివ్యూ చేయండి"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"బ్యాక్‌గ్రౌండ్ లొకేషన్‌కు యాక్సెస్‌ ఉన్న యాప్‌ను రివ్యూ చేయండి"</string>
<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>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"ఈ యాప్, అది లొకేషన్ డేటాను థర్డ్-పార్టీలతో షేర్ చేయవచ్చని పేర్కొంది"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"డేటా షేరింగ్ &amp; లొకేషన్"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"డేటా షేరింగ్‌కు సంబంధించిన సమాచారం ఎక్కడి నుంచి వస్తుంది"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"డెవలపర్ ఈ యాప్, డేటాను ఎలా షేర్ చేస్తుంది అనే సమాచారాన్ని పరికర తయారీదారుకు అందించారు. డెవలపర్ ఈ సమాచారాన్ని కాలానుగుణంగా అప్‌డేట్ చేయవచ్చు."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"ఈ యాప్, డేటాను ఎలా షేర్ చేస్తుంది అనే సమాచారాన్ని డెవలపర్ "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"‌కు అందించారు. డెవలపర్ ఈ సమాచారాన్ని కాలానుగుణంగా అప్‌డేట్ చేయవచ్చు."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"ఈ యాప్ లొకేషన్ డేటాను వీటి కోసం షేర్ చేయవచ్చు:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"డేటా షేరింగ్ మారుతూ ఉంటుంది"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"డేటా భద్రత"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"లొకేషన్ డేటా షేర్ చేయబడవచ్చు"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"ఈ యాప్ మీ లొకేషన్ డేటాను థర్డ్-పార్టీలతో షేర్ చేయవచ్చని పేర్కొంది"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"ఈ లింక్‌ను తెరవడం సాధ్యపడదు"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"లొకేషన్‌కు సంబంధించిన డేటా షేరింగ్ అప్‌డేట్‌లు"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"మీ లొకేషన్ డేటాను షేర్ చేసే విధానాన్ని మార్చిన యాప్‌లను రివ్యూ చేయండి"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"ఈ యాప్‌లు మీ లొకేషన్ డేటాను షేర్ చేయగల విధానాన్ని మార్చాయి. అవి దీన్ని ఇంతకు ముందు షేర్ చేసి ఉండకపోవచ్చు, లేదా ఇప్పుడు అడ్వర్టయిజింగ్ లేదా మార్కెటింగ్ ప్రయోజనాల కోసం షేర్ చేయవచ్చు."</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"డేటా షేరింగ్ అప్‌డేట్‌లు"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"కొన్ని యాప్‌లు మీ లొకేషన్ డేటాను షేర్ చేయగల విధానాన్ని మార్చాయి"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"సెట్టింగ్‌లు"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g>‌కు యాక్సెస్‌ చేశారు"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"నిన్న <xliff:g id="TIME_DATE">%1$s</xliff:g>‌కు యాక్సెస్‌ చేశారు"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g>‌న<xliff:g id="TIME_DATE_1">%2$s</xliff:g>‌కు యాక్సెస్‌ చేశారు"</string>
</resources>
diff --git a/PermissionController/res/values-th-v33/strings.xml b/PermissionController/res/values-th-v33/strings.xml
index 4cae29b03..1270c9c1c 100644
--- a/PermissionController/res/values-th-v33/strings.xml
+++ b/PermissionController/res/values-th-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"การแจ้งเตือนเพิ่มเติม"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"การแจ้งเตือนที่ปิดไป"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{ขยายและดูการแจ้งเตือนอีก 1 รายการ}other{ขยายและดูการแจ้งเตือนอีก # รายการ}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"การแจ้งเตือน <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"การดำเนินการเสร็จสมบูรณ์"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"ตรวจสอบการตั้งค่าที่เพิ่มการปกป้องให้กับอุปกรณ์ได้"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"การตั้งค่าด่วนด้านความปลอดภัยและความเป็นส่วนตัว"</string>
diff --git a/PermissionController/res/values-th-v34/strings.xml b/PermissionController/res/values-th-v34/strings.xml
index 7380c49d2..8e6bae837 100644
--- a/PermissionController/res/values-th-v34/strings.xml
+++ b/PermissionController/res/values-th-v34/strings.xml
@@ -21,7 +21,7 @@
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"การควบคุม"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
<string name="health_connect_summary" msgid="815473513776882296">"จัดการสิทธิ์เข้าถึงข้อมูลสุขภาพของแอป"</string>
- <string name="location_settings" msgid="8863940440881290182">"การเข้าถึงตำแหน่ง"</string>
+ <string name="location_settings" msgid="8863940440881290182">"สิทธิ์เข้าถึงตำแหน่ง"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"สำหรับแอปและบริการ หากปิดการตั้งค่านี้ ระบบอาจยังคงแชร์ข้อมูลไมโครโฟนเมื่อคุณโทรหาหมายเลขฉุกเฉิน"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"สำหรับแอปและบริการ"</string>
</resources>
diff --git a/PermissionController/res/values-th/strings.xml b/PermissionController/res/values-th/strings.xml
index 4e0916510..3ce55da09 100644
--- a/PermissionController/res/values-th/strings.xml
+++ b/PermissionController/res/values-th/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"ข้อมูลเพิ่มเติม"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"อนุญาตทั้งหมด"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"อนุญาตทั้งหมดตลอดเวลา"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"อนุญาตสิทธิ์เข้าถึงแบบจำกัด"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"เลือกรูปภาพและวิดีโอ"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"เลือกเพิ่มเติม"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ไม่ต้องเลือกเพิ่มเติม"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"ไม่เลือกเพิ่มแล้ว"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"ยังคงไม่อนุญาต"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"ปิด"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> จาก <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> รายการ"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"แอป"</string>
<string name="app_permissions" msgid="3369917736607944781">"สิทธิ์ของแอป"</string>
<string name="unused_apps" msgid="2058057455175955094">"แอปที่ไม่ได้ใช้"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"แก้ไขรูปภาพที่เลือกสำหรับแอปนี้"</string>
<string name="no_unused_apps" msgid="12809387670415295">"ไม่มีแอปที่ไม่ได้ใช้งาน"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"แอปที่ไม่ได้ใช้ 0 รายการ"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"สิทธิ์ที่กำหนดไว้ล่าสุด"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"สิทธิ์ทั้งหมด"</string>
<string name="other_permissions" msgid="2901186127193849594">"ความสามารถอื่นๆ ของแอป"</string>
<string name="permission_request_title" msgid="8790310151025020126">"คำขอสิทธิ์"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"ไม่สามารถติดตั้ง/ถอนการติดตั้งบน Wear"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"โปรดเลือกข้อมูลที่อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึง"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"อัปเดต &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; แล้ว โปรดเลือกข้อมูลที่อนุญาตให้แอปนี้เข้าถึง"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"ยกเลิก"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"นำสิทธิ์ออกหากไม่ได้ใช้งานแอป"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"นำสิทธิ์ออกและเพิ่มพื้นที่ว่าง"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"หยุดกิจกรรมบนแอปไว้ชั่วคราวหากไม่ได้ใช้"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"จัดการแอปหากไม่ได้ใช้งาน"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"นำสิทธิ์ออก ลบไฟล์ชั่วคราว และหยุดการแจ้งเตือน"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"นำสิทธิ์ออก ลบไฟล์ชั่วคราว หยุดการแจ้งเตือน และเก็บแอป"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"หากคุณไม่ได้ใช้งานแอปนาน 2-3 เดือน ระบบจะนำสิทธิ์ของ​แอปนี้ออกเพื่อปกป้องข้อมูลของคุณ"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"หากไม่มีการใช้งานแอปนาน 2-3 เดือน ระบบจะปกป้องข้อมูลของคุณด้วยการนำสิทธิ์ต่อไปนี้ออก ได้แก่ <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"ระบบนำสิทธิ์ออกจากแอปที่คุณไม่ได้ใช้งานนาน 2-3 เดือนเพื่อปกป้องข้อมูลของคุณ"</string>
@@ -397,10 +399,20 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและสตรีมแอปไปยังอุปกรณ์ที่เชื่อมต่อ"</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"บริการนี้แชร์รูปภาพ สื่อ และการแจ้งเตือนจากโทรศัพท์ของคุณไปยังอุปกรณ์อื่น"</string>
- <string name="role_notes_label" msgid="7451627001058089536">"แอปการจดบันทึกเริ่มต้น"</string>
- <string name="role_notes_short_label" msgid="8796604147546125285">"แอปการจดบันทึก"</string>
- <string name="role_notes_description" msgid="8496852798616883551">"แอปที่ให้คุณจดบันทึกในอุปกรณ์ได้"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"แอปโน้ตเริ่มต้น"</string>
+ <string name="role_notes_short_label" msgid="8796604147546125285">"แอปโน้ต"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"แอปที่ให้คุณจดโน้ตในอุปกรณ์ได้"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"บันทึก"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"แอปเริ่มต้นปัจจุบัน"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"ไม่ต้องถามอีก"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"ตั้งเป็นแอปเริ่มต้น"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"แสดงการตรวจหาตัวทริกเกอร์ผู้ช่วย"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"แสดงไอคอนในแถบสถานะเมื่อมีการใช้ไมโครโฟนเพื่อเปิดใช้งานผู้ช่วยสั่งการด้วยเสียง"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงรูปภาพและสื่อในอุปกรณ์ไหม"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงรูปภาพและสื่อบน&lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงรายชื่อติดต่อบน&lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"อนุญาตให้ &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"อนุญาตให้ &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>ไหม"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"แอปนี้อาจต้องการเข้าถึงตำแหน่งของคุณตลอดเวลา แม้ในขณะที่คุณไม่ได้ใช้แอป โปรด"<annotation id="link">"อนุญาตในการตั้งค่า"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"เปลี่ยนการเข้าถึงตำแหน่งสำหรับ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ไหม"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"เปลี่ยนแปลงสิทธิ์เข้าถึงตำแหน่งของ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; บน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"แอปนี้ต้องการเข้าถึงตำแหน่งของคุณตลอดเวลา แม้ในขณะที่คุณไม่ได้ใช้แอป โปรด"<annotation id="link">"อนุญาตในการตั้งค่า"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ค้นหา เชื่อมต่อ และระบุตำแหน่งสัมพัทธ์ของอุปกรณ์ที่อยู่ใกล้เคียงไหม"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ค้นหา เชื่อมต่อ และระบุตำแหน่งซึ่งสัมพันธ์กับอุปกรณ์ใกล้เคียงบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ค้นหา เชื่อมต่อ และระบุตำแหน่งซึ่งสัมพันธ์กับอุปกรณ์ที่อยู่ใกล้เคียง "<annotation id="link">"อนุญาตในการตั้งค่า"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"เปลี่ยนการเข้าถึงตำแหน่งของ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> จากตำแหน่งโดยประมาณเป็นตำแหน่งที่แน่นอนไหม"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"เปลี่ยนแปลงสิทธิ์เข้าถึงตำแหน่งของ <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> บน&lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงตำแหน่งโดยประมาณของ&lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงปฏิทินบน&lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ส่งและดูข้อความ SMS บน&lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงรูปภาพ สื่อ และไฟล์บน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึง&lt;b&gt;รูปภาพ วิดีโอ เพลง และเสียง&lt;/b&gt;ในอุปกรณ์นี้ไหม"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึง&lt;b&gt;รูปภาพ วิดีโอ เพลง เสียง และไฟล์อื่นๆ&lt;/b&gt; ในอุปกรณ์นี้ไหม"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงเพลงและเสียงในอุปกรณ์นี้ไหม"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงเพลงและเสียงบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงรูปภาพและวิดีโอในอุปกรณ์นี้ไหม"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงรูปภาพและวิดีโอบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงรูปภาพและวิดีโอเพิ่มเติมในอุปกรณ์นี้ไหม"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงรูปภาพและวิดีโอเพิ่มเติมบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; บันทึกเสียงไหม"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; บันทึกเสียงบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"แอปจะบันทึกเสียงได้ในขณะที่คุณใช้แอปอยู่เท่านั้น"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; บันทึกเสียงไหม"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; บันทึกเสียงบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"แอปนี้อาจต้องการบันทึกเสียงตลอดเวลา แม้ในขณะที่คุณไม่ได้ใช้แอป "<annotation id="link">"อนุญาตในการตั้งค่า"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"เปลี่ยนแปลงสิทธิ์เข้าถึงไมโครโฟนของ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ไหม"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"เปลี่ยนแปลงสิทธิ์เข้าถึงไมโครโฟนของ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; บน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"แอปนี้ต้องการบันทึกเสียงตลอดเวลา แม้ในขณะที่คุณไม่ได้ใช้แอป "<annotation id="link">"อนุญาตในการตั้งค่า"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงกิจกรรมการเคลื่อนไหวร่างกายของคุณไหม"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงกิจกรรมการเคลื่อนไหวร่างกายบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ถ่ายรูปและบันทึกวิดีโอไหม"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ถ่ายภาพและบันทึกวิดีโอบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"แอปจะถ่ายภาพและวิดีโอได้ในขณะที่คุณใช้แอปอยู่เท่านั้น"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ถ่ายภาพและวิดีโอไหม"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ถ่ายภาพและบันทึกวิดีโอบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"แอปนี้อาจต้องการถ่ายภาพและวิดีโอตลอดเวลา แม้ในขณะที่คุณไม่ได้ใช้แอป "<annotation id="link">"อนุญาตในการตั้งค่า"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"เปลี่ยนแปลงสิทธิ์เข้าถึงกล้องถ่ายรูปของ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ไหม"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"เปลี่ยนแปลงสิทธิ์เข้าถึงกล้องของ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; บน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"แอปนี้ต้องการถ่ายภาพและวิดีโอตลอดเวลา แม้ในขณะที่คุณไม่ได้ใช้แอป "<annotation id="link">"อนุญาตในการตั้งค่า"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงบันทึกการโทรในโทรศัพท์ไหม"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงบันทึกการโทรในโทรศัพท์บน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; โทรและจัดการการโทรไหม"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; โทรและจัดการการโทรบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพไหม"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"แอปนี้ต้องการเข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพตลอดเวลาแม้ว่าคุณจะไม่ได้ใช้​แอปอยู่ก็ตาม หากจะอนุญาตตามนี้ "<annotation id="link">"ไปที่การตั้งค่า"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพไหม"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"หากต้องการให้แอปนี้เข้าถึงข้อมูลเซ็นเซอร์ร่างกายได้ทุกเมื่อ แม้ว่าคุณจะไม่ได้ใช้งานแอปอยู่ "<annotation id="link">"ไปที่การตั้งค่า"</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงข้อมูลเซ็นเซอร์ร่างกายได้ตลอดขณะใช้งานแอปไหม"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; เข้าถึงข้อมูลเซ็นเซอร์ร่างกายได้ตลอดขณะใช้งานแอปบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ส่งการแจ้งเตือนถึงคุณไหม"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"อนุญาตให้ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ส่งการแจ้งเตือนถึงคุณบน&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;ไหม"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"สิทธิ์ที่มีการควบคุม"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> มีสิทธิ์เข้าถึงตำแหน่ง"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"องค์กรของคุณอนุญาตให้ <xliff:g id="APP_NAME">%1$s</xliff:g> เข้าถึงตำแหน่ง"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"สิทธิ์อื่นๆ"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"สิทธิ์ที่ใช้โดยระบบ"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"สิทธิ์ที่ใช้โดยแอปพลิเคชันระบบเท่านั้น"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"แอปนี้ระบุว่าแอปอาจแชร์ข้อมูลตำแหน่งกับองค์กรบุคคลที่สามของแอป"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"การแชร์ข้อมูลและตำแหน่ง"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"แหล่งที่มาของรายละเอียดการแชร์ข้อมูล"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"นักพัฒนาแอปได้ให้รายละเอียดเกี่ยวกับวิธีที่แอปนี้แชร์ข้อมูลไว้กับผู้ผลิตอุปกรณ์นี้ โดยอาจอัปเดตข้อมูลนี้เมื่อเวลาผ่านไป"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"นักพัฒนาแอปได้ให้รายละเอียดเกี่ยวกับวิธีที่แอปนี้แชร์ข้อมูลไว้ใน "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" โดยอาจอัปเดตข้อมูลนี้เมื่อเวลาผ่านไป"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"แอปนี้อาจแชร์ข้อมูลตำแหน่งเพื่อ"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"การแชร์ข้อมูลแตกต่างกันไปตามปัจจัยต่างๆ"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ความปลอดภัยของข้อมูล"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"อาจมีการแชร์ข้อมูลตำแหน่ง"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"แอปนี้ระบุว่าอาจแชร์ข้อมูลตำแหน่งของคุณกับบุคคลที่สาม"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"เปิดลิงก์นี้ไม่ได้"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"การอัปเดตการแชร์ข้อมูลตำแหน่ง"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ตรวจสอบแอปที่เปลี่ยนแปลงวิธีที่อาจใช้แชร์ข้อมูลตำแหน่งของคุณ"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"แอปต่อไปนี้ได้เปลี่ยนแปลงวิธีที่แอปอาจแชร์ข้อมูลตำแหน่งของคุณ โดยที่แอปอาจไม่เคยแชร์มาก่อน หรืออาจแชร์ในตอนนี้เพื่อวัตถุประสงค์ในการโฆษณาหรือการตลาดก็ได้"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"การอัปเดตการแชร์ข้อมูล"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"มีบางแอปเปลี่ยนแปลงวิธีที่แอปอาจแชร์ข้อมูลตำแหน่งของคุณ"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"การตั้งค่า"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"เข้าถึงตอน <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"เข้าถึงเมื่อวานตอน <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"เข้าถึงเมื่อวันที่ <xliff:g id="TIME_DATE_0">%1$s</xliff:g> ตอน <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-tl-v33/strings.xml b/PermissionController/res/values-tl-v33/strings.xml
index 28ef796d1..0c23a30f7 100644
--- a/PermissionController/res/values-tl-v33/strings.xml
+++ b/PermissionController/res/values-tl-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Higit pang alerto"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Mga na-dismiss na alerto"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{I-expand at makakita ng isa pang alerto}one{I-expand at makakita ng # pang alerto}other{I-expand at makakita ng # pang alerto}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Alerto. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Tapos na ang pagkilos"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Tingnan ang mga setting na makakapagdagdag ng proteksyon sa iyong device"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Mga mabilisang setting ng seguridad at privacy"</string>
diff --git a/PermissionController/res/values-tl/strings.xml b/PermissionController/res/values-tl/strings.xml
index 2b9beebd3..ec3d6dad2 100644
--- a/PermissionController/res/values-tl/strings.xml
+++ b/PermissionController/res/values-tl/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Higit pang info"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Pahintulutan lahat"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Palaging pahintulutan lahat"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Payagan ang limitadong access"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Pumili ng mga larawan at video"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Pumili pa"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Huwag nang pumili pa"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Mga App"</string>
<string name="app_permissions" msgid="3369917736607944781">"Mga pahintulot sa app"</string>
<string name="unused_apps" msgid="2058057455175955094">"Mga hindi ginagamit na app"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"I-edit ang mga piniling larawan para sa app na ito"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Walang hindi ginagamit na app"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 hindi ginagamit na app"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Mga recent permission decision"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Lahat ng pahintulot"</string>
<string name="other_permissions" msgid="2901186127193849594">"Iba pang kakayahan ng app"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Kahilingan sa pagpapahintulot"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Ang mga pagkilos na I-install/I-uninstall ay hindi sinusuportahan sa Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Piliin kung ano ang papayagang i-access ng &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Na-update na ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;. Piliin kung ano ang papayagang i-access ng app na ito."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Kanselahin"</string>
@@ -196,7 +196,7 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"Gamitin ang eksaktong lokasyon"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Kapag naka-off ang eksaktong lokasyon, puwedeng i-access ng mga app ang iyong tinatantyang lokasyon"</string>
<string name="app_permission_title" msgid="2090897901051370711">"Pahintulot sa <xliff:g id="PERM">%1$s</xliff:g>"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"access sa <xliff:g id="PERM">%1$s</xliff:g> para sa app na ito"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"Access sa <xliff:g id="PERM">%1$s</xliff:g> para sa app na ito"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Tingnan ang lahat ng pahintulot ng <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Tingnan ang lahat ng app na may ganitong pahintulot"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Ipakita ang paggamit ng mikropono ng assistant"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Alisin ang mga pahintulot kung hindi ginagamit ang app"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Alisin ang pahintulot, magbakante ng espasyo"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"I-pause ang aktibidad sa app kung hindi ginagamit"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Pamahalaan ang app kung hindi ginagamit"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Alisin ang mga pahintulot, i-delete ang mga pansamantalang file, at ihinto ang mga notification"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Alisin ang mga pahintulot, i-delete ang mga pansamantalang file, ihinto ang mga notification, at i-archive ang app"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Para maprotektahan ang iyong data, aalisin ang mga pahintulot para sa app na ito kapag ilang buwan nang hindi ginagamit ang app."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Para maprotektahan ang iyong data, kapag ilang buwan nang hindi ginagamit ang app, aalisin ang mga sumusunod na pahintulot: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Para protektahan ang iyong data, inalis na ang mga pahintulot sa mga app na ilang buwan mo nang hindi ginagamit."</string>
@@ -398,9 +400,19 @@
<string name="role_app_streaming_description" msgid="7341638576226183992">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa iyong mga notification at i-stream ang iyong mga app sa nakakonektang device."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ibinabahagi ng serbisyong ito ang iyong mga larawan, media, at notification sa ibang device mula sa iyong telepono."</string>
<string name="role_notes_label" msgid="7451627001058089536">"Default na app sa pagtatala"</string>
- <string name="role_notes_short_label" msgid="8796604147546125285">"App sa pagtatala"</string>
+ <string name="role_notes_short_label" msgid="8796604147546125285">"Notes app"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Mga app na nagbibigay-daan sa iyong magtala sa device mo"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"mga tala"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Kasalukuyang default"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Huwag nang itanong muli"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Itakdang default"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Ipakita ang pagtukoy ng trigger ng assistant"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Ipakita ang icon sa status bar kapag gumamit ng mikropono para i-activate ang voice assistant"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang mga larawan at media sa iyong device?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang mga larawan at media sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang iyong mga contact?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang iyong mga contact sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang lokasyon ng device na ito?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang lokasyon ng &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt; mo?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Magkakaroon lang ang app ng access sa lokasyon habang ginagamit mo ang app"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang lokasyon ng device na ito?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang lokasyon ng &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> mo?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Posibleng gustong i-access ng app na ito ang iyong lokasyon sa lahat ng oras, kahit na hindi mo ginagamit ang app. "<annotation id="link">"Payagan sa mga setting."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Baguhin ang access sa lokasyon para sa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Baguhin ang access sa lokasyon para sa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Gustong i-access ng app na ito ang iyong lokasyon sa lahat ng oras, kahit na hindi mo ginagamit ang app. "<annotation id="link">"Payagan sa mga setting."</annotation></string>
- <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na hanapin at tukuyin ang, at kumonekta sa relatibong posisyon ng mga kalapit na device?"</string>
+ <string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na maghanap, kumonekta sa, at tukuyin ang relatibong posisyon ng mga kalapit na device?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na humanap, kumonekta, at tumukoy ng posisyon ng nearby device sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na hanapin at tukuyin ang, at kumonekta sa relatibong posisyon ng mga kalapit na device? "<annotation id="link">"Payagan sa mga setting."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Gawing eksakto ang access sa lokasyon ng <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> mula sa pagiging tinatantya?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Gawing tumpak mula sa tinataya ang access sa lokasyon ng <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang tinatantyang lokasyon ng device na ito?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang tinatayang lokasyon ng &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;’s mo?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Eksakto"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Tinatantya"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang iyong kalendaryo?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang iyong kalendaryo sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na magpadala at tumingin ng mga mensaheng SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na magpadala at tumingin ng mga SMS message sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang mga larawan, media, at file sa iyong device?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang mga larawan, media, at file sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang &lt;b&gt;mga larawan, video, musika, at audio&lt;/b&gt; sa device?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang &lt;b&gt;mga larawan, video, musika, audio, at iba pang file&lt;/b&gt; sa device?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang musika at audio sa device na ito?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang musika at audio sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang mga larawan at video sa device na ito?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang mga larawan at video sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang higit pang larawan at video sa device na ito?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na mag-access ng higit pang larawan at video sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na mag-record ng audio?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na mag-record ng audio sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Makakapag-record lang ng audio ang app habang ginagamit mo ang app"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na mag-record ng audio?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na mag-record ng audio sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Posibleng gusto ng app na ito na mag-record ng audio sa lahat ng oras, kahit na hindi mo ginagamit ang app. "<annotation id="link">"Payagan sa mga setting."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Baguhin ang access sa mikropono para sa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Baguhin ang access sa mikropono para sa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Gusto ng app na ito na mag-record ng audio sa lahat ng oras, kahit na hindi mo ginagamit ang app. "<annotation id="link">"Payagan sa mga setting."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang iyong pisikal na aktibidad?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang iyong pisikal na aktibidad sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na kumuha ng larawan at mag-record ng video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na kumuha ng mga larawan at mag-record ng video sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Makakakuha lang ng mga larawan at makakapag-precord lang ng video ang app habang ginagamit mo ang app"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na kumuha ng mga larawan at mag-record ng video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na kumuha ng mga larawan at mag-record ng video sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Posibleng gusto ng app na ito na kumuha ng larawan at mag-record ng video sa lahat ng oras, kahit na hindi mo ginagamit ang app. "<annotation id="link">"Payagan sa settings."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Baguhin ang access sa camera para sa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Baguhin ang access sa camera para sa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Gusto ng app na ito na kumuha ng mga larawn at mag-record ng video sa lahat ng oras, kahit na hindi mo ginagamit ang app. "<annotation id="link">"Payagan sa mga setting."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang iyong mga log ng tawag sa telepono?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang iyong mga log ng tawag sa telepono sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na tumawag at mamahala ng mga tawag sa telepono?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na gumawa at mamahala ng mga tawag sa telepono sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang data ng sensor tungkol sa iyong mga vital sign?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang data ng sensor tungkol sa mga vital sign mo sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Gusto ng app na ito na palaging i-access ang data ng sensor tungkol sa iyong mga vital sign, kahit hindi mo ginagamit ang app. Para gawin ang pagbabagong ito, "<annotation id="link">"pumunta sa mga setting."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang data ng sensor tungkol sa iyong mga vital sign?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang data ng sensor tungkol sa mga vital sign mo sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Para pahintulutan ang app na ito na i-access ang data ng sensor ng katawan sa lahat ng oras, kahit na hindi mo ginagamit ang app, "<annotation id="link">"pumunta sa mga setting."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Patuloy na pahintulutan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang data ng sensor ng katawan habang ginagamit ang app?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na i-access ang data ng sensor ng katawan sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; habang ginagamit ito?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Payagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na padalhan ka ng mga notification?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Payagan ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na magpadala sa iyo ng mga notification sa &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; mo?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontroladong pahintulot"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"May access sa lokasyon ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Pinapayagan ng organisasyon mo ang <xliff:g id="APP_NAME">%1$s</xliff:g> na i-access ang iyong lokasyon"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Iba pang pahintulot"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Pahintulot na ginagamit ng system"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Mga pahintulot na mga application ng system lang ang gumagamit."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Isinaad ng app na ito na puwede nitong ibahagi ang data ng lokasyon sa mga third party"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Pagbabahagi ng data at lokasyon"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Saan nanggagaling ang impormasyon sa pagbabahagi ng data"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Nagbigay ang developer ng impormasyon sa manufacturer ng device na ito tungkol sa kung paano nagbabahagi ng data ang app na ito. Posibleng i-update ng developer ang impormasyong ito sa pagtagal."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Nagbigay ang developer ng impormasyon sa "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" tungkol sa kung paano nagbabahagi ng data ang app na ito. Posibleng i-update ng developer ang impormasyong ito sa paglipas ng panahon."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Puwedeng magbahagi ng data ng lokasyon para sa:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Nag-iiba ang pagbabahagi ng data"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Kaligtasan ng data"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Puwedeng ibahagi ang data ng lokasyon"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Isinaad ng app na ito na puwede nitong ibahagi ang iyong data ng lokasyon sa mga third party"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Hindi mabuksan ang link na ito"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Mga update sa pagbabahagi ng data para sa lokasyon"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Suriin ang mga app na nagbago ng paraan kung paano nila posibleng ibahagi ang iyong data ng lokasyon"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Binago ng mga app na ito ang paraan kung paano posibleng ibahagi ng mga ito ang iyong data ng lokasyon. Posibleng hindi pa nila ito ibinahagi noon, o ibinabahagi nila ito ngayon para sa mga layunin sa pag-advertise o marketing."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Update sa pagbabahagi ng data"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Binago ng ilang app kung paano posibleng ibahagi ng mga ito ang iyong data ng lokasyon"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Mga Setting"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Na-access noong <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Na-access kahapon nang <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Na-access noong <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-tr-v33/strings.xml b/PermissionController/res/values-tr-v33/strings.xml
index ddb34d1f2..d6d2e4286 100644
--- a/PermissionController/res/values-tr-v33/strings.xml
+++ b/PermissionController/res/values-tr-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Diğer uyarılar"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Reddedilen uyarılar"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Genişletip bir uyarıyı daha görün}other{Genişletip # uyarıyı daha görün}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Uyarı. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"İşlem tamamlandı"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Cihazınızın korumasını artırabilecek ayarlara göz atın"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Güvenlik ve gizlilikle ilgili hızlı ayarlar"</string>
diff --git a/PermissionController/res/values-tr/strings.xml b/PermissionController/res/values-tr/strings.xml
index 7e0c01670..b42876b27 100644
--- a/PermissionController/res/values-tr/strings.xml
+++ b/PermissionController/res/values-tr/strings.xml
@@ -34,13 +34,14 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Daha fazla bilgi"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Tümüne izin ver"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Tümüne her zaman izin ver"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Sınırlı erişime izin ver"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Fotoğraf ve video seçin"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Daha fazla seçin"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Daha fazla seçme"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Başka seçilmesin"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Yine de izin verme"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Kapat"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına <xliff:g id="ACTION">%2$s</xliff:g> için izin verilsin mi?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına <xliff:g id="ACTION">%2$s</xliff:g> izni verilsin mi?"</string>
<string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına <xliff:g id="ACTION">%2$s</xliff:g> için her zaman izin verilsin mi?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Sadece uygulama kullanılırken"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Her zaman"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Uygulamalar"</string>
<string name="app_permissions" msgid="3369917736607944781">"Uygulama izinleri"</string>
<string name="unused_apps" msgid="2058057455175955094">"Kullanılmayan uygulamalar"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Bu uygulamanın hangi fotoğraflara erişebileceğini düzenler"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Kullanılmayan uygulama yok"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Kullanılmayan 0 uygulama"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Son izin kararları"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Tüm izinler"</string>
<string name="other_permissions" msgid="2901186127193849594">"Diğer uygulama özellikleri"</string>
<string name="permission_request_title" msgid="8790310151025020126">"İzin isteği"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Yükleme/Yüklemeyi Kaldırma işlemleri Wear\'da desteklenmiyor."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının nelere erişmesine izin vereceğinizi seçin"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; güncellendi. Bu uygulamanın nelere erişmesine izin verileceğini seçin."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"İptal"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Uygulama kullanılmıyorsa izinleri kaldır"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"İzinleri kaldırıp yer aç"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Kullanılmayan uygulama etkinliğini duraklat"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Kullanılmayan uygulamayı yönet"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"İzinleri kaldır, geçici dosyaları sil ve bildirimleri durdur"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"İzinleri kaldır, geçici dosyaları sil, bildirimleri durdur ve uygulamayı arşivle"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Bu uygulama birkaç ay boyunca kullanılmazsa verilerinizi korumak için uygulamanın izinleri kaldırılır."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Uygulama birkaç ay boyunca kullanılmazsa şu izinler verilerinizi korumak için kaldırılacak: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Birkaç aydır kullanmadığınız uygulamaların izinleri verilerinizi korumak için kaldırıldı."</string>
@@ -221,7 +223,7 @@
<string name="unused_apps_page_title" msgid="6986983535677572559">"Kullanılmayan uygulamalar"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Uygulama birkaç ay kullanılmazsa:\n\n• Verilerinizi korumak için izinler kaldırılır\n• Pilden tasarruf etmek için bildirimler durdurulur\n• Yer açmak için geçici dosyalar kaldırılır\n\nİzinleri ve bildirimleri yeniden etkinleştirmek için uygulamayı açın."</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Uygulama bir ay kullanılmazsa:\n\n• Verilerinizi korumak için izinler kaldırılır\n• Yer açmak için geçici dosyalar kaldırılır\n\nİzinleri yeniden etkinleştirmek için uygulamayı açın."</string>
- <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{En son # aydan fazla bir süre önce açıldı}other{En son # aydan uzun bir süre önce açıldı}}"</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{En son # aydan uzun bir süre önce açıldı}other{En son # aydan uzun bir süre önce açıldı}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Uygulama en son <xliff:g id="DATE">%s</xliff:g> tarihinde açıldı"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"En son <xliff:g id="DATE">%s</xliff:g> tarihinde açıldı"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Tüm dosyaların yönetilmesine izin verirseniz bu uygulama, bu cihazdaki ortak depolama alanında veya bu cihaza bağlı depolama cihazlarında bulunan tüm dosyalara erişebilir, bunları değiştirebilir ve silebilir. Uygulama, size sormadan dosyalara erişebilir."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Notlar uygulaması"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Cihazınızda not almanıza olanak tanıyan uygulamalar"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"notlar"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Mevcut varsayılan"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Tekrar sorma"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Varsayılan olarak ayarla"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Yardımcı uygulama tetikleyici algılamasını göster"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Sesli yardımı etkinleştirmek için mikrofon kullanıldığında simgeyi durum çubuğunda göster"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının cihazınızdaki fotoğraf ve medya içeriğine erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki fotoğraf ve medyalara erişmesine izin verilsin mi?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının kişilerinize erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki kişilerinize erişmesine izin verilsin mi?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının bu cihazın konumuna erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt; cihazınızın konumuna erişmesine izin verilsin mi?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Bu uygulama konum bilgisine yalnızca kullanıldığı sırada erişebilecektir"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının bu cihazın konumuna erişmesine izin verilsin mi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> cihazınızın konumuna erişmesine izin verilsin mi?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Bu uygulama, kullanmadığınız sırada bile konum bilginize sürekli olarak erişmek isteyebilir. "<annotation id="link">"Ayarlar\'da izin verin."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; için konum adresi değiştirilsin mi?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki konum erişimi değiştirilsin mi?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Bu uygulama, kullanmadığınız sırada bile konum bilginize sürekli olarak erişmek isteyebilir. "<annotation id="link">"Ayarlar\'da izin verin."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına, yakındaki cihazları bulup bağlanma ve göreli konumlarını belirleme izni verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda yakındaki cihazları keşfedip bağlanma ve bu cihazların göreli konumunu belirleme izni verilsin mi?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına, yakındaki cihazları bulup bağlanma ve göreli konumlarını belirleme izni verilsin mi? "<annotation id="link">"Ayarlarda izin ver"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> uygulamasının konum erişimi, yaklaşık konumdan tam konuma değiştirilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki konum erişimi yaklaşık konum yerine tam konum olarak değiştirilsin mi?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının bu cihazın yaklaşık konumuna erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızın yaklaşık konumuna erişmesine izin verilsin mi?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Tam"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Yaklaşık"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının takviminize erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki takviminize erişmesine izin verilsin mi?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının SMS mesajları göndermesine ve görüntülemesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda SMS mesajları gönderip görmesine izin verilsin mi?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının cihazınızdaki fotoğraf, medya ve dosyalara erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda fotoğraf, medya ve dosyalara erişme izni verilsin mi?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; için bu cihazdaki &lt;b&gt;fotoğraf, video, müzik ve ses dosyalarına&lt;/b&gt; erişim verilsin mi?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; için cihazdaki &lt;b&gt;fotoğraf, video, müzik, ses vb. dosyalara&lt;/b&gt; erişim verilsin mi?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının bu cihazda müzik ve ses dosyalarına erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda müzik ve ses dosyalarına erişmesine izin verilsin mi?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının bu cihazdaki fotoğraf ve videolara erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki fotoğraf ve videolara erişmesine izin verilsin mi?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının bu cihazdaki diğer fotoğraf ve videolara erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki diğer fotoğraf ve videolara erişme izni verilsin mi?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının ses kaydetmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda ses kaydetmesine izin verilsin mi?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Bu uygulama, yalnızca kullanıldığı sırada ses kaydedebilir"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının ses kaydetmesine izin verilsin mi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda ses kaydetmesine izin verilsin mi?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Bu uygulama, kullanmadığınız sırada bile sürekli olarak ses kaydetmek isteyebilir. "<annotation id="link">"Ayarlar\'da izin verin."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; için mikrofon erişimi değiştirilsin mi?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki mikrofon erişimi değiştirilsin mi?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Bu uygulama, kullanmadığınız sırada bile sürekli olarak ses kaydetmek istiyor. "<annotation id="link">"Ayarlar\'da izin verin."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına fiziksel aktivitenize erişme izni verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki fiziksel aktivitenize erişmesine izin verilsin mi?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının fotoğraf çekmesine ve video kaydı yapmasına izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda resim çekip video kaydetmesine izin verilsin mi?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Bu uygulama, yalnızca kullanıldığı sırada resim çekebilir veya video kaydedebilir"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının resim çekmesine ve video kaydı yapmasına izin verilsin mi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda resim çekip video kaydetmesine izin verilsin mi?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Bu uygulama, kullanmadığınız sırada bile sürekli olarak resim çekmek ve video kaydetmek isteyebilir. "<annotation id="link">"Ayarlar\'da izin verin."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; için kamera erişimi değiştirilsin mi?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki kamera erişimi değiştirilsin mi?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Bu uygulama, kullanmadığınız sırada bile sürekli olarak resim çekmek ve video kaydetmek istiyor. "<annotation id="link">"Ayarlar\'da izin verin."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının telefon arama kayıtlarınıza erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki telefon arama kaydına erişmesine izin verilsin mi?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının telefon etmesine ve aramaları yönetmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda telefon edip aramaları yönetmesine izin verilsin mi?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının hayati belirtilerinizle ilgili sensör verilerine erişmesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki hayati bulgularla ilgili sensör verilerine erişmesine izin verilsin mi?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Bu uygulama, kullanmadığınız sırada bile hayati belirtilerinizle ilgili sensör verilerine sürekli olarak erişmek istiyor. Bu değişikliği yapmak için "<annotation id="link">"ayarlara gidin."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının hayati belirtilerinizle ilgili sensör verilerine erişmesine izin verilsin mi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızdaki hayati bulgularla ilgili sensör verilerine erişmesine izin verilsin mi?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Bu uygulamanın, kullanmadığınız sırada bile vücut sensörü verilerine sürekli olarak erişmesine izin vermek için "<annotation id="link">"ayarlara gidin."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının kullanımdayken vücut sensörü verilerine erişme izni sürdürülsün mü?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının kullanımdayken &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazındaki vücut sensörü verilerine erişme izni sürdürülsün mü?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının size bildirim göndermesine izin verilsin mi?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının, &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; cihazınızda size bildirim göndermesine izin verilsin mi?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontrol edilen izinler"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> konuma erişebiliyor"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Kuruluşunuz <xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının konumunuza erişmesine izin veriyor"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Diğer izinler"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Sistem tarafından kullanılan izinler"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Yalnızca sistem uygulamaları tarafından kullanılan izinler."</string>
@@ -585,12 +622,13 @@
<string name="mic_toggle_description" msgid="9163104307990677157">"Uygulamalar ve hizmetler için. Bu ayar kapalıyken bir acil durum numarasını aradığınızda mikrofon verileri paylaşılmaya devam edilebilir."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Konum erişimi olan uygulama ve hizmetlere göz atın."</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Panoya erişimi göster"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Uygulamalar kopyaladığınız metne, resimlere veya diğer içeriklere eriştiğinde mesaj gösterilsin."</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Uygulamalar kopyaladığınız metne, resimlere veya diğer içeriklere eriştiğinde mesaj gösterilsin"</string>
<string name="show_password_title" msgid="2877269286984684659">"Şifreleri göster"</string>
<string name="show_password_summary" msgid="1110166488865981610">"Yazarken karakterleri kısa süreliğine göster"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Bu uygulama, konum verilerini üçüncü taraflarla paylaşabileceğini belirtti"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Veri paylaşımı ve konum"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Veri paylaşımı bilgilerinin kaynağı"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Geliştirici, bu cihazın üreticisine bu uygulamanın veri paylaşım yöntemleri hakkında bilgi sağladı. Geliştirici bu bilgiyi zaman içinde güncelleyebilir."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Geliştirici, "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" uygulama mağazasına bu uygulamanın veri paylaşımı yöntemleri hakkında bilgi sağladı. Geliştirici bu bilgiyi zaman içinde güncelleyebilir."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Bu uygulama, konum verilerini paylaşabilir:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Veri paylaşımı değişir"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Veri güvenliği"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Konum verileri paylaşılabilir"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Bu uygulama, konum verilerinizi üçüncü taraflarla paylaşabileceğini belirtti"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Bu bağlantı açılamıyor"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Konum için veri paylaşımı güncellemeleri"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Konum verilerinizi paylaşma şekillerini değiştiren uygulamaları inceleyin"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Bu uygulamalar, konum verilerinizi paylaşma şekillerini değiştirdi. Daha önce paylaşmadıkları konum verilerinizi paylaşmaya başlamış olabilecekleri gibi reklam ya da pazarlama için paylaşmaya başlamış da olabilirler."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Veri paylaşımı güncellemeleri"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Bazı uygulamalar, konum verilerinizi paylaşma şeklini değiştirdi"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Ayarlar"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Erişim zamanı: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Dün saat <xliff:g id="TIME_DATE">%1$s</xliff:g> itibarıyla erişildi"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Erişim tarihi: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-uk-v33/strings.xml b/PermissionController/res/values-uk-v33/strings.xml
index 5ea1b68cb..0066766f5 100644
--- a/PermissionController/res/values-uk-v33/strings.xml
+++ b/PermissionController/res/values-uk-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Більше сповіщень"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Закриті сповіщення"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Розгорніть і перегляньте ще одне сповіщення}one{Розгорніть і перегляньте ще # сповіщення}few{Розгорніть і перегляньте ще # сповіщення}many{Розгорніть і перегляньте ще # сповіщень}other{Розгорніть і перегляньте ще # сповіщення}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Сповіщення. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Дію виконано"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Перевірте налаштування, які можуть посилити захист вашого пристрою"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Швидкі налаштування безпеки й конфіденційності"</string>
diff --git a/PermissionController/res/values-uk-v34/strings.xml b/PermissionController/res/values-uk-v34/strings.xml
index 30c8e75b9..5d14c8ebe 100644
--- a/PermissionController/res/values-uk-v34/strings.xml
+++ b/PermissionController/res/values-uk-v34/strings.xml
@@ -18,10 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="security_privacy_brand_name" msgid="7303621734258440812">"Безпека й конфіденційність"</string>
- <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Елементи керування"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Параметри"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
- <string name="health_connect_summary" msgid="815473513776882296">"Керуйте доступом додатка до даних про здоров’я"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Керуйте доступом додатків до даних про здоров’я"</string>
<string name="location_settings" msgid="8863940440881290182">"Доступ до геоданих"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Для додатків і сервісів. Якщо це налаштування вимкнено, дані мікрофона можуть усе одно передаватися під час виклику екстреного номера"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Для додатків і сервісів. Якщо це налаштування вимкнено, дані мікрофона можуть усе одно передаватися під час виклику екстреного номера."</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"Для додатків і сервісів"</string>
</resources>
diff --git a/PermissionController/res/values-uk/strings.xml b/PermissionController/res/values-uk/strings.xml
index ab9258484..801248a3d 100644
--- a/PermissionController/res/values-uk/strings.xml
+++ b/PermissionController/res/values-uk/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Докладніше"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Дозволити всі"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Завжди дозволяти всі"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Дозволити обмежений доступ"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Вибрати фото й відео"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Вибрати ще"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Не вибирати більше"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Усе одно не дозволяти"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Закрити"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> з <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; таке: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Завжди дозволяти додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; таке: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Завжди дозволяти додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Лише коли додаток активний"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Завжди"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Не дозволяти й більше не запитувати"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Додатки"</string>
<string name="app_permissions" msgid="3369917736607944781">"Дозволи додатка"</string>
<string name="unused_apps" msgid="2058057455175955094">"Непотрібні додатки"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Змінити вибрані фотографії для цього додатка"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Усі додатки використовуються"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 додатків не використовуються"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Останні рішення щодо дозволів"</string>
@@ -71,7 +73,7 @@
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{Сьогодні}=1{1 день тому}one{# день тому}few{# дні тому}many{# днів тому}other{# дня тому}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"Вимкнути додаток"</string>
<string name="app_disable_dlg_text" msgid="3126943217146120240">"Якщо вимкнути цей додаток, система Android та інші додатки можуть працювати неналежним чином. Важливо: ви не можете видалити цей додаток, оскільки він був попередньо встановлений на пристрої. Вимкнений додаток буде приховано."</string>
- <string name="app_permission_manager" msgid="3903811137630909550">"Диспетчер дозволів"</string>
+ <string name="app_permission_manager" msgid="3903811137630909550">"Менеджер дозволів"</string>
<string name="never_ask_again" msgid="4728762438198560329">"Більше не запитувати"</string>
<string name="no_permissions" msgid="3881676756371148563">"Немає дозволів"</string>
<string name="additional_permissions" msgid="5801285469338873430">"Додаткові дозволи"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Усі дозволи"</string>
<string name="other_permissions" msgid="2901186127193849594">"Інші дозволи додатка"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Запит на дозвіл"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Встановлення й видалення не підтримуються на пристроях Android Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Виберіть, до чого додаток &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; матиме доступ"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Додаток &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; оновлено. Виберіть, до чого він матиме доступ."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Скасувати"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Відкликати дозволи, якщо додаток не використовується"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Вилучати дозволи й звільняти місце"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Призупиняти роботу в неактивний період"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Керувати невикористовуваним додатком"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Вилучити дозволи, видалити тимчасові файли та зупинити сповіщення"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Вилучити дозволи, видалити тимчасові файли, зупинити сповіщення й архівувати додаток"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Щоб захистити ваші дані, дозволи для цього додатка буде автоматично скасовано, якщо ви не будете користуватися ним кілька місяців."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Якщо додаток не використовується впродовж кількох місяців, для захисту ваших даних буде скасовано такі дозволи: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Щоб захистити ваші дані, було скасовано дозволи додатків, які не використовувалися впродовж кількох місяців."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Додаток для нотаток"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Додатки, у яких можна робити нотатки на вашому пристрої"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"нотатки"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Поточний за умовчанням"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Не запитувати знову"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Вибрати за умовчанням"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Показувати значок очікування активатора асистента"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Показувати значок у рядку стану, коли мікрофон працює в режимі очікування активатора голосового помічника"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до фото й медіа на пристрої?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до фото й медіаконтенту на &lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до контактів на &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"Дозволити додатку &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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Дозволити додатку &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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Додаток може запитувати доступ до ваших геоданих, навіть коли ви не використовуєте його. Дозвіл можна надати в "<annotation id="link">"налаштуваннях"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Змінити доступ до геоданих для додатка &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Змінити налаштування доступу до геоданих для додатка &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Додаток хоче завжди отримувати доступ до ваших геоданих, навіть коли ви не використовуєте його. Дозвіл можна надати в "<annotation id="link">"налаштуваннях"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Дозволити додатку <xliff:g id="APP_NAME">%1$s</xliff:g> знаходити пристрої поблизу, підключатися до них і визначати їх відносне розташування?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; знаходити пристрої поблизу, підключатися до них і визначати їх відносне розташування на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Дозволити додатку <xliff:g id="APP_NAME">%1$s</xliff:g> знаходити пристрої поблизу, підключатися до них і визначати їх відносне розташування? "<annotation id="link">"Дозвольте в налаштуваннях."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Змінити доступ до місцезнаходження для додатка <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> з приблизного на точне?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Змінити доступ до місцезнаходження для додатка <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> на &lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до приблизного місцезнаходження &lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до календаря на &lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; надсилати й переглядати SMS на &lt;b&gt;<xliff:g id="DEVICE">%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="872629037299467086">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до фото, медіаконтенту й файлів на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Надати додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до &lt;b&gt;фото, відео, музики й аудіо&lt;/b&gt; на цьому пристрої?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Надати додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до &lt;b&gt;фото, відео, музики, аудіо й інших файлів&lt;/b&gt; на пристрої?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Надати додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до музики й аудіофайлів на цьому пристрої?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до музики й аудіо на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Надати додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до фотографій і відео на цьому пристрої?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до фото й відео на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до інших фото й відео на цьому пристрої?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до інших фото й відео на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записувати аудіо?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записувати звук на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Додаток зможе записувати звук, лише коли ви використовуєте його"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записувати звук?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записувати звук на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Цей додаток може записувати звук, навіть коли ви не використовуєте його. Дозвіл можна надати в "<annotation id="link">"налаштуваннях"</annotation>"."</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Змінити налаштування доступу до мікрофона для додатка &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Змінити налаштування доступу до мікрофона для додатка &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Цей додаток може записувати звук, навіть коли ви не використовуєте його. Дозвіл можна надати в "<annotation id="link">"налаштуваннях"</annotation>"."</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Надати додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до даних про фізичну активність?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до даних про фізичну активність на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; робити знімки та записувати відео?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; робити знімки й записувати відео на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Додаток зможе робити фотографії та записувати відео, лише коли ви використовуєте його"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; робити знімки й записувати відео?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; робити знімки й записувати відео на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Цей додаток може робити фотографії та записувати відео, навіть коли ви не використовуєте його. Дозвіл можна надати в "<annotation id="link">"налаштуваннях"</annotation>"."</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Змінити налаштування доступу до камери для додатка &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Змінити налаштування доступу до камери для додатка &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Цей додаток може робити фотографії та записувати відео, навіть коли ви не використовуєте його. Дозвіл можна надати в "<annotation id="link">"налаштуваннях"</annotation>"."</string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до журналів викликів телефона?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до журналів викликів на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; здійснювати телефонні дзвінки та керувати ними?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; здійснювати телефонні дзвінки й керувати ними на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Надати додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до життєвих показників із датчиків?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до життєвих показників від датчиків на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Цей додаток хоче постійно отримувати дані життєвих показників від датчиків, навіть коли ви не використовуєте його. Щоб внести зміни, "<annotation id="link">"перейдіть у налаштування"</annotation>"."</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до життєвих показників із датчиків?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до життєвих показників від датчиків на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Щоб надати додатку постійний доступ до показників датчиків на тілі, навіть коли він не використовується, "<annotation id="link">"перейдіть у налаштування"</annotation>"."</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Надавати й надалі додатку <xliff:g id="APP_NAME">%1$s</xliff:g> доступ до показників датчиків на тілі, коли він використовується?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Дозволяти й надалі додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ до показників датчиків на тілі на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;, коли додаток використовується?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; надсилати вам сповіщення?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Дозволити додатку &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; надсилати вам сповіщення на &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Керовані дозволи"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> має доступ до геоданих"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Ваша організація надає додатку <xliff:g id="APP_NAME">%1$s</xliff:g> доступ до ваших геоданих"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Інші дозволи"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Дозволи, які використовує система"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Дозволи, які використовують лише системні додатки."</string>
@@ -515,7 +552,7 @@
<string name="privdash_label_24h" msgid="1512532123865375319">"Минулі\n24 години"</string>
<string name="privdash_label_7d" msgid="5645301995348656931">"Останні\n7 днів"</string>
<string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> захищено системою Android. Оскільки ваші дані обробляються на цьому пристрої, дозволи, які використовує цей додаток, не відображаються на панелі керування дозволами чи в рядку стану."</string>
- <string name="exempt_info_label" msgid="6286190981253476699">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> захищено системою Android. Оскільки ваші дані обробляються на цьому пристрої, дозволи, які використовує цей додаток, не відображаються на панелі керування дозволами чи в рядку стану."</string>
+ <string name="exempt_info_label" msgid="6286190981253476699">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> захищено системою Android. Оскільки ваші дані обробляються на цьому пристрої, дозволи, які використовує цей додаток, не відображаються на панелі керування дозволами."</string>
<string name="blocked_camera_title" msgid="1128510551791284384">"Камеру пристрою заблоковано"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"Мікрофон пристрою заблоковано"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"Геодані пристрою вимкнено"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Цей додаток зазначає, що може передавати дані про місцезнаходження третім особам"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Передавання даних і місцезнаходження"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Звідки надходить інформація про передавання даних"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Розробник надав виробнику цього пристрою інформацію про те, як цей додаток передає дані. Розробник може періодично оновлювати цю інформацію."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Розробник надав "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" інформацію про те, як цей додаток передає дані. Розробник може періодично оновлювати цю інформацію."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Цілі передавання геоданих цим додатком"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Спосіб передавання даних може різнитися"</string>
@@ -608,9 +646,7 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Безпека даних"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Можуть передаватися геодані"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Цей додаток повідомляє, що може передавати ваші геодані третім особам"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Не вдається відкрити це посилання"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
- <string name="data_sharing_updates_title" msgid="7996933386875213859">"Оновлення способу передавання геоданих"</string>
+ <string name="data_sharing_updates_title" msgid="7996933386875213859">"Зміни в передаванні геоданих"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Перегляньте додатки, які змінили спосіб передавання ваших геоданих"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Ці додатки змінили спосіб передавання ваших геоданих. Можливо, ваші дані раніше не передавалися або тепер вони можуть використовуватися для реклами й маркетингу."</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Розробники надали магазину додатків інформацію про свої методи передавання даних. Вони можуть періодично вносити зміни в цю інформацію.\n\nМетоди передавання даних можуть різнитися залежно від версії додатка, його використання, регіону й віку користувача."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Оновлення способу передавання даних"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Деякі додатки змінили спосіб передавання ваших геоданих"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Налаштування"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Доступ отримано: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Доступ отримано вчора: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Доступ отримано: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-ur-v33/strings.xml b/PermissionController/res/values-ur-v33/strings.xml
index b3bcc412d..0a56dd190 100644
--- a/PermissionController/res/values-ur-v33/strings.xml
+++ b/PermissionController/res/values-ur-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"مزید الرٹس"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"برخاست کردہ الرٹس"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{پھیلائیں اور ایک اور الرٹ دیکھیں}other{پھیلائیں اور # مزید الرٹس دیکھیں}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"الرٹ۔ <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"کارروائی مکمل ہو گئی"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"اپنے آلہ کو تحفظ دینے والی ترتیبات چیک کریں"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"سیکیورٹی اور رازداری کی فوری ترتیبات"</string>
diff --git a/PermissionController/res/values-ur/strings.xml b/PermissionController/res/values-ur/strings.xml
index c0f7022dd..e3666865e 100644
--- a/PermissionController/res/values-ur/strings.xml
+++ b/PermissionController/res/values-ur/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"مزید معلومات"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"سبھی کو اجازت دیں"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"ہمیشہ سبھی کو اجازت دیں"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"محدود رسائی کی اجازت دیں"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"تصاویر اور ویڈیوز منتخب کریں"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"مزید منتخب کریں"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"مزید منتخب نہ کریں"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"ایپس"</string>
<string name="app_permissions" msgid="3369917736607944781">"ایپ کی اجازتیں"</string>
<string name="unused_apps" msgid="2058057455175955094">"غیر مستعمل ایپس"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"منتخب کریں کہ کن تصاویر تک اس ایپ کو رسائی ہوگی"</string>
<string name="no_unused_apps" msgid="12809387670415295">"کوئی غیر مستعمل ایپ نہیں ہے"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 غیر مستعمل ایپس"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"اجازت کے حالیہ فیصلے"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"تمام اجازتیں"</string>
<string name="other_permissions" msgid="2901186127193849594">"ایپ کی دوسری اہلیتیں"</string>
<string name="permission_request_title" msgid="8790310151025020126">"اجازت کی درخواست"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"‏\'کارروائیاں انسٹال/اَن انسٹال کریں\' Wear پر تعاون یافتہ نہیں ہے۔"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"‏منتخب کریں کہ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو کس چیز تک رسائی کی اجازت دینی ہے"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; اپ ڈیٹ ہو گئی ہے۔ منتخب کریں کہ اس ایپ کو کس تک رسائی کی اجازت دینی ہے۔"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"منسوخ کریں"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"ایپ کے استعمال نہ ہونے پر اجازتیں ہٹائیں"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"اجازتوں کو ہٹائیں اور جگہ خالی کریں"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"غیر استعمال شدہ ہو تو ایپ سرگرمی روکیں"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"اگر غیر استعمال شدہ ہے تو ایپ کا نظم کریں"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"اجازتیں ہٹائیں، عارضی فائلز حذف کریں اور اطلاعات موقوف کریں"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"اجازتیں ہٹائیں، عارضی فائلوں کو حذف کریں، اطلاعات کو روکیں اور ایپ کو آرکائیو کریں"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"آپ کے ڈیٹا کی حفاظت کے لیے، اگر ایپ کو کچھ مہینوں تک استعمال نہیں کیا گیا تو اس ایپ کے لیے اجازتیں ہٹا دی جائیں گی۔"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"آپ کے ڈیٹا کی حفاظت کے لیے، اگر ایپ کو کچھ مہینوں تک استعمال نہیں کیا گيا تو درج ذیل اجازتیں ہٹا دی جائیں گی: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"آپ کے ڈیٹا کی حفاظت کے لیے، اجازتوں کو ان ایپس سے ہٹا دیا گیا ہے جنہیں آپ نے کچھ مہینوں سے استعمال نہیں کیا ہے۔"</string>
@@ -367,12 +369,12 @@
<string name="role_sms_request_title" msgid="7953552109601185602">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی ڈیفالٹ SMS ایپ کے بطور سیٹ کریں؟"</string>
<string name="role_sms_request_description" msgid="2691004766132144886">"‏اس ایپ کو آپ کے کیمرا، رابطوں، فائلز اور میڈیا، مائیکروفون، فون اور SMS تک رسائی دی جائے گی"</string>
<string name="role_sms_search_keywords" msgid="8022048144395047352">"ٹیکسٹ پیغام، پیغام بھیجنا، پیغامات، پیغام رسانی"</string>
- <string name="role_emergency_label" msgid="7028825857206842366">"ڈیفالٹ ہنگامی ایپ"</string>
- <string name="role_emergency_short_label" msgid="2388431453335350348">"ہنگامی ایپ"</string>
- <string name="role_emergency_description" msgid="5051840234887686630">"وہ ایپس جو آپ کو آپ کی طبی معلومات ریکارڈ کرنے اور اسے ہنگامی طبی مدد فراہم کنندگان کے لیے قابل رسائی بنانے؛ خطرناک موسمی واقعات اور آفات کے بارے میں الرٹس حاصل کرنے؛ آپ کو مدد درکار ہونے پر دوسروں کو اطلاع دینے کی اجازت دیتی ہیں"</string>
- <string name="role_emergency_request_title" msgid="8469579020654348567">"<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی ڈیفالٹ ہنگامی ایپ کے بطور سیٹ کریں؟"</string>
+ <string name="role_emergency_label" msgid="7028825857206842366">"ڈیفالٹ ایمرجنسی ایپ"</string>
+ <string name="role_emergency_short_label" msgid="2388431453335350348">"ایمرجنسی ایپ"</string>
+ <string name="role_emergency_description" msgid="5051840234887686630">"وہ ایپس جو آپ کو آپ کی طبی معلومات ریکارڈ کرنے اور اسے ایمرجنسی طبی مدد فراہم کنندگان کے لیے قابل رسائی بنانے؛ خطرناک موسمی واقعات اور آفات کے بارے میں الرٹس حاصل کرنے؛ آپ کو مدد درکار ہونے پر دوسروں کو اطلاع دینے کی اجازت دیتی ہیں"</string>
+ <string name="role_emergency_request_title" msgid="8469579020654348567">"<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی ڈیفالٹ ایمرجنسی ایپ کے بطور سیٹ کریں؟"</string>
<string name="role_emergency_request_description" msgid="131645948770262850">"کوئی اجازت درکار نہیں ہے"</string>
- <string name="role_emergency_search_keywords" msgid="1920007722599213358">"ہنگامی، آئس، ایپ، ڈیفالٹ"</string>
+ <string name="role_emergency_search_keywords" msgid="1920007722599213358">"ایمرجنسی، آئس، ایپ، ڈیفالٹ"</string>
<string name="role_home_label" msgid="3871847846649769412">"ڈیفالٹ ہوم ایپ"</string>
<string name="role_home_short_label" msgid="8544733747952272337">"ہوم ایپ"</string>
<string name="role_home_description" msgid="7997371519626556675">"‏وہ ایپس، جنہیں اکثر لانچرز کہا جاتا ہے، جو آپ کے Android آلہ پر ہوم اسکرینز کی جگہ لے لیتی ہیں اور آپ کے آلہ کے مواد اور خصوصیات تک آپ کو رسائی فراہم کرتی ہیں"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"نوٹس ایپ"</string>
<string name="role_notes_description" msgid="8496852798616883551">"ایسی ایپس جو آپ کو آپ کے آلے پر نوٹس لینے کی اجازت دیتی ہیں"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"نوٹس"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"موجودہ ڈیفالٹ"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"دوبارہ نہ پوچھیں"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"بطور ڈیفالٹ سیٹ کریں"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"اسسٹنٹ ٹریگر کا پتہ لگانا دکھائیں"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"جب صوتی معاون کو فعال کرنے کے لیے مائیکروفون کا استعمال کیا جائے تو اسٹیٹس بار میں آئیکن دکھائیں"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"‏‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎ کو آپ کے آلہ پر تصاویر اور میڈیا تک رسائی کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%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="2270563860206654757">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"‏&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"‏&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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"ممکن ہے یہ ایپ ہر وقت آپ کے مقام تک رسائی حاصل کرنا چاہے، اگرچہ آپ ایپ استعمال نہ کر رہے ہوں۔ "<annotation id="link"></annotation>"ترتیبات میں اجازت دیں۔"</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کے ليے مقام تک رسائی تبدیل کریں"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"‏آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"یہ ایپ ہر وقت آپ کے مقام تک رسائی حاصل کرنا چاہتی ہے، اگرچہ آپ ایپ استعمال نہ کر رہے ہوں۔ "<annotation id="link"></annotation>"ترتیبات میں اجازت دیں۔"</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"‏‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎ کو قریبی آلات تلاش کرنے، ان سے منسلک ہونے اور ان کی متعلقہ پوزیشن کا تعین کرنے کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر قریبی آلات کی متعلقہ پوزیشن تلاش کرنے، ان سے منسلک ہونے اور اس کا تعین کرنے کی اجازت دیں؟"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"‏‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎ کو قریبی آلات تلاش کرنے، ان سے منسلک ہونے اور ان کی متعلقہ پوزیشن کا تعین کرنے کی اجازت دیں؟ "<annotation id="link">"ترتیبات میں اجازت دیں۔"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> کے مقام تک رسائی کو تخمینی سے قطعی میں تبدیل کریں؟"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"‏آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%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="9001956706241104626">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%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_device_aware_sms" msgid="7212083972999874267">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر SMS پیغامات بھیجنے اور دیکھنے کی اجازت دیں؟؟"</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="872629037299467086">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر تصاویر، میڈیا اور فائلز تک رسائی کی اجازت دیں؟"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"‏اس آلے پر &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو &lt;b&gt;تصاویر، ویڈیوز، موسیقی اور آڈیو&lt;/b&gt; تک رسائی کی اجازت دیں؟"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"‏اس آلے پر &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو &lt;b&gt;تصاویر، ویڈیوز، موسیقی، آڈیو اور دیگر فائلز&lt;/b&gt; تک رسائی کی اجازت دیں؟"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"‏اس آلے پر &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو موسیقی اور آڈیو تک رسائی کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر موسیقی اور آڈیو تک رسائی کی اجازت دیں؟"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"‏اس آلے پر &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو تصاویر اور ویڈیوز تک رسائی کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر تصاویر اور ویڈیوز تک رسائی کی اجازت دیں؟"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"‏‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎ کو اس آلے پر مزید تصاویر اور ویڈیوز تک رسائی کی اجازت دیں؟"</string>
- <string name="permgrouprequest_microphone" msgid="2825208549114811299">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آڈیو ریکارڈ کرنے کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر مزید تصاویر اور ویڈیوز تک رسائی کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_microphone" msgid="2825208549114811299">"‏آڈیو ریکارڈ کرنے کے لیے &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر آڈیو ریکارڈ کرنے کی اجازت دیں؟"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"جب آپ ایپ استعمال کر رہے ہوں تب ایپ صرف آڈیو ریکارڈ کر پائے گی"</string>
- <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آڈیو ریکارڈ کرنے کی اجازت دیں؟"</string>
+ <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"‏آڈیو ریکارڈ کرنے کے لیے &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو اجازت دیں؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر آڈیو ریکارڈ کرنے کی اجازت دیں؟"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"ممکن ہے یہ ایپ ہر وقت آڈیو ریکارڈ کرنا چاہے، اگرچہ آپ ایپ استعمال نہ کر رہے ہوں۔ "<annotation id="link">"ترتیبات میں اجازت دیں۔"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;? کے ليے مائیکروفون تک رسائی تبدیل کریں؟"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"‏آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"یہ ایپ ہر وقت آڈیو ریکارڈ کرنا چاہتی ہے، اگرچہ آپ ایپ استعمال نہ کر رہے ہوں۔ "<annotation id="link">"ترتیبات میں اجازت دیں۔"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"‏‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;b&gt;‎ کو آپ کی جسمانی سرگرمی کی شناخت کرنے کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر آپ کی جسمانی سرگرمی تک رسائی کی اجازت دیں؟"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو تصاویر لینے اور ویڈیو ریکارڈ کرنے کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر تصاویر لینے اور ویڈیو ریکارڈ کرنے کی اجازت دیں؟"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"جب آپ ایپ استعمال کر رہے ہوں تب ایپ صرف تصاویر لے سکے گی اور ویڈیوز ریکارڈ کر پائے گی"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو تصاویر لینے اور ویڈیو ریکارڈ کرنے کی اجازت دیں؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر تصاویر لینے اور ویڈیو ریکارڈ کرنے کی اجازت دیں؟"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"ممکن ہے یہ ایپ ہر وقت تصاویر لینا اور ویڈیو ریکارڈ کرنا چاہے، اگرچہ آپ ایپ استعمال نہ کر رہے ہوں۔ "<annotation id="link">"ترتیبات میں اجازت دیں۔"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;? کے ليے کیمرا تک رسائی تبدیل کریں؟"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"‏آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"یہ ایپ ہر وقت تصاویر لینا اور ویڈیو ریکارڈ کرنا چاہتی ہے، اگرچہ آپ ایپ استعمال نہ کر رہے ہوں۔ "<annotation id="link">"ترتیبات میں اجازت دیں۔"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"‏‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎ کو آپ کے فون کال لاگز تک رسائی کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر آپ کے فون کال لاگز تک رسائی کی اجازت دیں؟"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"‏&lt;/b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو فون کالز کرنے اور ان کا نظم کرنے کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر فون کالز کرنے اور ان کا نظم کرنے کی اجازت دیں؟"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے اہم اشاروں کے متعلق سینسر ڈیٹا تک رسائی کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر آپ کی علامات حیات کے بارے میں سینسر ڈیٹا تک رسائی کی اجازت دیں؟"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"آپ کے ایپ کا استعمال نہ کرنے کے باوجود یہ ایپ ہر وقت آپ کے اہم علامتوں کے متعلق سینسر ڈیٹا تک رسائی حاصل کرنا چاہتی ہے۔ یہ تبدیلی کرنے کے لیے "<annotation id="link">"ترتیبات پر جائیں۔"</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے اہم اشاروں کے متعلق سینسر ڈیٹا تک رسائی کی اجازت دیں؟"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر آپ کی علامات حیات کے بارے میں سینسر ڈیٹا تک رسائی کی اجازت دیں؟"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"آپ کے ایپ کا استعمال نہ کرنے کے باوجود اس ایپ کو ہر وقت باڈی سینسر ڈیٹا تک رسائی کی اجازت دینے کے لیے "<annotation id="link">"ترتیبات پر جائیں۔"</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"‏ایپ کے استعمال میں ہونے کے دوران ‎&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;‎ کو باڈی سینسر ڈیٹا تک رسائی کی اجازت دینا جاری رکھیں؟"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"‏ایپ کے استعمال کے دوران &lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;/b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر باڈی سینسر ڈیٹا تک رسائی کی اجازت دینا جاری رکھیں؟"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>‏&lt;/b&gt; کو آپ کو اطلاعات بھیجنے کی اجازت دیں؟"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"‏&lt;b&gt;‏<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; کو آپ کے &lt;b&gt;‏<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; پر اطلاعات بھیجنے کی اجازت دیں؟"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"کنٹرول کی گئی اجازتیں"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے پاس مقام تک رسائی حاصل ہے"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"آپ کی تنظیم <xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کے مقام تک رسائی کی اجازت دیتی ہے"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"دیگر اجازتیں"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"سسٹم کے ذریعے استعمال کردہ اجازتیں"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"صرف سسٹم ایپلیکیشنز کے ذریعے استعمال کردہ اجازتیں۔"</string>
@@ -549,7 +586,7 @@
<string name="active_call_usage_qs" msgid="8559974395932523391">"فون کال کے ذریعے استعمال کیا جا رہا ہے"</string>
<string name="recent_call_usage_qs" msgid="743044899599410935">"فون کال میں حال ہی میں استعمال کیا گیا"</string>
<string name="active_app_usage_qs" msgid="4063912870936464727">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے ذریعے استعمال کیا جا رہا ہے"</string>
- <string name="recent_app_usage_qs" msgid="6650259601306212327">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے ذریعے حال ہی میں استعمال کیا گیا"</string>
+ <string name="recent_app_usage_qs" msgid="6650259601306212327">"حال ہی میں <xliff:g id="APP_NAME">%1$s</xliff:g> نے استعمال کیا"</string>
<string name="active_app_usage_1_qs" msgid="4325136375823357052">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) کے ذریعے استعمال کیا جا رہا ہے"</string>
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) کے ذریعے حال ہی میں استعمال کیا گیا"</string>
<string name="active_app_usage_2_qs" msgid="6107866785243565283">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) کے ذریعے استعمال کیا جا رہا ہے"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"اس ایپ نے بتایا ہے کہ یہ مقام کے ڈیٹا کا اشتراک فریقین ثالث کے ساتھ کر سکتی ہے"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"ڈیٹا کا اشتراک اور مقام"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"ڈیٹا کے اشتراک کی معلومات کا ذریعہ"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"ڈویلپر نے اس آلہ کے مینوفیکچرر کو معلومات فراہم کی کہ یہ ایپ ڈیٹا کا اشتراک کیسے کرتی ہے۔ ڈویلپر وقت کے ساتھ اس معلومات کو اپ ڈیٹ کر سکتا ہے۔"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"‏ڈویلپر نے "<annotation id="link"><annotation id="install_source" example="App Store">"‏%1$s"</annotation></annotation>" کو معلومات فراہم کی کہ یہ ایپ ڈیٹا کا اشتراک کیسے کرتی ہے۔ ڈویلپر وقت کے ساتھ اس معلومات کو اپ ڈیٹ کر سکتا ہے۔"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"یہ ایپ ذیل کے لیے مقام کے ڈیٹا کا اشتراک کر سکتی ہے:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"ڈیٹا کا اشتراک مختلف ہوتا ہے"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"ڈیٹا کی حفاظت"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"مقام کے ڈیٹا کا اشتراک کیا جا سکتا ہے"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"اس ایپ نے بتایا ہے کہ یہ آپ کے مقام کے ڈیٹا کا اشتراک فریقین ثالث کے ساتھ کر سکتی ہے"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"اس لنک کو کھولا نہیں جا سکتا"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"مقام کیلئے ڈیٹا کے اشتراک کی اپ ڈیٹس"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"ان ایپس کا جائزہ لیں جنہوں نے آپ کے مقام کے ڈیٹا کے اشتراک کے اپنے ممکنہ طریقے کو تبدیل کر دیا"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"ان ایپس نے آپ کے مقام کے ڈیٹا کے اشتراک کے اپنے ممکنہ طریقے کو تبدیل کر دیا ہے۔ ہو سکتا ہے کہ انہوں نے پہلے اس کا اشتراک نہ کیا ہو یا ممکنہ طور پر اب تشہیر یا مارکیٹنگ کے مقاصد کے لیے اس کا اشتراک کر سکتی ہیں۔"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"ڈیٹا کے اشتراک کی اپ ڈیٹس"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"کچھ ایپس نے آپ کے مقام کے ڈیٹا کے اشتراک کے اپنے ممکنہ طریقے کو تبدیل کر دیا"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"ترتیبات"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g> پر رسائی حاصل کی گئی"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"گزشتہ کل <xliff:g id="TIME_DATE">%1$s</xliff:g> پر رسائی حاصل کی گئی"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g> پر رسائی حاصل کی گئی"</string>
</resources>
diff --git a/PermissionController/res/values-uz-v33/strings.xml b/PermissionController/res/values-uz-v33/strings.xml
index 45b7b7248..a32387c37 100644
--- a/PermissionController/res/values-uz-v33/strings.xml
+++ b/PermissionController/res/values-uz-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Boshqa ogohlantirishlar"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Ogohlantirishlar yopildi"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Kengaytirish va yana bitta ogohlantirishni ochish}other{Kengaytirish va yana # ta ogohlantirishni ochish}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Ogohlantirish: <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Amal bajarildi"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Qurilmangizga himoya qoʻshadigan sozlamalarni tekshiring"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Xavfsizlik va maxfiylik tezkor sozlamalari"</string>
diff --git a/PermissionController/res/values-uz/strings.xml b/PermissionController/res/values-uz/strings.xml
index f3dbf18bc..324202f9d 100644
--- a/PermissionController/res/values-uz/strings.xml
+++ b/PermissionController/res/values-uz/strings.xml
@@ -32,16 +32,17 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"“Ilova ishlatilganda” rejimida qolsin"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"“Faqat shu safar” ruxsat berish"</string>
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Batafsil"</string>
- <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Hammasiga ruxsat berish"</string>
+ <string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Hammasiga ruxsat"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Doim hammasiga ruxsat berish"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Cheklangan ruxsat berish"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Surat va videolarni tanlash"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Yana"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Boshqa tanlanmasin"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Baribir rad etilsin"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Yopish"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasiga <xliff:g id="ACTION">%2$s</xliff:g> uchun ruxsat berilsinmi?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasiga bu amalga bajarishga doim ruxsat berilsinmi: <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun <xliff:g id="ACTION">%2$s</xliff:g> ruxsati berilsinmi?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun doim <xliff:g id="ACTION">%2$s</xliff:g> ruxsati berilsinmi?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Faqat ilova ishlatilayotganda"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Har doim"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Rad etilsin va boshqa soʻralmasin"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Ilovalar"</string>
<string name="app_permissions" msgid="3369917736607944781">"Ilovalar uchun ruxsatlar"</string>
<string name="unused_apps" msgid="2058057455175955094">"Ishlatilmagan ilovalar"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Bu ilova uchun tanlangan suratlarni tahrirlash"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Ishlatilmagan ilovalar yoʻq"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ta ishlatilmagan ilova"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Yaqinda tekshirilgan ruxsatlar"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Barcha ruxsatlar"</string>
<string name="other_permissions" msgid="2901186127193849594">"Ilovaning boshqa imkoniyatlari"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Ruxsat olish talabi"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear qurilmasi o‘rnatish/o‘chirish amallarini qo‘llab-quvvatlamaydi."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun beriladigan ruxsatlarni tanlang"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; yangilandi. Unga beriladigan ruxsatlarni tanlang."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Bekor qilish"</string>
@@ -124,7 +124,7 @@
<string name="current_permissions_category" msgid="4292990083585728880">"Joriy ruxsatlar"</string>
<string name="message_staging" msgid="9110563899955511866">"Kutib turing…"</string>
<string name="app_name_unknown" msgid="1319665005754048952">"Noaniq"</string>
- <string name="permission_usage_title" msgid="1568233336351734538">"Maxfiylik boshqaruv paneli"</string>
+ <string name="permission_usage_title" msgid="1568233336351734538">"Maxfiylik boshqaruvi"</string>
<string name="auto_permission_usage_summary" msgid="7335667266743337075">"Ruxsatlardan yaqinda foydalangan ilovalarni koʻrish"</string>
<string name="permission_group_usage_title" msgid="2595013198075285173">"<xliff:g id="PERMGROUP">%1$s</xliff:g> ruxsatidan foydalanish"</string>
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Boshqa ruxsatlarni koʻrish"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Ishlatilmayotgan ilovalardan ruxsatlarni olib tashlash"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Ruxsatlarni olib tashlash va joy ochish"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Ishlatilmayotgan ilovalarni pauzalash"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Ishlatilmagan ilovalarni boshqarish"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Ruxsatlarni olib tashlash, vaqtinchalik fayllarni oʻchirish va bildirishnomalarni toʻxtatish"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Ruxsatlarni olib tashlash, vaqtinchalik fayllarni oʻchirish, bildirishnomalarni toʻxtatish va ilovani arxivlash"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Xavfsizlik yuzasidan, bir necha oydan beri ishlatilmagan ilovalardan ruxsatlar olib tashlanadi"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Agar bu ilova bir necha oy ishlatilmasa, quyidagi ruxsatlar olib tashlanadi: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Xavfsizlik yuzasidan, bir necha oydan beri ishlatilmagan ilovalardan ruxsatlar olib tashlanadi"</string>
@@ -226,7 +228,7 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Oxirgi marta ochilgan: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Barcha fayllarni boshqarishga ruxsat berilsa, ilova bu qurilmadagi yoki ulangan xotira omborlaridagi barcha fayllarni ochishi, tahrirlashi yoki oʻchirib tashlashi mumkin. Ilova fayllar bilan sizga xabar qilmay ishlay oladi."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Ilovaga bu qurilmadagi yoki ulangan xotira omborlaridagi barcha fayllarni ochish, tahrirlash yoki oʻchirib tashlash uchun ruxsat berilsinmi? Bu ilova fayllar bilan sizga xabar qilmay ishlay oladi."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Bunday ruxsatga ega ilovalar quyidagi amallarni bajara oladi: <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"<xliff:g id="DESCRIPTION">%1$s</xliff:g> ruxsatiga ega ilovalar"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Bunday ruxsatga ega ilovalar piyoda yurish, velosiped haydash, avtomobil boshqarish, qadamlaringiz soni kabi jismoniy faoliyatingiz haqidagi axborotlarga ham kira oladi"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Bunday ruxsatga ega ilovalar taqvimingizdan foydalana oladi"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Bunday ruxsatga ega ilovalar telefondagi chaqiruvlar jurnaliga kira oladi va uni tahrirlay oladi"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Qaydlar ilovasi"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Qurilmangizda qaydlar olish imkonini beruvchi ilovalar"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"qaydlar"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Hozirda asosiy ilova"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Boshqa soʻralmasin"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Birlamchi deb belgilash"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Ovozli yordamchi faollashgani haqidagi belgini chiqarish"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Ovozli yordamchi mikrofon orqali faollashtirilganda, bu haqda holat qatorida maxsus belgi chiqadi"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun qurilmadagi suratlar va media fayllarga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;dagi suratlar va media fayllarga kirish ruxsati berilsinmi?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun kontaktlaringizga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da kontaktlaringizga ruxsat berilsinmi?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun bu qurilmaning joylashuvi haqidagi axborotdan foydalanish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt; joylashuviga kirishga ruxsat berilsinmi?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Bu ilovadan foydalanilayotdangina u joylashuv axborotidan foydalana oladi"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun bu qurilmaning joylashuvi haqidagi axborotdan foydalanish ruxsati berilsinmi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> joylashuviga kirishga ruxsat berilsinmi?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Bu ilova ochiq emasligida ham joylashuvingiz haqidagi axborotdan foydalanmoqchi. Bunga "<annotation id="link">" sozlamalar"</annotation>" orqali ruxsat bering."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun joylashuv axborotiga ruxsat oʻzgartirilsinmi?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun joylashuv axborotiga ruxsat oʻzgartirilsinmi?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Bu ilova ochiq emasligida ham joylashuvingiz haqidagi axborotdan foydalanmoqchi. Bunga "<annotation id="link">"sozlamalar"</annotation>" orqali ruxsat bering."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; yaqin-atrofdagi qurilmalar joylashuvini aniqlashi va ularga ulanishiga ruxsat berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ilovasi uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da yaqin-atrofdagi qurilmalar joylashuvini aniqlashi va ularga ulanishiga ruxsat berilsinmi?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; yaqin-atrofdagi qurilmalar joylashuvini aniqlashi va ularga ulanishiga ruxsat berilsinmi? "<annotation id="link">"Sozlamalar orqali ruxsat berish mumkin."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> uchun joylashuv ruxsati taxminiydan aniqqa oʻzgartirilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> ilovasining joylashuv ruxsati &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da taxminiydan aniq qiymatga oʻzgartirilsinmi?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun bu qurilmaning taxminiy joylashuvi haqidagi axborotdan foydalanish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g> taxminiy joylashuviga kirishga ruxsat berilsinmi?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Aniq"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Taxminiy"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun taqvimingizga ruxsat berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da taqvimingizga ruxsat berilsinmi?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun SMS xabarlarni yuborish va ko‘rishga ruxsat berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da SMS xabarlarni yuborish va ko‘rishga ruxsat berilsinmi?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun qurilmangizdagi suratlar, multimedia va fayllarga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;dagi surat, multimedia va fayllarga ruxsat berilsinmi?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun ushbu qurilmadagi surat, video, musiqa va audiolarga kirish ruxsati berilsinmi?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun ushbu qurilmadagi surat, video, musiqa, audio va fayllarga kirish ruxsati berilsinmi?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun ushbu qurilmadagi musiqa va audio fayllarga kirish ruxsati berilsinmi?"</string>
- <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun qurilmadagi rasm va videolarga kirish ruxsati berilsinmi?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun qurilmadagi boshqa rasm va videolarga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;dagi musiqa va audio fayllarga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun qurilmadagi suratlar va videolarga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;dagi rasm va videolarga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun qurilmadagi boshqa surat va videolarga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;dagi boshqa rasm va videolarga kirish ruxsati berilsinmi?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun audio yozib olish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da audio yozib olishga ruxsat berilsinmi?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Bu ilova faqat undan foydalanganingizda ovozlarni yozib oladi"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun audio yozib olishga ruxsat berilsinmi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da audio yozib olishga ruxsat berilsinmi?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Bu ilova doimo, hatto undan foydalanmagan vaqtlaringizda ham ovoz yozib olishi mumkin. "<annotation id="link">"Sozlamalar orqali ruxsat bering."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun mikrofonga ruxsat oʻzgartirilsinmi?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasi uchun mikrofon ruxsati oʻzgartirilsinmi?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Bu ilova doimo, hatto undan foydalanmagan vaqtlaringizda ham ovoz yozib olishi mumkin. "<annotation id="link">"Sozlamalar orqali ruxsat bering."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun jismoniy harakatlaringizga oid axborotga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da jismoniy harakatlaringiz axborotiga ruxsat berilsinmi?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun surat va videoga olish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da surat va videoga olishga ruxsat berilsinmi?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Bu ilova faqat undan foydalanganingizda rasm va videoga oladi"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun surat va videoga olishga ruxsat berilsinmi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da surat va videoga olishga ruxsat berilsinmi?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Bu ilova doimo, hatto undan foydalanmagan vaqtlaringizda ham rasm va videoga olishi mumkin. "<annotation id="link">"Sozlamalar orqali ruxsat bering."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun kameraga ruxsat oʻzgartirilsinmi?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasi uchun kamera ruxsati oʻzgartirilsinmi?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Bu ilova doimo, hatto undan foydalanmagan vaqtlaringizda ham rasm va videoga olishi mumkin. "<annotation id="link">"Sozlamalar orqali ruxsat bering."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun telefoningizdagi chaqiruvlar tarixiga kirish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da telefon chaqiruvlari tarixiga kirishga ruxsat berilsinmi?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun telefon chaqiruvlarini amalga oshirish va boshqarish ruxsati berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da telefon chaqiruvlarini amalga oshirish va boshqarishga ruxsat berilsinmi?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun tana holati haqidagi sensor axborotlariga ruxsat berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da organizm holati haqidagi sezgichlar axborotlariga ruxsat berilsinmi?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Bu ilova organizm holati haqidagi sensor maʼlumotlaringizdan doimiy foydalanishga ruxsat olmoqchi. Bu ruxsatni berish uchun "<annotation id="link">"sozlamalarni oching."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun organizm holati haqidagi sensor axborotlariga ruxsat berilsinmi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da organizm holati haqidagi sezgichlar axborotlariga ruxsat berilsinmi?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Bu ilovaga tanadagi sensor maʼlumotlaridan foydalanishga (hatto ilova yopiqligida ham) doimiy ruxsat berish uchun "<annotation id="link">"sozlamalarni oching."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasining tanadagi sensor maʼlumotlaridan foydalanishiga ruxsat berilsinmi?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasi tanadagi sensor maʼlumotlaridan foydalanishiga ruxsat berilaversinmi?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasiga sizga bildirishnomalar yuborishi uchun ruxsat berilsinmi?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasiga &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;da sizga bildirishnomalar yuborishi uchun ruxsat berilsinmi?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Boshqariluvchi ruxsatlar"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> joylashuvga kira oladi"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Tashkilotingiz <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga joylashuvingizga kirishga ruxsat bergan"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Boshqa ruxsatlar"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Tizim ishlatadigan ruxsatlar"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Faqat tizim ilovalari ishlatadigan ruxsatlar"</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Bu ilovaning maʼlumotlarini begonalarga ulashishi mumkinligi xabar berildi"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Maʼlumotlar ulashuvi va joylashuv axboroti"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Maʼlumotlar ulashuvi haqidagi axborot manbasi"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Dasturchi bu qurilma ishlab chiqaruvchisiga ushbu ilova maʼlumotlarni qanday ulashishi haqida axborot berdi. Bu axborot keyinchalik yangilanishi mumkin."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Dasturchi "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" ga bu ilovadagi maʼlumotlar qanday ulashilishi haqida axborot bergan. Bu axborot keyinchalik yangilanishi mumkin."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Ilova joylashuv axborotini quyidagicha ulashadi:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Maʼlumotlarning turlicha ulashuvi"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Maʼlumotlar xavfsizligi"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Joylashuv axboroti ulashilishi mumkin"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Bu ilova tashqariga joylashuv axborotini ulashishi mumkinligi aniqlandi"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Bu havola ochilmadi"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Joylashuv axboroti ulashuvidagi oʻzgarishlar"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Joylashuv axboroti ulashuviga oʻzgartirish kiritgan ilovalarni tekshiring"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Quyidagi ilovalarda joylashuv axboroti ulashuvi oʻzgardi. Avval ulashilmagan boʻlishi yoki endi reklama va marketing maqsadlarida ulashilishi mumkin"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Axborot ulashuvi yangilanishi"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Ayrim ilovalarda joylashuv axboroti ulashuvi oʻzgardi"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Sozlamalar"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Kirilgan: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Kecha kirilgan: <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Kirilgan: <xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-v31/styles.xml b/PermissionController/res/values-v31/styles.xml
index a05fd488b..e2f6378f5 100644
--- a/PermissionController/res/values-v31/styles.xml
+++ b/PermissionController/res/values-v31/styles.xml
@@ -90,22 +90,22 @@
parent="@style/PermissionGrantButtonTop"></style>
<style name="PermissionGrantButtonAllowOneTimeMaterial3"
parent="@style/PermissionGrantButtonMiddle"></style>
+ <style name="PermissionGrantButtonAllowSelectedMaterial3"
+ parent="@style/PermissionGrantButtonTop"></style>
<style name="PermissionGrantButtonAllowAllMaterial3"
parent="@style/PermissionGrantButtonMiddle"></style>
- <style name="PermissionGrantButtonAllowSelectedMaterial3"
- parent="@style/PermissionGrantButtonTop"></style>
- <style name="PermissionGrantButtonDontAllowMoreMaterial3"
- parent="@style/PermissionGrantButtonBottom"></style>
<style name="PermissionGrantButtonDenyMaterial3"
parent="@style/PermissionGrantButtonBottom"></style>
<style name="PermissionGrantButtonNoUpgradeMaterial3"
parent="@style/PermissionGrantButtonBottom"></style>
+ <style name="PermissionGrantButtonDontAllowMoreMaterial3"
+ parent="@style/PermissionGrantButtonBottom"></style>
<!-- END PERMISSION GRANT DIALOG -->
<style name="AppPermissionRadioButton"
parent="@android:style/Widget.DeviceDefault.CompoundButton.RadioButton">
- <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:paddingStart">?android:attr/listPreferredItemPaddingStart</item>
diff --git a/PermissionController/res/values-v33/attrs.xml b/PermissionController/res/values-v33/attrs.xml
index b59716f6d..4a417076d 100644
--- a/PermissionController/res/values-v33/attrs.xml
+++ b/PermissionController/res/values-v33/attrs.xml
@@ -37,7 +37,10 @@
<attr name="scStatusTitleAndSummaryContainerStyle" format="reference" />
<attr name="scStatusButtonStyle" format="reference" />
+ <attr name="scActionButtonListLayout" format="reference" />
+ <attr name="scActionButtonTheme" format="reference" />
<attr name="scActionButtonStyle" format="reference"/>
<attr name="scSecondaryActionButtonStyle" format="reference"/>
+
<attr name="colorScShieldAccent" format="color" />
</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-v33/dimens.xml b/PermissionController/res/values-v33/dimens.xml
index ef70d2711..e6925bc54 100644
--- a/PermissionController/res/values-v33/dimens.xml
+++ b/PermissionController/res/values-v33/dimens.xml
@@ -24,20 +24,25 @@
<dimen name="sc_spacing_xlarge">18dp</dimen>
<dimen name="sc_spacing_xxlarge">20dp</dimen>
<dimen name="sc_spacing_xxxlarge">24dp</dimen>
- <dimen name="sc_large_screen_button_padding">56dp</dimen>
<dimen name="sc_card_margin">@dimen/sc_spacing_xxxsmall</dimen>
<dimen name="sc_list_margin">@dimen/sc_spacing_large</dimen>
<dimen name="sc_list_margin_top">@dimen/sc_spacing_small</dimen>
+
+ <!-- Only used for small screen views, but doesn't have _small_screen suffix since it's fixed in
+ the overlayable. -->
<dimen name="sc_action_button_list_margin">@dimen/sc_spacing_large</dimen>
+ <dimen name="sc_action_button_list_margin_large_screen">@dimen/sc_spacing_large</dimen>
<dimen name="sc_top_action_button_margin">@dimen/sc_spacing_xxxlarge</dimen>
+ <dimen name="sc_button_horizontal_padding_small_screen">@dimen/sc_spacing_xxxlarge</dimen>
+ <dimen name="sc_button_horizontal_padding_large_screen">56dp</dimen>
+
<dimen name="sc_entry_padding_end">@dimen/sc_spacing_xxxlarge</dimen>
<dimen name="sc_entry_group_expanded_padding_top">@dimen/sc_spacing_xxxlarge</dimen>
<dimen name="sc_entry_group_expanded_padding_bottom">@dimen/sc_spacing_xsmall</dimen>
<dimen name="sc_entry_group_collapsed_padding_top">@dimen/sc_spacing_large</dimen>
<dimen name="sc_entry_group_collapsed_padding_bottom">@dimen/sc_spacing_large</dimen>
<dimen name="sc_card_margin_bottom">@dimen/sc_spacing_xxxlarge</dimen>
- <dimen name="sc_button_horizontal_padding">@dimen/sc_spacing_xxxlarge</dimen>
<dimen name="sc_icon_button_touch_target_size">48dp</dimen>
<dimen name="sc_button_corner_radius">12dp</dimen>
diff --git a/PermissionController/res/values-v33/layout.xml b/PermissionController/res/values-v33/layout.xml
new file mode 100644
index 000000000..a963dae0d
--- /dev/null
+++ b/PermissionController/res/values-v33/layout.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <item name="action_button_list_fixed" type="layout">
+ @layout/action_button_list_small_screen
+ </item>
+ <item name="action_button_list_responsive" type="layout">
+ @layout/action_button_list_small_screen
+ </item>
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-v33/styles.xml b/PermissionController/res/values-v33/styles.xml
index a0938665f..c018ca094 100644
--- a/PermissionController/res/values-v33/styles.xml
+++ b/PermissionController/res/values-v33/styles.xml
@@ -324,10 +324,10 @@
<style name="SafetyCenterActionButton"
parent="@style/Widget.MaterialComponents.Button.UnelevatedButton">
- <item name="android:theme">@style/Theme.MaterialComponents</item>
+ <item name="android:theme">?attr/scActionButtonTheme</item>
<item name="android:minHeight">56dp</item>
- <item name="android:paddingStart">@dimen/sc_button_horizontal_padding</item>
- <item name="android:paddingEnd">@dimen/sc_button_horizontal_padding</item>
+ <item name="android:paddingStart">@dimen/sc_button_horizontal_padding_small_screen</item>
+ <item name="android:paddingEnd">@dimen/sc_button_horizontal_padding_small_screen</item>
<item name="android:paddingTop">@dimen/sc_spacing_xlarge</item>
<item name="android:paddingBottom">@dimen/sc_spacing_xlarge</item>
<item name="android:insetTop">0dp</item>
@@ -340,13 +340,15 @@
<item name="cornerRadius">@dimen/sc_button_corner_radius</item>
<item name="rippleColor">?android:colorControlHighlight</item>
</style>
+ <style name="SafetyCenterActionButton.Fixed" />
+ <style name="SafetyCenterActionButton.Responsive" />
- <style name="SafetyCenterActionButton.Secondary"
+ <style name="SecondarySafetyCenterActionButton"
parent="@style/Widget.MaterialComponents.Button.OutlinedButton">
- <item name="android:theme">@style/Theme.MaterialComponents</item>
+ <item name="android:theme">?attr/scActionButtonTheme</item>
<item name="android:minHeight">56dp</item>
- <item name="android:paddingStart">@dimen/sc_button_horizontal_padding</item>
- <item name="android:paddingEnd">@dimen/sc_button_horizontal_padding</item>
+ <item name="android:paddingStart">@dimen/sc_button_horizontal_padding_small_screen</item>
+ <item name="android:paddingEnd">@dimen/sc_button_horizontal_padding_small_screen</item>
<item name="android:paddingTop">@dimen/sc_spacing_xlarge</item>
<item name="android:paddingBottom">@dimen/sc_spacing_xlarge</item>
<item name="android:insetTop">0dp</item>
@@ -361,6 +363,8 @@
<item name="cornerRadius">@dimen/sc_button_corner_radius</item>
<item name="rippleColor">?android:colorControlHighlight</item>
</style>
+ <style name="SecondarySafetyCenterActionButton.Fixed" />
+ <style name="SecondarySafetyCenterActionButton.Responsive" />
<!-- START SAFETY STATUS CARD -->
<style name="SafetyCenterCard.Status">
@@ -592,11 +596,10 @@
<style name="SafetyCenterMoreIssuesCounter"
parent="android:Widget.DeviceDefault">
- <item name="android:layout_height">24dp</item>
+ <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:orientation">horizontal</item>
- <item name="android:paddingStart">@dimen/sc_spacing_xsmall</item>
- <item name="android:paddingEnd">@dimen/sc_spacing_xsmall</item>
+ <item name="android:paddingHorizontal">@dimen/sc_spacing_xsmall</item>
<item name="android:background">@drawable/safety_center_card_widget_background</item>
<item name="android:gravity">center_vertical</item>
<item name="layout_constraintTop_toTopOf">parent</item>
@@ -608,6 +611,7 @@
parent="SafetyCenterBaseTextContainer">
<item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Body</item>
<item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ <item name="android:paddingVertical">@dimen/sc_spacing_xxxsmall</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
@@ -789,12 +793,6 @@
<item name="android:layout_height">24dp</item>
</style>
- <style name="SafetyCenterNoLabelPreferenceCategory"
- parent="android:Widget.DeviceDefault">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">16dp</item>
- </style>
-
<style name="SafetyCenterGroupEntry"
parent="android:Widget.DeviceDefault">
<item name="android:layout_width">match_parent</item>
diff --git a/PermissionController/res/values-v33/themes.xml b/PermissionController/res/values-v33/themes.xml
index 338cbaa01..82a8ef5b6 100644
--- a/PermissionController/res/values-v33/themes.xml
+++ b/PermissionController/res/values-v33/themes.xml
@@ -47,14 +47,18 @@
<item name="scStatusButtonStyle">@style/SafetyCenterStatusButton.Fixed</item>
<!-- Buttons -->
- <item name="scActionButtonStyle">@style/SafetyCenterActionButton</item>
- <item name="scSecondaryActionButtonStyle">@style/SafetyCenterActionButton.Secondary</item>
+ <item name="scActionButtonListLayout">@layout/action_button_list_fixed</item>
+ <item name="scActionButtonTheme">
+ <!-- Dark-only theme for QS buttons -->
+ @style/Theme.MaterialComponents
+ </item>
+ <item name="scActionButtonStyle">@style/SafetyCenterActionButton.Fixed</item>
+ <item name="scSecondaryActionButtonStyle">
+ @style/SecondarySafetyCenterActionButton.Fixed
+ </item>
<item name="textColorScActionButton">@color/sc_primary_action_button_text</item>
- <!-- While the rest of the text colors automatically appear correct in quick settings,
- the outline action button text color needs to be set to primary inverse in light mode
- and primary in night mode to appear correctly in QS's faux permanent night mode. -->
- <item name="textColorScSecondaryActionButton">?android:attr/textColorPrimaryInverse</item>
+ <item name="textColorScSecondaryActionButton">?android:attr/textColorPrimary</item>
<item name="colorScOutlineButtonInfoBase">@color/sc_outline_button_info_base_dark</item>
<item name="colorScOutlineButtonRecommendBase">
@@ -93,8 +97,12 @@
<item name="scStatusButtonStyle">@style/SafetyCenterStatusButton.Responsive</item>
<!-- Buttons -->
- <item name="scActionButtonStyle">@style/SafetyCenterActionButton</item>
- <item name="scSecondaryActionButtonStyle">@style/SafetyCenterActionButton.Secondary</item>
+ <item name="scActionButtonListLayout">@layout/action_button_list_responsive</item>
+ <item name="scActionButtonTheme">@style/Theme.MaterialComponents.DayNight</item>
+ <item name="scActionButtonStyle">@style/SafetyCenterActionButton.Responsive</item>
+ <item name="scSecondaryActionButtonStyle">
+ @style/SecondarySafetyCenterActionButton.Responsive
+ </item>
<item name="textColorScActionButton">@color/sc_primary_action_button_text</item>
<item name="textColorScSecondaryActionButton">?android:attr/textColorPrimary</item>
diff --git a/PermissionController/res/values-v34/strings.xml b/PermissionController/res/values-v34/strings.xml
index 30181aa02..26a9b4bcc 100644
--- a/PermissionController/res/values-v34/strings.xml
+++ b/PermissionController/res/values-v34/strings.xml
@@ -28,7 +28,7 @@
<!-- Title for the link to location settings [CHAR LIMIT=30] -->
<string name="location_settings">Location access</string>
- <!-- Describes what is affected by the mic toggle [CHAR LIMIT=NONE] -->
+ <!-- Describes what is affected by the mic toggle. Unlike the similar tc/9163104307990677157, there should NOT be a full stop at the end of this sentence. [CHAR LIMIT=NONE] -->
<string name="mic_toggle_description">For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number</string>
<!-- Subtitle for the link to location settings [CHAR LIMIT=NONE] -->
<string name="location_settings_subtitle">For apps and services</string>
diff --git a/PermissionController/res/values-v35/bools.xml b/PermissionController/res/values-v35/bools.xml
new file mode 100644
index 000000000..f015b636e
--- /dev/null
+++ b/PermissionController/res/values-v35/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <bool name="is_at_least_v">true</bool>
+</resources>
diff --git a/PermissionController/res/values-vi-v33/strings.xml b/PermissionController/res/values-vi-v33/strings.xml
index b5d70029e..d5fdffc1e 100644
--- a/PermissionController/res/values-vi-v33/strings.xml
+++ b/PermissionController/res/values-vi-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Cảnh báo khác"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Cảnh báo bị loại bỏ"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Mở rộng và xem một cảnh báo khác}other{Mở rộng và xem # cảnh báo khác}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Cảnh báo. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Hoàn tất hành động"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Kiểm tra các chế độ cài đặt có thể giúp tăng cường bảo vệ cho thiết bị của bạn"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Các tùy chọn cài đặt nhanh về bảo mật và quyền riêng tư"</string>
diff --git a/PermissionController/res/values-vi-v34/strings.xml b/PermissionController/res/values-vi-v34/strings.xml
index 22832fc8d..618a266d8 100644
--- a/PermissionController/res/values-vi-v34/strings.xml
+++ b/PermissionController/res/values-vi-v34/strings.xml
@@ -22,6 +22,6 @@
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
<string name="health_connect_summary" msgid="815473513776882296">"Quản lý quyền truy cập của ứng dụng vào dữ liệu sức khoẻ"</string>
<string name="location_settings" msgid="8863940440881290182">"Quyền truy cập thông tin vị trí"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"Ảnh hưởng đến các ứng dụng và dịch vụ. Nếu tắt chế độ cài đặt này, dữ liệu thu được qua micrô vẫn có thể được chia sẻ khi bạn gọi đến số khẩn cấp"</string>
- <string name="location_settings_subtitle" msgid="6846532794702613851">"Đối với các ứng dụng và dịch vụ"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Áp dụng cho các ứng dụng và dịch vụ. Nếu bạn tắt chế độ cài đặt này, dữ liệu thu được qua micrô vẫn có thể được chia sẻ khi bạn gọi đến số khẩn cấp"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Áp dụng cho các ứng dụng và dịch vụ"</string>
</resources>
diff --git a/PermissionController/res/values-vi/strings.xml b/PermissionController/res/values-vi/strings.xml
index fac51befe..de260f0ac 100644
--- a/PermissionController/res/values-vi/strings.xml
+++ b/PermissionController/res/values-vi/strings.xml
@@ -34,14 +34,15 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Thông tin khác"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Cho phép tất cả"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Luôn cho phép tất cả"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Cho phép quyền truy cập bị hạn chế"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Chọn ảnh và video"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Chọn thêm"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Không chọn thêm"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Vẫn không cho phép"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Đóng"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>/<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
- <string name="permission_warning_template" msgid="2247087781222679458">"Bạn có muốn cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g> không?"</string>
- <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Bạn có muốn luôn cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g> không?"</string>
+ <string name="permission_warning_template" msgid="2247087781222679458">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
+ <string name="permission_add_background_warning_template" msgid="1812914855915092273">"Luôn cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; <xliff:g id="ACTION">%2$s</xliff:g>?"</string>
<string name="allow_permission_foreground_only" msgid="116465816039675404">"Chỉ khi dùng ứng dụng"</string>
<string name="allow_permission_always" msgid="5194342531206054051">"Luôn luôn"</string>
<string name="deny_permission_deny_and_dont_ask_again" msgid="6106035221490102341">"Không cho phép và không hỏi lại"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Ứng dụng"</string>
<string name="app_permissions" msgid="3369917736607944781">"Quyền ứng dụng"</string>
<string name="unused_apps" msgid="2058057455175955094">"Ứng dụng không dùng đến"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Chỉnh sửa các ảnh đã chọn cho ứng dụng này"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Không có ứng dụng không dùng đến"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"0 ứng dụng không dùng đến"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Quyết định cấp quyền gần đây"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Tất cả các quyền"</string>
<string name="other_permissions" msgid="2901186127193849594">"Các khả năng khác của ứng dụng"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Yêu cầu quyền"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Các hành động Cài đặt/Gỡ cài đặt không được hỗ trợ trên Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Chọn nội dung &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; được phép truy cập vào"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"Đã cập nhật &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;. Chọn nội dung ứng dụng này được phép truy cập vào."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Hủy"</string>
@@ -130,7 +130,7 @@
<string name="perm_usage_adv_info_title" msgid="3357831829538873708">"Xem các quyền khác"</string>
<string name="perm_usage_adv_info_summary_2_items" msgid="3702175198750127822">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g>"</string>
<string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>, <xliff:g id="PERMGROUP_1">%2$s</xliff:g> và <xliff:g id="NUM">%3$s</xliff:g> mục khác"</string>
- <string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"Lịch trình các ứng dụng dùng <xliff:g id="PERMGROUP">%1$s</xliff:g> của bạn trong 24 giờ qua"</string>
+ <string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"Mốc thời gian các ứng dụng dùng <xliff:g id="PERMGROUP">%1$s</xliff:g> của bạn trong 24 giờ qua"</string>
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Lịch trình các ứng dụng dùng <xliff:g id="PERMGROUP">%1$s</xliff:g> của bạn trong 7 ngày qua"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Thời điểm ứng dụng này sử dụng quyền <xliff:g id="PERMGROUP">%1$s</xliff:g> của bạn"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Tìm hiểu thêm"</string>
@@ -201,10 +201,12 @@
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Xem tất cả ứng dụng có quyền này"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"Hiển thị việc sử dụng micrô của Trợ lý"</string>
<string name="unused_apps_category_title" msgid="2988455616845243901">"Chế độ cài đặt cho ứng dụng không dùng đến"</string>
- <string name="auto_revoke_label" msgid="5068393642936571656">"Thu hồi quyền nếu không dùng ứng dụng"</string>
+ <string name="auto_revoke_label" msgid="5068393642936571656">"Thu hồi quyền nếu bạn không dùng ứng dụng"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Thu hồi quyền và giải phóng dung lượng"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Tạm dừng hoạt động trong ứng dụng nếu không dùng"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Quản lý ứng dụng nếu không dùng"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Loại bỏ quyền, xoá tệp tạm thời và dừng thông báo"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Loại bỏ quyền, xoá tệp tạm thời, dừng thông báo và lưu trữ ứng dụng"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Để bảo vệ dữ liệu của bạn, các quyền cấp cho ứng dụng này sẽ bị thu hồi nếu bạn không dùng ứng dụng trong vài tháng."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Để bảo vệ dữ liệu của bạn, nếu bạn không dùng ứng dụng này trong vài tháng thì các quyền sau đây sẽ bị thu hồi: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Để bảo vệ dữ liệu của bạn, quản trị viên CNTT đã thu hồi các quyền đối với những ứng dụng bạn không dùng trong vài tháng."</string>
@@ -221,7 +223,7 @@
<string name="unused_apps_page_title" msgid="6986983535677572559">"Ứng dụng không dùng đến"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Nếu một ứng dụng không được dùng đến trong vài tháng, hệ thống sẽ:\n\n• Thu hồi các quyền để bảo vệ dữ liệu của bạn\n• Chặn các thông báo để tiết kiệm pin\n• Xóa các tệp tạm thời để giải phóng bộ nhớ\n\nĐể cho phép lại các quyền và thông báo, hãy mở ứng dụng đó."</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Nếu bạn không dùng một ứng dụng trong một tháng, thì hệ thống sẽ:\n\n• Xoá các quyền để bảo vệ dữ liệu của bạn\n• Xoá các tệp tạm thời để giải phóng dung lượng\n\nĐể cấp lại các quyền, hãy mở ứng dụng đó."</string>
- <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Lần mở gần đây nhất là hơn # tháng trước}other{Lần mở gần đây nhất là hơn # tháng trước}}"</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Không dùng trong hơn # tháng}other{Không dùng trong hơn # tháng}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Lần gần đây nhất bạn mở ứng dụng này là vào <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Lần mở gần đây nhất là vào <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Nếu bạn cho phép quản lý tất cả các tệp, thì ứng dụng này có thể truy cập, sửa đổi và xóa bất kỳ tệp nào trong bộ nhớ chung trên thiết bị này hoặc các thiết bị lưu trữ được kết nối. Ứng dụng có thể truy cập vào tệp mà không cần hỏi bạn."</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"Ứng dụng ghi chú"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Các ứng dụng cho phép bạn tạo ghi chú trên thiết bị"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"ghi chú"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Ứng dụng mặc định hiện tại"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Không hỏi lại"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Đặt làm mặc định"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Hiển thị tính năng phát hiện trình kích hoạt Trợ lý"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Hiển thị biểu tượng trong thanh trạng thái khi sử dụng micrô để kích hoạt trợ lý thoại"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào ảnh và nội dung nghe nhìn trên thiết bị?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào ảnh và nội dung đa phương tiện trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào danh bạ của bạn?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập danh bạ của bạn trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào thông tin vị trí của thiết bị này?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập dữ liệu vị trí của &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Ứng dụng này sẽ chỉ có quyền truy cập vào vị trí khi bạn đang sử dụng ứng dụng này"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào thông tin vị trí của thiết bị này?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập dữ liệu vị trí của &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Ứng dụng này có thể muốn truy cập vào thông tin vị trí của bạn mọi lúc, ngay cả khi bạn không dùng ứng dụng. "<annotation id="link">"Hãy cho phép trong phần cài đặt."</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Thay đổi quyền truy cập vào thông tin vị trí đối với &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Thay đổi quyền truy cập vào dữ liệu vị trí của &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Ứng dụng này muốn truy cập vào thông tin vị trí của bạn mọi lúc, ngay cả khi bạn không dùng ứng dụng. "<annotation id="link">"Hãy cho phép trong phần cài đặt."</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tìm, kết nối và xác định vị trí tương đối của các thiết bị ở gần?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tìm, kết nối và xác định vị trí tương đối của các thiết bị ở gần trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tìm, kết nối và xác định vị trí tương đối của các thiết bị ở gần? "<annotation id="link">"Bạn có thể cho phép việc này trong phần cài đặt."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Thay đổi quyền truy cập thông tin vị trí của <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> từ vị trí gần đúng thành vị trí chính xác?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Thay đổi quyền truy cập dữ liệu vị trí của <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; từ ước chừng thành chính xác?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào thông tin vị trí gần đúng của thiết bị này?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vị trí ước chừng của &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Chính xác"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Gần đúng"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào lịch của bạn?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập lịch của bạn trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gửi và xem tin nhắn SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gửi và xem tin nhắn SMS trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào ảnh, nội dung nghe nhìn và tệp trên thiết bị của bạn?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào ảnh, nội dung đa phương tiện và tệp trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào &lt;b&gt;ảnh, video, nhạc và âm thanh&lt;/b&gt; trên thiết bị này?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào &lt;b&gt;ảnh, video, nhạc, âm thanh và các tệp khác&lt;/b&gt; trên thiết bị này?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào nhạc và âm thanh trên thiết bị này?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào nhạc và âm thanh trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào ảnh và video trên thiết bị này?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào ảnh và video trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào ảnh và video khác trên thiết bị này?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập thêm nhiều ảnh và video trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ghi âm?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ghi âm trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Ứng dụng này chỉ có thể ghi âm khi bạn đang dùng ứng dụng"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ghi âm?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ghi âm trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Ứng dụng này có thể muốn ghi âm mọi lúc, ngay cả khi bạn không dùng ứng dụng. "<annotation id="link">"Cho phép trong phần cài đặt."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Thay đổi quyền sử dụng micrô của &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Thay đổi quyền truy cập vào micrô của &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Ứng dụng này muốn ghi âm mọi lúc, ngay cả khi bạn không dùng ứng dụng. "<annotation id="link">"Cho phép trong phần cài đặt."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Bạn cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào hoạt động thể chất?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập dữ liệu về hoạt động thể chất của bạn trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; chụp ảnh và quay video?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; chụp ảnh và quay video trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Ứng dụng này chỉ có thể chụp ảnh và quay video khi bạn đang dùng ứng dụng"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; chụp ảnh và quay video?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; chụp ảnh và quay video trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Ứng dụng này có thể muốn chụp ảnh và quay video mọi lúc, ngay cả khi bạn không dùng ứng dụng. "<annotation id="link">"Cho phép trong phần cài đặt."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Thay đổi quyền sử dụng máy ảnh của &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Thay đổi quyền truy cập vào camera của &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Ứng dụng này muốn chụp ảnh và quay video mọi lúc, ngay cả khi bạn không dùng ứng dụng. "<annotation id="link">"Cho phép trong phần cài đặt."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào nhật ký cuộc gọi điện thoại của bạn?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập nhật ký gọi điện thoại của bạn trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; thực hiện và quản lý cuộc gọi điện thoại?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gọi điện thoại và quản lý cuộc gọi điện thoại trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào dữ liệu cảm biến về các dấu hiệu sinh tồn của bạn?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào dữ liệu cảm biến về dấu hiệu sinh tồn của bạn trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Ứng dụng này muốn truy cập vào dữ liệu cảm biến về các dấu hiệu sinh tồn của bạn bất cứ lúc nào, ngay cả khi bạn không dùng ứng dụng. Để thay đổi, hãy "<annotation id="link">"chuyển đến phần cài đặt."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào dữ liệu cảm biến về các dấu hiệu sinh tồn của bạn?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào dữ liệu cảm biến về dấu hiệu sinh tồn của bạn trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Để cho phép ứng dụng này truy cập vào dữ liệu cảm biến cơ thể bất cứ lúc nào, ngay cả khi bạn đang không dùng ứng dụng, "<annotation id="link">"chuyển đến phần cài đặt."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Luôn cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập vào dữ liệu cảm biến cơ thể trong khi đang dùng ứng dụng?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Luôn cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; truy cập dữ liệu cảm biến cơ thể trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; khi dùng ứng dụng?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gửi thông báo cho bạn?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Cho phép &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; gửi thông báo cho bạn trên &lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Các quyền bị kiểm soát"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> có quyền truy cập thông tin vị trí"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Tổ chức của bạn cho phép <xliff:g id="APP_NAME">%1$s</xliff:g> truy cập thông tin vị trí của bạn"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Quyền khác"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Quyền mà hệ thống sử dụng"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Quyền mà chỉ có ứng dụng hệ thống sử dụng."</string>
@@ -519,7 +556,7 @@
<string name="blocked_camera_title" msgid="1128510551791284384">"Quyền truy cập vào máy ảnh của thiết bị đã bị chặn"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"Quyền truy cập vào micrô của thiết bị đã bị chặn"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"Tuỳ chọn vị trí thiết bị đang tắt"</string>
- <string name="blocked_sensor_summary" msgid="4443707628305027375">"Đối với các ứng dụng và dịch vụ"</string>
+ <string name="blocked_sensor_summary" msgid="4443707628305027375">"Áp dụng cho các ứng dụng và dịch vụ"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Dữ liệu thu được qua micrô vẫn có thể được chia sẻ khi bạn gọi đến số khẩn cấp."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Thay đổi"</string>
<string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Bảo mật và quyền riêng tư"</string>
@@ -537,8 +574,8 @@
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Kiểm tra trạng thái"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"Các chế độ kiểm soát quyền riêng tư"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"Tùy chọn cài đặt khác"</string>
- <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Truy cập máy ảnh"</string>
- <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Truy cập micrô"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Quyền truy cập camera"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Quyền truy cập micrô"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Đã thu hồi quyền sử dụng"</string>
<string name="camera_usage_qs" msgid="4394233566086665994">"Xem mức sử dụng của máy ảnh gần đây"</string>
<string name="microphone_usage_qs" msgid="8527666682168170417">"Xem mức sử dụng của micrô gần đây"</string>
@@ -577,20 +614,21 @@
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Xem lại ứng dụng có quyền truy cập thông tin vị trí ở chế độ nền"</string>
<string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ứng dụng này luôn truy cập được vào thông tin vị trí của bạn, kể cả khi đang đóng.\n\nMột số ứng dụng khẩn cấp và an toàn cần truy cập vào thông tin vị trí của bạn ở chế độ nền để hoạt động như mong đợi."</string>
<string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Đã thay đổi quyền truy cập"</string>
- <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Xem thông tin gần đây về việc sử dụng thông tin vị trí"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Xem thông tin về hoạt động sử dụng thông tin vị trí gần đây"</string>
<string name="privacy_controls_title" msgid="7605929972256835199">"Chế độ kiểm soát quyền riêng tư"</string>
- <string name="camera_toggle_title" msgid="1251201397431837666">"Quyền truy cập máy ảnh"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Quyền truy cập camera"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"Quyền truy cập micrô"</string>
- <string name="perm_toggle_description" msgid="7801326363741451379">"Đối với các ứng dụng và dịch vụ"</string>
- <string name="mic_toggle_description" msgid="9163104307990677157">"Đối với các ứng dụng và dịch vụ. Nếu chế độ cài đặt này tắt, dữ liệu thu được qua micrô vẫn có thể được chia sẻ khi bạn gọi đến số khẩn cấp."</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Áp dụng cho các ứng dụng và dịch vụ"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Áp dụng cho các ứng dụng và dịch vụ. Nếu bạn tắt chế độ cài đặt, dữ liệu thu được qua micrô vẫn có thể được chia sẻ khi bạn gọi đến số khẩn cấp."</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"Xem các ứng dụng và dịch vụ có quyền truy cập vào thông tin vị trí của thiết bị"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"Hiện quyền truy cập vào bảng nhớ tạm"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Hiện thông báo khi có ứng dụng truy cập vào văn bản, hình ảnh hoặc nội dung khác mà bạn đã sao chép"</string>
- <string name="show_password_title" msgid="2877269286984684659">"Hiển thị mật khẩu"</string>
- <string name="show_password_summary" msgid="1110166488865981610">"Hiển thị các ký tự ngắn gọn khi bạn nhập"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Hiện mật khẩu"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Hiện các ký tự trong thời gian ngắn khi bạn nhập"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Nhà phát triển nêu rõ ứng dụng này có thể chia sẻ dữ liệu vị trí với bên thứ ba"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Chia sẻ dữ liệu và thông tin vị trí"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Nguồn cung cấp thông tin về cách thức chia sẻ dữ liệu"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Nhà phát triển đã cung cấp cho nhà sản xuất thiết bị này thông tin về cách thức ứng dụng này chia sẻ dữ liệu. Nhà phát triển có thể cập nhật thông tin này theo thời gian."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Nhà phát triển đã cung cấp thông tin cho "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" về cách thức ứng dụng này chia sẻ dữ liệu. Nhà phát triển có thể cập nhật thông tin này theo thời gian."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Ứng dụng này có thể chia sẻ dữ liệu vị trí cho:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Nhiều cách thức chia sẻ dữ liệu"</string>
@@ -608,12 +646,10 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"An toàn dữ liệu"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Dữ liệu vị trí có thể được chia sẻ"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Nhà phát triển nêu rõ rằng ứng dụng này có thể chia sẻ dữ liệu vị trí với bên thứ ba"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Không mở được đường liên kết này"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Nội dung cập nhật về cách thức chia sẻ dữ liệu vị trí"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Xem xét những ứng dụng đã thay đổi cách thức có thể được dùng để chia sẻ dữ liệu vị trí của bạn"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Những ứng dụng này đã thay đổi cách thức có thể được dùng để chia sẻ dữ liệu vị trí của bạn. Có thể những ứng dụng này trước đây chưa từng chia sẻ dữ liệu vị trí, nhưng bây giờ mới chia sẻ dữ liệu đó nhằm mục đích quảng cáo hoặc tiếp thị."</string>
- <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Nhà phát triển của những ứng dụng này đã cung cấp thông tin cho cửa hàng ứng dụng về cách thức ứng dụng của họ chia sẻ dữ liệu. Họ có thể cập nhật thông tin này theo thời gian.\n\nCách thức chia sẻ dữ liệu có thể thay đổi tuỳ theo phiên bản ứng dụng, cách sử dụng, khu vực và độ tuổi của bạn."</string>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Nhà phát triển của những ứng dụng này đã cung cấp thông tin cho một cửa hàng ứng dụng về cách thức ứng dụng của họ chia sẻ dữ liệu. Họ có thể cập nhật thông tin này theo thời gian.\n\nCách thức chia sẻ dữ liệu có thể thay đổi tuỳ theo phiên bản ứng dụng, cách sử dụng, khu vực và độ tuổi của bạn."</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"Tìm hiểu về chế độ chia sẻ dữ liệu"</string>
<string name="shares_location_with_third_parties" msgid="2278051743742057767">"Dữ liệu vị trí của bạn nay được chia sẻ với bên thứ ba"</string>
<string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Dữ liệu vị trí của bạn giờ đây được chia sẻ với các bên thứ ba để quảng cáo hoặc tiếp thị"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Nội dung cập nhật về cách thức chia sẻ dữ liệu"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Một số ứng dụng đã thay đổi cách thức có thể được dùng để chia sẻ dữ liệu vị trí của bạn"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Cài đặt"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Truy cập lúc <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Truy cập hôm qua lúc <xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Truy cập lúc <xliff:g id="TIME_DATE_1">%2$s</xliff:g> ngày <xliff:g id="TIME_DATE_0">%1$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-w764dp-v33/layout.xml b/PermissionController/res/values-w764dp-v33/layout.xml
new file mode 100644
index 000000000..9035c8868
--- /dev/null
+++ b/PermissionController/res/values-w764dp-v33/layout.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <item name="action_button_list_responsive" type="layout">
+ @layout/action_button_list_large_screen
+ </item>
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-w764dp-v33/styles.xml b/PermissionController/res/values-w764dp-v33/styles.xml
index a836e4aa5..78f1bb42e 100644
--- a/PermissionController/res/values-w764dp-v33/styles.xml
+++ b/PermissionController/res/values-w764dp-v33/styles.xml
@@ -16,6 +16,16 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="SafetyCenterActionButton.Responsive">
+ <item name="android:paddingStart">@dimen/sc_button_horizontal_padding_large_screen</item>
+ <item name="android:paddingEnd">@dimen/sc_button_horizontal_padding_large_screen</item>
+ </style>
+
+ <style name="SecondarySafetyCenterActionButton.Responsive">
+ <item name="android:paddingStart">@dimen/sc_button_horizontal_padding_large_screen</item>
+ <item name="android:paddingEnd">@dimen/sc_button_horizontal_padding_large_screen</item>
+ </style>
+
<!-- START SAFETY STATUS CARD -->
<style name="SafetyCenterStatusTitleAndSummaryContainer.Responsive">
<item name="layout_constraintEnd_toStartOf">@id/sc_status_buttons_start_barrier</item>
@@ -30,8 +40,8 @@
<item name="layout_constraintStart_toEndOf">@id/status_title_and_summary</item>
<item name="layout_constraintEnd_toEndOf">parent</item>
<item name="android:layout_marginTop">@dimen/sc_spacing_xxsmall</item>
- <item name="android:paddingStart">@dimen/sc_large_screen_button_padding</item>
- <item name="android:paddingEnd">@dimen/sc_large_screen_button_padding</item>
+ <item name="android:paddingStart">@dimen/sc_button_horizontal_padding_large_screen</item>
+ <item name="android:paddingEnd">@dimen/sc_button_horizontal_padding_large_screen</item>
<!-- Clear the base style constraints so they don't conflict with this style's constraints
on the same sides. -->
<item name="layout_constraintTop_toBottomOf">@null</item>
diff --git a/PermissionController/res/values-watch/themes.xml b/PermissionController/res/values-watch/themes.xml
index 0e9b7a919..822bb55d1 100644
--- a/PermissionController/res/values-watch/themes.xml
+++ b/PermissionController/res/values-watch/themes.xml
@@ -21,6 +21,10 @@
<style name="Theme.PermissionController.Settings" parent="Settings" />
<style name="GrantPermissions" parent="@android:style/Theme.DeviceDefault.NoActionBar">
- <item name="android:windowBackground">@android:color/transparent</item>
</style>
+
+ <style name="RequestRole" parent="Settings" />
+
+ <style name="Theme.PermissionController.IncidentReportDialog"
+ parent="@android:style/Theme.DeviceDefault.Dialog.Alert" />
</resources>
diff --git a/PermissionController/res/values-zh-rCN-v33/strings.xml b/PermissionController/res/values-zh-rCN-v33/strings.xml
index 0e4242912..064e8b581 100644
--- a/PermissionController/res/values-zh-rCN-v33/strings.xml
+++ b/PermissionController/res/values-zh-rCN-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"更多提醒"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"忽略的提醒"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{展开并查看另外一项提醒}other{展开并查看另外 # 项提醒}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"提醒:<xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"操作完成"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"查看可提高设备安全性的设置"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"“安全和隐私”快捷设置"</string>
diff --git a/PermissionController/res/values-zh-rCN-v34/strings.xml b/PermissionController/res/values-zh-rCN-v34/strings.xml
index 0ba05798b..7bebdf9bc 100644
--- a/PermissionController/res/values-zh-rCN-v34/strings.xml
+++ b/PermissionController/res/values-zh-rCN-v34/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="security_privacy_brand_name" msgid="7303621734258440812">"安全和隐私"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"控件"</string>
- <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"健康数据共享"</string>
<string name="health_connect_summary" msgid="815473513776882296">"管理应用对健康数据的访问权限"</string>
<string name="location_settings" msgid="8863940440881290182">"位置信息访问权限"</string>
<string name="mic_toggle_description" msgid="1504101620086616040">"针对应用和服务。关闭此设置后,系统仍可能在您拨打紧急电话号码时分享麦克风数据"</string>
diff --git a/PermissionController/res/values-zh-rCN/strings.xml b/PermissionController/res/values-zh-rCN/strings.xml
index a87874676..932adbc58 100644
--- a/PermissionController/res/values-zh-rCN/strings.xml
+++ b/PermissionController/res/values-zh-rCN/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"更多信息"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"全部允许"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"始终全部允许"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"允许有限访问"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"选择照片和视频"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"选择更多"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"不选择更多数据"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"不选择其他数据"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"仍然不允许"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"关闭"</string>
<string name="current_permission_template" msgid="7452035392573329375">"第 <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> 项权限(共 <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> 项)"</string>
@@ -59,8 +60,9 @@
<string name="grant_dialog_button_allow_media_only" msgid="4832877658422573832">"允许访问媒体文件"</string>
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"应用"</string>
<string name="app_permissions" msgid="3369917736607944781">"应用权限"</string>
- <string name="unused_apps" msgid="2058057455175955094">"未使用的应用"</string>
- <string name="no_unused_apps" msgid="12809387670415295">"没有未使用的应用"</string>
+ <string name="unused_apps" msgid="2058057455175955094">"闲置应用"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"重选此应用可访问的照片"</string>
+ <string name="no_unused_apps" msgid="12809387670415295">"无闲置应用"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"没有未使用的应用"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"最近的权限决定"</string>
<string name="review_permission_decisions_view_all" msgid="90391040431566130">"查看最近的所有权限决定"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"所有权限"</string>
<string name="other_permissions" msgid="2901186127193849594">"其他应用功能"</string>
<string name="permission_request_title" msgid="8790310151025020126">"权限请求"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear 不支持安装/卸载操作。"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"请选择要向&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;授予哪些权限"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;已更新。请选择要向此应用授予哪些权限。"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"取消"</string>
@@ -196,15 +196,17 @@
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"使用确切位置"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"确切位置关闭时,应用可以获取您的大致位置"</string>
<string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g>权限"</string>
- <string name="app_permission_header" msgid="2951363137032603806">"是否允许这个应用访问<xliff:g id="PERM">%1$s</xliff:g>"</string>
+ <string name="app_permission_header" msgid="2951363137032603806">"是否允许此应用获得“<xliff:g id="PERM">%1$s</xliff:g>”权限"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"查看“<xliff:g id="APP">%1$s</xliff:g>”的所有权限"</string>
<string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"查看具有此权限的所有应用"</string>
<string name="assistant_mic_label" msgid="1011432357152323896">"显示 Google 助理麦克风使用情况"</string>
- <string name="unused_apps_category_title" msgid="2988455616845243901">"关于未使用应用的设置"</string>
+ <string name="unused_apps_category_title" msgid="2988455616845243901">"针对闲置应用的设置"</string>
<string name="auto_revoke_label" msgid="5068393642936571656">"如果未使用此应用,则移除相关权限"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"撤消权限并释放空间"</string>
- <string name="unused_apps_label_v2" msgid="7058776770056517980">"如果应用未使用,暂停其活动"</string>
+ <string name="unused_apps_label_v2" msgid="7058776770056517980">"暂停闲置应用的活动"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"管理闲置应用"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"移除权限、删除临时文件并停止发送通知"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"撤消权限、删除临时文件、停止发送通知并归档应用"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"为了保护您的数据,如果您连续几个月未使用此应用,系统会移除它的权限。"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"为了保护您的数据,如果您连续几个月未使用此应用,系统会移除其以下权限:<xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"为了保护您的数据,对于您连续几个月未使用过的应用,系统已将其权限移除。"</string>
@@ -218,7 +220,7 @@
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"已移除<xliff:g id="PERMISSION_NAME">%s</xliff:g>权限"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"已移除<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g>以及<xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>权限"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"已移除<xliff:g id="PERMISSION_NAME">%1$s</xliff:g>权限及另外 <xliff:g id="NUMBER">%2$s</xliff:g> 项权限"</string>
- <string name="unused_apps_page_title" msgid="6986983535677572559">"未使用的应用"</string>
+ <string name="unused_apps_page_title" msgid="6986983535677572559">"闲置应用"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"如果您连续几个月未使用某个应用,系统将对该应用采取以下措施:\n\n• 移除权限以保护您的数据\n• 停止通知功能以节省电量\n• 移除临时文件以释放空间\n\n如需重新授予权限以继续接收通知,请打开该应用。"</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"如果您连续 1 个月未使用某个应用,系统将对该应用采取以下措施:\n\n• 撤消权限以保护您的数据\n• 移除临时文件以释放空间\n\n如需重新授予权限,请打开该应用。"</string>
<string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{距上次打开已超过 # 个月}other{距上次打开已超过 # 个月}}"</string>
@@ -233,7 +235,7 @@
<string name="permission_description_summary_camera" msgid="108004375101882069">"具有此权限的应用可以拍摄照片和录制视频"</string>
<string name="permission_description_summary_contacts" msgid="2337798886460408996">"具有此权限的应用可以访问您的通讯录"</string>
<string name="permission_description_summary_location" msgid="2817531799933480694">"具有此权限的应用可以使用此设备的位置信息"</string>
- <string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"具有这项权限的应用可以查找、连接附近设备以及确定附近设备的相对位置"</string>
+ <string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"具有这项权限的应用可以查找、连接附近设备,以及确定附近设备的相对位置"</string>
<string name="permission_description_summary_microphone" msgid="630834800308329907">"具有此权限的应用可以录制音频"</string>
<string name="permission_description_summary_phone" msgid="4515277217435233619">"具有此权限的应用可以拨打电话及管理通话"</string>
<string name="permission_description_summary_sensors" msgid="1836045815643119949">"具有此权限的应用可以获取与您的生命体征相关的传感器数据"</string>
@@ -302,7 +304,7 @@
<string name="auto_revoke_before_notification_title_one" msgid="6758024954464359876">"1 个应用未使用"</string>
<string name="auto_revoke_before_notification_title_many" msgid="4415543943846385685">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> 个应用未使用"</string>
<string name="auto_revoke_before_notification_content_one" msgid="1156635373417068822">"为保护您的隐私,系统将移除这些权限。点按即可查看。"</string>
- <string name="unused_apps_title" msgid="8589298917717872239">"未使用的应用"</string>
+ <string name="unused_apps_title" msgid="8589298917717872239">"闲置应用"</string>
<string name="unused_apps_subtitle_after" msgid="2034267519506357898">"以下应用的权限已被移除"</string>
<string name="unused_apps_subtitle_before" msgid="5233302577076132427">"以下应用的权限将被移除"</string>
<string name="unused_permissions_subtitle_two" msgid="2207266295008423015">"“<xliff:g id="PERM_NAME_0">%1$s</xliff:g>”权限和“<xliff:g id="PERM_NAME_1">%2$s</xliff:g>”权限"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"记事应用"</string>
<string name="role_notes_description" msgid="8496852798616883551">"允许您在设备上记事的应用"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"记事"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"当前默认应用"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"不再询问"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"设为默认应用"</string>
@@ -455,59 +467,84 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"显示智能助理应用触发检测"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"使用麦克风激活语音助理后,在状态栏中显示相关图标"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$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_storage_isolated" msgid="5934218468708513375">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问&lt;b&gt;<xliff:g id="DEVICE">%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="2270563860206654757">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%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_device_aware_location" msgid="6641436550953715107">"要允许&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>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"要允许&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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"该应用可能想要随时获取您的位置信息(即使您并未使用该应用)。"<annotation id="link">"在“设置”中允许"</annotation>"。"</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"要更改&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;的位置信息访问权限吗?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"要更改&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的位置信息访问权限吗?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"该应用想要随时获取您的位置信息(即使您并未使用该应用)。"<annotation id="link">"在“设置”中允许"</annotation>"。"</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”查找、连接到附近设备以及确定附近设备的相对位置吗?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上查找、连接到附近设备及确定附近设备相对位置吗?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;查找、连接附近设备以及确定附近设备的相对位置吗?"<annotation id="link">"您可以在“设置”中允许。"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"要将“<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>”可以使用的位置信息从大致位置改为确切位置吗?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"要将<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>在&lt;b&gt;<xliff:g id="DEVICE">%2$s</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="9001956706241104626">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;获取&lt;b&gt;<xliff:g id="DEVICE">%2$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_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="3103987548035171850">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%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;发送和查看短信吗?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上发送和查看短信吗?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"要允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”&lt;b&gt;&lt;/b&gt;访问您设备上的照片、媒体内容和文件吗?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的照片、媒体和文件吗?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”访问此设备上的&lt;b&gt;照片、视频、音乐和音频&lt;/b&gt;吗?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”访问此设备上的&lt;b&gt;照片、视频、音乐、音频和其他文件&lt;/b&gt;吗?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问此设备上的音乐和音频吗?"</string>
- <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问此设备上的照片和视频吗?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上访问音乐和音频吗?"</string>
+ <string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”访问此设备上的照片和视频吗?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的照片和视频吗?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问此设备上的更多照片和视频?"</string>
- <string name="permgrouprequest_microphone" msgid="2825208549114811299">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;录音吗?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的更多照片和视频吗?"</string>
+ <string name="permgrouprequest_microphone" msgid="2825208549114811299">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”录音吗?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上录音吗?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"此应用将只能在您使用它时录音"</string>
- <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;录音吗?"</string>
+ <string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”录音吗?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上录音吗?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"此应用可能想要随时录音,即使在您未使用它的时候。"<annotation id="link">"您可以在“设置”中授权"</annotation>"。"</string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"要更改&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;的麦克风使用权限吗?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"要更改&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的麦克风使用权限吗?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"此应用想要随时录音,即使在您未使用它的时候。"<annotation id="link">"您可以在“设置”中授权"</annotation>"。"</string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;获取您的身体活动数据吗?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上访问您的身体活动记录吗?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”拍摄照片和录制视频吗?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上拍照片和录视频吗?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"此应用将只能在您使用它时拍摄照片和录制视频"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”拍摄照片和录制视频吗?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上拍照片和录视频吗?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"此应用可能想要随时拍摄照片和录制视频,即使在您未使用它的时候。"<annotation id="link">"您可以在“设置”中授权"</annotation>"。"</string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"要更改&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;的相机使用权限吗?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"要更改&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的相机使用权限吗?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"此应用想要随时拍摄照片和录制视频,即使在您未使用它的时候。"<annotation id="link">"您可以在“设置”中授权"</annotation>"。"</string>
- <string name="permgrouprequest_calllog" msgid="2065327180175371397">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问您的手机通话记录吗?"</string>
- <string name="permgrouprequest_phone" msgid="1829234136997316752">"允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”拨打电话和管理通话吗?"</string>
+ <string name="permgrouprequest_calllog" msgid="2065327180175371397">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”访问您的手机通话记录吗?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上访问您的手机通话记录吗?"</string>
+ <string name="permgrouprequest_phone" msgid="1829234136997316752">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”拨打电话和管理通话吗?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上拨打电话和管理通话吗?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问与您的生命体征相关的传感器数据吗?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上访问与您生命体征相关的传感器数据吗?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"此应用希望随时都能访问与您的生命体征相关的传感器数据(即使在您未使用此应用时)。如要进行这种权限更改,请"<annotation id="link">"前往设置页面"</annotation>"。"</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问与您的生命体征相关的传感器数据吗?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上访问与您生命体征相关的传感器数据吗?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"如要允许此应用始终可以访问身体传感器数据(即使在您未使用此应用时),请"<annotation id="link">"前往设置"</annotation>"。"</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"始终允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”在使用中时访问身体传感器数据?"</string>
- <string name="permgrouprequest_notifications" msgid="6396739062335106181">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;向您发送通知吗?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"要始终允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;于使用期间在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上访问身体传感器数据吗?"</string>
+ <string name="permgrouprequest_notifications" msgid="6396739062335106181">"要允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”向您发送通知吗?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"要允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上向您发送通知吗?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"受控权限"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"<xliff:g id="APP_NAME">%1$s</xliff:g> 具有位置信息访问权限"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"您的组织允许 <xliff:g id="APP_NAME">%1$s</xliff:g> 访问位置信息"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"其他权限"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"系统使用的权限"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"仅限系统应用使用的权限"</string>
<string name="additional_permissions_label" msgid="7693557637462569046">"其他权限"</string>
<string name="additional_permissions_description" msgid="2186611950890732112">"应用定义的权限"</string>
- <string name="privdash_label_camera" msgid="1426440033626198096">"摄像头"</string>
+ <string name="privdash_label_camera" msgid="1426440033626198096">"相机"</string>
<string name="privdash_label_microphone" msgid="8415035835803511693">"麦克风"</string>
<string name="privdash_label_location" msgid="6882400763866489291">"位置信息"</string>
<string name="privdash_label_other" msgid="3710394147423236033">"其他"</string>
@@ -515,7 +552,7 @@
<string name="privdash_label_24h" msgid="1512532123865375319">"过去 24 小时\n"</string>
<string name="privdash_label_7d" msgid="5645301995348656931">"过去\n7 天"</string>
<string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”受 Android 保护。由于您的数据是在此设备上处理,因此状态栏或隐私信息中心不会显示这个应用的权限使用情况。"</string>
- <string name="exempt_info_label" msgid="6286190981253476699">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”受 Android 保护。由于您的数据是在此设备上处理,因此隐私信息中心不会显示这个应用的权限使用情况。"</string>
+ <string name="exempt_info_label" msgid="6286190981253476699">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”受 Android 保护。由于您的数据是在此设备上处理的,因此隐私信息中心不会显示该应用的权限使用情况。"</string>
<string name="blocked_camera_title" msgid="1128510551791284384">"设备摄像头已被屏蔽"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"设备麦克风已被屏蔽"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"设备位置信息功能已关闭"</string>
@@ -537,7 +574,7 @@
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"查看状态"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"您的隐私控制项"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"更多设置"</string>
- <string name="camera_toggle_label_qs" msgid="3880261453066157285">"相机使用权限"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"摄像头使用权限"</string>
<string name="microphone_toggle_label_qs" msgid="8132912469813396552">"麦克风使用权限"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"已移除权限"</string>
<string name="camera_usage_qs" msgid="4394233566086665994">"查看近期相机使用情况"</string>
@@ -588,9 +625,10 @@
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"系统会在应用访问您复制的文字、图片或其他内容时显示一条消息"</string>
<string name="show_password_title" msgid="2877269286984684659">"显示密码"</string>
<string name="show_password_summary" msgid="1110166488865981610">"输入时短暂显示字符"</string>
- <string name="permission_rationale_message_location" msgid="2153841534298068414">"此应用已声明它可能会与第三方共享位置数据"</string>
+ <string name="permission_rationale_message_location" msgid="2153841534298068414">"此应用已声明它可能会与第三方分享位置数据"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"数据分享和位置信息"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"数据分享信息的来源"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"开发者已将此应用的数据分享方式相关信息提供给此设备的制造商。开发者可能会随时间推移更新此信息。"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"开发者已将此应用的数据分享方式相关信息提供给"<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"。开发者可能会随时间推移更新此信息。"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"此应用可能会出于以下目的分享位置数据:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"数据分享因情况而异"</string>
@@ -604,12 +642,10 @@
<string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"广告或营销"</string>
<string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"欺诈防范、安全和法规遵从"</string>
<string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"个性化"</string>
- <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"帐号管理"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"账号管理"</string>
<string name="app_permission_rationale_message" msgid="8511466916077100713">"数据安全"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"可能会分享位置数据"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"此应用已声明它可能会与第三方分享您的位置数据"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"无法打开此链接"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"位置数据分享方面的更新"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"查看改变了位置数据分享方式的应用"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"这些应用改变了它们在分享您位置数据上的做法。它们之前可能未分享过位置数据,也可能现在是为了广告或营销目的而分享此类数据。"</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"数据分享方式变更"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"部分应用更改了位置数据分享方式"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"设置"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"<xliff:g id="TIME_DATE">%1$s</xliff:g>访问过"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"昨天<xliff:g id="TIME_DATE">%1$s</xliff:g>访问过"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"<xliff:g id="TIME_DATE_0">%1$s</xliff:g><xliff:g id="TIME_DATE_1">%2$s</xliff:g>访问过"</string>
</resources>
diff --git a/PermissionController/res/values-zh-rHK-car/strings.xml b/PermissionController/res/values-zh-rHK-car/strings.xml
index fae91ec10..1c9959056 100644
--- a/PermissionController/res/values-zh-rHK-car/strings.xml
+++ b/PermissionController/res/values-zh-rHK-car/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="unused_apps_page_summary" msgid="7505839764289846511">"如果您在過去幾個月未曾使用應用程式,系統將會:\n\n• 移除權限以保護您的資料\n• 移除暫存檔案以騰出空間"</string>
+ <string name="unused_apps_page_summary" msgid="7505839764289846511">"如果你在過去幾個月未曾使用應用程式,系統將會:\n\n• 移除權限以保護你的資料\n• 移除暫存檔案以騰出空間"</string>
</resources>
diff --git a/PermissionController/res/values-zh-rHK-television/strings.xml b/PermissionController/res/values-zh-rHK-television/strings.xml
index dd90168f9..4a8a23848 100644
--- a/PermissionController/res/values-zh-rHK-television/strings.xml
+++ b/PermissionController/res/values-zh-rHK-television/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="grant_dialog_button_deny_dont_ask_again" msgid="747769682501286250">"拒絕,不要再詢問"</string>
- <string name="grant_dialog_how_to_change" msgid="997462845048160559">"您稍後可以在 [設定] &gt; [應用程式] 中變更這項設定"</string>
+ <string name="grant_dialog_how_to_change" msgid="997462845048160559">"你稍後可以在 [設定] &gt; [應用程式] 中變更這項設定"</string>
<string name="current_permission_template" msgid="6240787325714651204">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> / <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
<string name="preference_show_system_apps" msgid="4262140518693221093">"顯示系統應用程式"</string>
<string name="app_permissions_decor_title" msgid="7438716722786036814">"應用程式權限"</string>
diff --git a/PermissionController/res/values-zh-rHK-v33/strings.xml b/PermissionController/res/values-zh-rHK-v33/strings.xml
index 27174dbb3..da31b6eae 100644
--- a/PermissionController/res/values-zh-rHK-v33/strings.xml
+++ b/PermissionController/res/values-zh-rHK-v33/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="role_dialer_request_description" msgid="6188305064871543419">"此應用程式將可傳送通知,並能存取您的相機、通訊錄、麥克風、電話及短訊"</string>
- <string name="role_sms_request_description" msgid="1506966389698625395">"此應用程式將可傳送通知,並能存取您的相機、通訊錄、檔案、麥克風、電話及短訊"</string>
+ <string name="role_dialer_request_description" msgid="6188305064871543419">"此應用程式將可傳送通知,並能存取你的相機、通訊錄、麥克風、電話及短訊"</string>
+ <string name="role_sms_request_description" msgid="1506966389698625395">"此應用程式將可傳送通知,並能存取你的相機、通訊錄、檔案、麥克風、電話及短訊"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"擁有此權限的應用程式可存取此裝置上的所有檔案"</string>
- <string name="work_policy_title" msgid="832967780713677409">"您的工作政策資料"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"你的工作政策資料"</string>
<string name="work_policy_summary" msgid="3886113358084963931">"由 IT 管理員管理的設定"</string>
<string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"展開並顯示清單"</string>
<string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"收合清單並隱藏設定"</string>
diff --git a/PermissionController/res/values-zh-rHK-v34/strings.xml b/PermissionController/res/values-zh-rHK-v34/strings.xml
index 99e078541..65ad05bdb 100644
--- a/PermissionController/res/values-zh-rHK-v34/strings.xml
+++ b/PermissionController/res/values-zh-rHK-v34/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="security_privacy_brand_name" msgid="7303621734258440812">"安全性和私隱權"</string>
+ <string name="security_privacy_brand_name" msgid="7303621734258440812">"保安和私隱"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"控制項"</string>
<string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
<string name="health_connect_summary" msgid="815473513776882296">"管理應用程式的健康資料存取權"</string>
diff --git a/PermissionController/res/values-zh-rHK/strings.xml b/PermissionController/res/values-zh-rHK/strings.xml
index f2546c69c..612572808 100644
--- a/PermissionController/res/values-zh-rHK/strings.xml
+++ b/PermissionController/res/values-zh-rHK/strings.xml
@@ -34,9 +34,10 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"更多資料"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"全部允許"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"一律全部允許"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"允許有限存取"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"選取相片和影片"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"選取更多項目"</string>
- <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"不選取更多資料"</string>
+ <string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"不選取更多"</string>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"一律不允許"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"關閉"</string>
<string name="current_permission_template" msgid="7452035392573329375">"第 <xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> 個 (共 <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g> 個)"</string>
@@ -60,17 +61,18 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"應用程式"</string>
<string name="app_permissions" msgid="3369917736607944781">"應用程式權限"</string>
<string name="unused_apps" msgid="2058057455175955094">"不使用的應用程式"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"設定此應用程式可存取哪些相片"</string>
<string name="no_unused_apps" msgid="12809387670415295">"沒有不使用的應用程式"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"沒有未使用的應用程式"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"最近的權限決定"</string>
<string name="review_permission_decisions_view_all" msgid="90391040431566130">"查看所有最近的權限決定"</string>
<string name="review_permission_decisions_empty" msgid="8120775336417279806">"最近沒有權限決定"</string>
<string name="auto_permission_manager_summary" msgid="9157438376234301354">"管理日曆、通話記錄等項目的資料存取權"</string>
- <string name="granted_permission_decision" msgid="7824827491551861365">"您已允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取<xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
- <string name="denied_permission_decision" msgid="5308961501779563781">"您已拒絕「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取<xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
+ <string name="granted_permission_decision" msgid="7824827491551861365">"你已允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取<xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
+ <string name="denied_permission_decision" msgid="5308961501779563781">"你已拒絕「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取<xliff:g id="PERMISSION_NAME">%2$s</xliff:g>"</string>
<string name="days_ago" msgid="6650359081551335629">"{count,plural, =0{今天}=1{1 天前}other{# 天前}}"</string>
<string name="app_disable_dlg_positive" msgid="7418444149981904940">"停用應用程式"</string>
- <string name="app_disable_dlg_text" msgid="3126943217146120240">"如果您停用此應用程式,Android 和其他應用程式可能無法正常運作。請謹記,由於此應用程式已在您的裝置預先安裝,因此無法刪除。停用後,您便可在裝置上關閉並隱藏此應用程式。"</string>
+ <string name="app_disable_dlg_text" msgid="3126943217146120240">"如果你停用此應用程式,Android 和其他應用程式可能無法正常運作。請謹記,由於此應用程式已在你的裝置預先安裝,因此無法刪除。停用後,你便可在裝置上關閉並隱藏此應用程式。"</string>
<string name="app_permission_manager" msgid="3903811137630909550">"權限管理工具"</string>
<string name="never_ask_again" msgid="4728762438198560329">"不要再詢問"</string>
<string name="no_permissions" msgid="3881676756371148563">"沒有權限"</string>
@@ -90,11 +92,11 @@
<string name="manage_permission" msgid="2895385393037061964">"管理權限"</string>
<string name="no_apps" msgid="2412612731628386816">"沒有應用程式"</string>
<string name="location_settings" msgid="3624412509133422562">"位置設定"</string>
- <string name="location_warning" msgid="2381649060929040962">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為此裝置提供定位服務。您可以在位置設定中更改位置存取權。"</string>
- <string name="system_warning" msgid="1173400963234358816">"如果您拒絕授予此權限,裝置的基本功能或會無法正常運作。"</string>
+ <string name="location_warning" msgid="2381649060929040962">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為此裝置提供定位服務。你可以在位置設定中更改位置存取權。"</string>
+ <string name="system_warning" msgid="1173400963234358816">"如果你拒絕授予此權限,裝置的基本功能或會無法正常運作。"</string>
<string name="deny_read_media_visual_warning" msgid="3982586279917232827">"此應用程式專為舊版 Android 而設。如果拒絕此應用程式存取相片和影片,此應用程式亦無法存取音樂和其他音訊。"</string>
<string name="deny_read_media_aural_warning" msgid="8928699919508646732">"此應用程式專為舊版 Android 而設。如果拒絕此應用程式存取音樂和其他音訊,此應用程式亦無法存取相片和影片。"</string>
- <string name="cdm_profile_revoke_warning" msgid="4443893270719106700">"如果您拒絕授予此權限,裝置上受此應用程式管理的部分功能可能無法正常運作。"</string>
+ <string name="cdm_profile_revoke_warning" msgid="4443893270719106700">"如果你拒絕授予此權限,裝置上受此應用程式管理的部分功能可能無法正常運作。"</string>
<string name="permission_summary_enforced_by_policy" msgid="4443598170942950519">"已根據政策執行"</string>
<string name="permission_summary_disabled_by_policy_background_only" msgid="221995005556362660">"已根據政策停用背景存取權"</string>
<string name="permission_summary_enabled_by_policy_background_only" msgid="8287675974767104279">"已根據政策啟用背景存取權"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"所有權限"</string>
<string name="other_permissions" msgid="2901186127193849594">"其他應用程式功能"</string>
<string name="permission_request_title" msgid="8790310151025020126">"權限要求"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear 不支援安裝/解除安裝操作。"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"選擇允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取的內容"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"已更新「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;。選擇允許此應用程式存取的內容。"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"取消"</string>
@@ -132,7 +132,7 @@
<string name="perm_usage_adv_info_summary_more_items" msgid="949055326299562218">"<xliff:g id="PERMGROUP_0">%1$s</xliff:g>、<xliff:g id="PERMGROUP_1">%2$s</xliff:g> 和另外 <xliff:g id="NUM">%3$s</xliff:g> 個"</string>
<string name="permission_group_usage_subtitle_24h" msgid="5120155996322114181">"過去 24 小時內應用程式使用「<xliff:g id="PERMGROUP">%1$s</xliff:g>」權限的時間軸"</string>
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"過去 7 天內應用程式使用「<xliff:g id="PERMGROUP">%1$s</xliff:g>」權限的時間軸"</string>
- <string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"當此應用程式使用您的<xliff:g id="PERMGROUP">%1$s</xliff:g>權限時"</string>
+ <string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"當此應用程式使用你的<xliff:g id="PERMGROUP">%1$s</xliff:g>權限時"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"瞭解詳情"</string>
<string name="learn_more_content_description" msgid="8673699744544502539">"進一步瞭解「<xliff:g id="PERMGROUP">%1$s</xliff:g>」"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"控制應用程式<xliff:g id="PERMGROUP">%1$s</xliff:g>存取權"</string>
@@ -194,7 +194,7 @@
<string name="precise_image_description" msgid="6349638632303619872">"精確位置"</string>
<string name="approximate_image_description" msgid="938803699637069884">"概略位置"</string>
<string name="app_permission_location_accuracy" msgid="7166912915040018669">"使用精確位置"</string>
- <string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"關閉精確位置後,應用程式可存取您的概略位置"</string>
+ <string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"關閉精確位置後,應用程式可存取你的概略位置"</string>
<string name="app_permission_title" msgid="2090897901051370711">"<xliff:g id="PERM">%1$s</xliff:g>權限"</string>
<string name="app_permission_header" msgid="2951363137032603806">"這個應用程式的<xliff:g id="PERM">%1$s</xliff:g>存取權"</string>
<string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"查看「<xliff:g id="APP">%1$s</xliff:g>」的所有權限"</string>
@@ -204,10 +204,12 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"如不使用應用程式,即移除權限"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"移除權限並騰出空間"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"暫停未使用應用程式的活動"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"管理應用程式 (如未使用)"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"移除權限、刪除暫存檔案和停止通知"</string>
- <string name="auto_revoke_summary" msgid="5867548789805911683">"為保護您的資料,系統已移除您在過去幾個月未曾使用的應用程式的權限。"</string>
- <string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"為保護您的資料,如果應用程式在過去幾個月未曾使用,系統將會移除以下權限:<xliff:g id="PERMS">%1$s</xliff:g>。"</string>
- <string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"為保護您的資料,系統已移除您在過去幾個月未曾使用的應用程式的權限。"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"移除權限、刪除暫存檔案、停止通知和封存應用程式"</string>
+ <string name="auto_revoke_summary" msgid="5867548789805911683">"為保護你的資料,系統已移除你在過去幾個月未曾使用的應用程式的權限。"</string>
+ <string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"為保護你的資料,如果應用程式在過去幾個月未曾使用,系統將會移除以下權限:<xliff:g id="PERMS">%1$s</xliff:g>。"</string>
+ <string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"為保護你的資料,系統已移除你在過去幾個月未曾使用的應用程式的權限。"</string>
<string name="auto_revoke_open_app_message" msgid="8075556291711205039">"如要重新授予權限,請開啟應用程式。"</string>
<string name="auto_revoke_disabled" msgid="8697684442991567188">"此應用程式已停用自動移除功能。"</string>
<string name="auto_revocable_permissions_none" msgid="8334929619113991466">"目前沒有授予任何自動撤銷權限"</string>
@@ -219,19 +221,19 @@
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"已移除「<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g>」及「<xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>」權限"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"已移除「<xliff:g id="PERMISSION_NAME">%1$s</xliff:g>」及另外 <xliff:g id="NUMBER">%2$s</xliff:g> 個權限"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"不使用的應用程式"</string>
- <string name="unused_apps_page_summary" msgid="1867593913217272155">"如果應用程式在過去幾個月未曾使用,系統將會:\n\n• 移除權限以保護您的資料\n• 停止顯示通知以節省電量\n• 移除暫存檔案以騰出空間\n\n如要重新允許權限和通知,請開啟應用程式。"</string>
- <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"如果您在過去一個月未曾使用應用程式,系統將會:\n\n• 移除權限以保護您的資料\n• 移除暫存檔案以騰出空間\n\n如要再次允許權限,請開啟應用程式。"</string>
+ <string name="unused_apps_page_summary" msgid="1867593913217272155">"如果應用程式在過去幾個月未曾使用,系統將會:\n\n• 移除權限以保護你的資料\n• 停止顯示通知以節省電量\n• 移除暫存檔案以騰出空間\n\n如要重新允許權限和通知,請開啟應用程式。"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"如果你在過去一個月未曾使用應用程式,系統將會:\n\n• 移除權限以保護你的資料\n• 移除暫存檔案以騰出空間\n\n如要再次允許權限,請開啟應用程式。"</string>
<string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{距離上次開啟已超過 # 個月}other{距離上次開啟已超過 # 個月}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"應用程式上次於 <xliff:g id="DATE">%s</xliff:g>開啟"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"上次開啟日期:<xliff:g id="DATE">%s</xliff:g>"</string>
- <string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"如允許管理所有檔案,此應用程式便可存取、修改和刪除此裝置或已連接儲存裝置上一般儲存的任何檔案。應用程式可能會在未通知您的情況下存取檔案。"</string>
- <string name="special_file_access_dialog" msgid="583804114020740610">"要允許此應用程式存取、修改和刪除此裝置或任何已連接儲存裝置上的檔案嗎?此應用程式可能會在未通知您的情況下存取檔案。"</string>
+ <string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"如允許管理所有檔案,此應用程式便可存取、修改和刪除此裝置或已連接儲存裝置上一般儲存的任何檔案。應用程式可能會在未通知你的情況下存取檔案。"</string>
+ <string name="special_file_access_dialog" msgid="583804114020740610">"要允許此應用程式存取、修改和刪除此裝置或任何已連接儲存裝置上的檔案嗎?此應用程式可能會在未通知你的情況下存取檔案。"</string>
<string name="permission_description_summary_generic" msgid="5401399408814903391">"擁有此權限的應用程式可以<xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
- <string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"擁有此權限的應用程式可以存取您的體能活動資料,例如步行、踏單車、駕駛、步數及其他資料"</string>
- <string name="permission_description_summary_calendar" msgid="103329982944411010">"擁有此權限的應用程式可以存取您的日曆"</string>
+ <string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"擁有此權限的應用程式可以存取你的體能活動資料,例如步行、踏單車、駕駛、步數及其他資料"</string>
+ <string name="permission_description_summary_calendar" msgid="103329982944411010">"擁有此權限的應用程式可以存取你的日曆"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"擁有此權限的應用程式可以讀取及寫入手機通話記錄"</string>
<string name="permission_description_summary_camera" msgid="108004375101882069">"擁有此權限的應用程式可以拍照及錄製影片"</string>
- <string name="permission_description_summary_contacts" msgid="2337798886460408996">"擁有此權限的應用程式可以存取您的通訊錄"</string>
+ <string name="permission_description_summary_contacts" msgid="2337798886460408996">"擁有此權限的應用程式可以存取你的通訊錄"</string>
<string name="permission_description_summary_location" msgid="2817531799933480694">"擁有此權限的應用程式可以存取此裝置的位置資訊"</string>
<string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"擁有此權限的應用程式可以尋找和連接附近的裝置,並可判斷附近裝置的相對位置"</string>
<string name="permission_description_summary_microphone" msgid="630834800308329907">"擁有此權限的應用程式可以錄音"</string>
@@ -260,7 +262,7 @@
<string name="permission_reminders" msgid="6528257957664832636">"權限提醒"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 個不使用的應用程式"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> 個不使用的應用程式"</string>
- <string name="auto_revoke_permission_reminder_notification_content" msgid="4492228990462107487">"為保護您的私隱,系統已移除權限。輕按即可查看"</string>
+ <string name="auto_revoke_permission_reminder_notification_content" msgid="4492228990462107487">"為保護你的私隱,系統已移除權限。輕按即可查看"</string>
<string name="auto_revoke_permission_notification_title" msgid="2629844160853454657">"已移除沒有用過的應用程式的權限"</string>
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"部分應用程式在過去幾個月都沒有用過。輕按即可查看。"</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# 個未使用的應用程式}other{# 個未使用的應用程式}}"</string>
@@ -269,28 +271,28 @@
<string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"如果應用程式已沒有使用一段時間,系統會移除權限和臨時檔案,並停止顯示通知。"</string>
<string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"查看應用程式"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"查看最近授予的權限"</string>
- <string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"您在駕駛時已將<xliff:g id="PERMISSION">%2$s</xliff:g>的存取權授予「<xliff:g id="APP">%1$s</xliff:g>」"</string>
- <string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"您在駕駛時已將<xliff:g id="PERMISSION_1">%2$s</xliff:g>和<xliff:g id="PERMISSION_2">%3$s</xliff:g>的存取權授予「<xliff:g id="APP">%1$s</xliff:g>」"</string>
- <string name="post_drive_permission_decision_reminder_summary_1_app_multi_permission" msgid="4080701771111456927">"您在駕駛時已將 <xliff:g id="COUNT">%1$d</xliff:g> 項權限授予「<xliff:g id="APP">%2$s</xliff:g>」"</string>
- <string name="post_drive_permission_decision_reminder_summary_multi_apps" msgid="5253882771252863902">"{count,plural, =1{您在駕駛時已將存取權授予「<xliff:g id="APP_0">%1$s</xliff:g>」和另外 # 個應用程式}other{您在駕駛時已將存取權授予「<xliff:g id="APP_1">%1$s</xliff:g>」和另外 # 個應用程式}}"</string>
+ <string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"你在駕駛時已將<xliff:g id="PERMISSION">%2$s</xliff:g>的存取權授予「<xliff:g id="APP">%1$s</xliff:g>」"</string>
+ <string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"你在駕駛時已將<xliff:g id="PERMISSION_1">%2$s</xliff:g>和<xliff:g id="PERMISSION_2">%3$s</xliff:g>的存取權授予「<xliff:g id="APP">%1$s</xliff:g>」"</string>
+ <string name="post_drive_permission_decision_reminder_summary_1_app_multi_permission" msgid="4080701771111456927">"你在駕駛時已將 <xliff:g id="COUNT">%1$d</xliff:g> 項權限授予「<xliff:g id="APP">%2$s</xliff:g>」"</string>
+ <string name="post_drive_permission_decision_reminder_summary_multi_apps" msgid="5253882771252863902">"{count,plural, =1{你在駕駛時已將存取權授予「<xliff:g id="APP_0">%1$s</xliff:g>」和另外 # 個應用程式}other{你在駕駛時已將存取權授予「<xliff:g id="APP_1">%1$s</xliff:g>」和另外 # 個應用程式}}"</string>
<string name="go_to_settings" msgid="1053735612211228335">"前往「設定」"</string>
<string name="auto_revoke_setting_subtitle" msgid="8631720570723050460">"部分應用程式在過去幾個月都沒有用過。"</string>
<string name="permissions_removed_category_title" msgid="1064754271178447643">"已移除權限的應用程式"</string>
<string name="permission_removed_page_title" msgid="2627436155091001209">"權限已移除的應用程式"</string>
<string name="all_unused_apps_category_title" msgid="755663524704745414">"所有沒有用過的應用程式"</string>
<string name="months_ago" msgid="1766026492610646354">"<xliff:g id="COUNT">%1$d</xliff:g> 個月前"</string>
- <string name="auto_revoke_preference_summary" msgid="5517958331781391481">"為保護您的私隱,系統已移除權限"</string>
- <string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g>在背景存取了您的位置資訊"</string>
- <string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"此應用程式可隨時存取您的位置資訊。輕按即可變更權限。"</string>
+ <string name="auto_revoke_preference_summary" msgid="5517958331781391481">"為保護你的私隱,系統已移除權限"</string>
+ <string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g>在背景存取了你的位置資訊"</string>
+ <string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"此應用程式可隨時存取你的位置資訊。輕按即可變更權限。"</string>
<string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"查看擁有通知存取權的應用程式"</string>
<string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> 可關閉通知內容、對內容採取動作以及存取內容"</string>
- <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"此應用程式可讓您關閉/存取通知中的內容或執行操作。有些應用程式需要此權限才能正常運作。"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"此應用程式可讓你關閉/存取通知中的內容或執行操作。有些應用程式需要此權限才能正常運作。"</string>
<string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"移除存取權"</string>
<string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"查看更多選項"</string>
<string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"已移除存取權"</string>
<string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"查看擁有完整裝置存取權的應用程式"</string>
<string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"「<xliff:g id="APP_NAME">%s</xliff:g>」可以查看裝置畫面並在裝置上執行操作。無障礙應用程式需要取得這種存取權才能發揮功用。"</string>
- <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"此應用程式可以查看裝置畫面並在裝置上執行操作。無障礙應用程式需要取得這種存取權才能發揮功用,但請確認您信任此應用程式。"</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"此應用程式可以查看裝置畫面並在裝置上執行操作。無障礙應用程式需要取得這種存取權才能發揮功用,但請確認你信任此應用程式。"</string>
<string name="accessibility_remove_access_button_label" msgid="44145801526711640">"移除存取權"</string>
<string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"查看擁有完整存取權的應用程式"</string>
<string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"已移除存取權"</string>
@@ -301,14 +303,14 @@
<string name="auto_revoke_after_notification_content_many" msgid="4774106206289751220">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」和另外 <xliff:g id="NUMBER_OF_APPS">%2$s</xliff:g> 個應用程式在過去幾個月未有使用。輕按即可查看。"</string>
<string name="auto_revoke_before_notification_title_one" msgid="6758024954464359876">"1 個應用程式未有使用"</string>
<string name="auto_revoke_before_notification_title_many" msgid="4415543943846385685">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> 個應用程式未有使用"</string>
- <string name="auto_revoke_before_notification_content_one" msgid="1156635373417068822">"為保護您的私隱,系統將會移除權限。輕按即可查看。"</string>
+ <string name="auto_revoke_before_notification_content_one" msgid="1156635373417068822">"為保護你的私隱,系統將會移除權限。輕按即可查看。"</string>
<string name="unused_apps_title" msgid="8589298917717872239">"不使用的應用程式"</string>
<string name="unused_apps_subtitle_after" msgid="2034267519506357898">"已移除以下應用程式的權限"</string>
<string name="unused_apps_subtitle_before" msgid="5233302577076132427">"系統將會移除以下應用程式的權限"</string>
<string name="unused_permissions_subtitle_two" msgid="2207266295008423015">"<xliff:g id="PERM_NAME_0">%1$s</xliff:g>和<xliff:g id="PERM_NAME_1">%2$s</xliff:g>"</string>
<string name="unused_permissions_subtitle_many" msgid="4387289202207450238">"<xliff:g id="PERM_NAME_0">%1$s</xliff:g>、<xliff:g id="PERM_NAME_1">%2$s</xliff:g> 和另外 <xliff:g id="NUMBER_OF_PERMISSIONS">%3$s</xliff:g> 個權限"</string>
- <string name="unused_app_permissions_removed_summary" msgid="6779039455326071033">"為保護您的資料,系統已移除您在過去幾個月未使用應用程式的權限"</string>
- <string name="unused_app_permissions_removed_summary_some" msgid="5080490037831563441">"為保護您的資料,系統已移除您在過去幾個月沒有用過的部分應用程式的權限。"</string>
+ <string name="unused_app_permissions_removed_summary" msgid="6779039455326071033">"為保護你的資料,系統已移除你在過去幾個月未使用應用程式的權限"</string>
+ <string name="unused_app_permissions_removed_summary_some" msgid="5080490037831563441">"為保護你的資料,系統已移除你在過去幾個月沒有用過的部分應用程式的權限。"</string>
<string name="one_unused_app_summary" msgid="7831913934488881991">"1 個應用程式在過去幾個月未曾使用"</string>
<string name="num_unused_apps_summary" msgid="1870719749940571227">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> 個應用程式在過去幾個月未曾使用"</string>
<string name="permission_subtitle_only_in_foreground" msgid="9068389431267377564">"只在使用應用程式時"</string>
@@ -343,64 +345,74 @@
<string name="no_apps_denied" msgid="7663435886986784743">"沒有拒絕任何應用程式"</string>
<string name="car_permission_selected" msgid="180837028920791596">"已選取"</string>
<string name="settings" msgid="5409109923158713323">"設定"</string>
- <string name="accessibility_service_dialog_title_single" msgid="7956432823014102366">"<xliff:g id="SERVICE_NAME">%s</xliff:g>可以取得您裝置的完整存取權"</string>
- <string name="accessibility_service_dialog_title_multiple" msgid="5527879210683548175">"<xliff:g id="NUM_SERVICES">%s</xliff:g> 個無障礙應用程式可以取得您裝置的完整存取權"</string>
- <string name="accessibility_service_dialog_bottom_text_single" msgid="1128666197822205958">"「<xliff:g id="SERVICE_NAME">%s</xliff:g>」可以查看您的螢幕、操作和輸入內容、執行操作以及控制顯示屏。"</string>
- <string name="accessibility_service_dialog_bottom_text_multiple" msgid="7009848932395519852">"這些應用程式可以查看您的螢幕、動作和輸入內容、執行動作以及控制顯示屏。"</string>
+ <string name="accessibility_service_dialog_title_single" msgid="7956432823014102366">"<xliff:g id="SERVICE_NAME">%s</xliff:g>可以取得你裝置的完整存取權"</string>
+ <string name="accessibility_service_dialog_title_multiple" msgid="5527879210683548175">"<xliff:g id="NUM_SERVICES">%s</xliff:g> 個無障礙應用程式可以取得你裝置的完整存取權"</string>
+ <string name="accessibility_service_dialog_bottom_text_single" msgid="1128666197822205958">"「<xliff:g id="SERVICE_NAME">%s</xliff:g>」可以查看你的螢幕、操作和輸入內容、執行操作以及控制顯示屏。"</string>
+ <string name="accessibility_service_dialog_bottom_text_multiple" msgid="7009848932395519852">"這些應用程式可以查看你的螢幕、動作和輸入內容、執行動作以及控制顯示屏。"</string>
<string name="role_assistant_label" msgid="4727586018198208128">"預設數碼助理應用程式"</string>
<string name="role_assistant_short_label" msgid="3369003713187703399">"數碼助理應用程式"</string>
- <string name="role_assistant_description" msgid="6622458130459922952">"小幫手應用程式能根據您正在查看的螢幕資訊提供協助。部分應用程式可同時支援啟動器及語音輸入服務,以提供更全面的協助。"</string>
+ <string name="role_assistant_description" msgid="6622458130459922952">"小幫手應用程式能根據你正在查看的螢幕資訊提供協助。部分應用程式可同時支援啟動器及語音輸入服務,以提供更全面的協助。"</string>
<string name="role_browser_label" msgid="2877796144554070207">"預設瀏覽器應用程式"</string>
<string name="role_browser_short_label" msgid="6745009127123292296">"瀏覽器應用程式"</string>
- <string name="role_browser_description" msgid="3465253637499842671">"此類應用程式可讓您存取互聯網,並會顯示您輕按的連結"</string>
+ <string name="role_browser_description" msgid="3465253637499842671">"此類應用程式可讓你存取互聯網,並會顯示你輕按的連結"</string>
<string name="role_browser_request_title" msgid="2895200507835937192">"要將 <xliff:g id="APP_NAME">%1$s</xliff:g> 設為預設瀏覽器應用程式嗎?"</string>
<string name="role_browser_request_description" msgid="5888803407905985941">"無需任何權限"</string>
<string name="role_dialer_label" msgid="1100224146343237968">"預設電話應用程式"</string>
<string name="role_dialer_short_label" msgid="7186888549465352489">"手機應用程式"</string>
- <string name="role_dialer_description" msgid="8768708633696539612">"此類應用程式允許您使用自己的裝置撥打和接聽電話"</string>
+ <string name="role_dialer_description" msgid="8768708633696539612">"此類應用程式允許你使用自己的裝置撥打和接聽電話"</string>
<string name="role_dialer_request_title" msgid="5959618560705912058">"要將「<xliff:g id="APP_NAME">%1$s</xliff:g>」設為預設手機應用程式嗎?"</string>
- <string name="role_dialer_request_description" msgid="6288839625724909320">"此應用程式將可存取您的相機、通訊錄、麥克風、電話及短訊"</string>
+ <string name="role_dialer_request_description" msgid="6288839625724909320">"此應用程式將可存取你的相機、通訊錄、麥克風、電話及短訊"</string>
<string name="role_dialer_search_keywords" msgid="3324448983559188087">"撥號器"</string>
<string name="role_sms_label" msgid="8456999857547686640">"預設短訊應用程式"</string>
<string name="role_sms_short_label" msgid="4371444488034692243">"短訊應用程式"</string>
- <string name="role_sms_description" msgid="3424020199148153513">"此類應用程式允許您使用自己手機號碼傳送和接收短訊、相片、影片和其他資料"</string>
+ <string name="role_sms_description" msgid="3424020199148153513">"此類應用程式允許你使用自己手機號碼傳送和接收短訊、相片、影片和其他資料"</string>
<string name="role_sms_request_title" msgid="7953552109601185602">"要將「<xliff:g id="APP_NAME">%1$s</xliff:g>」設為預設短訊應用程式嗎?"</string>
- <string name="role_sms_request_description" msgid="2691004766132144886">"此應用程式將可存取您的相機、通訊錄、檔案和媒體、麥克風、電話及短訊"</string>
+ <string name="role_sms_request_description" msgid="2691004766132144886">"此應用程式將可存取你的相機、通訊錄、檔案和媒體、麥克風、電話及短訊"</string>
<string name="role_sms_search_keywords" msgid="8022048144395047352">"短訊, 發短訊, 訊息, 傳送短訊"</string>
<string name="role_emergency_label" msgid="7028825857206842366">"預設緊急應用程式"</string>
<string name="role_emergency_short_label" msgid="2388431453335350348">"緊急應用程式"</string>
- <string name="role_emergency_description" msgid="5051840234887686630">"此類應用程式可讓您記錄及供救援人員存取醫療資訊、獲取惡劣天氣事件和災難事件警示,以及在需要幫助時通知他人"</string>
+ <string name="role_emergency_description" msgid="5051840234887686630">"此類應用程式可讓你記錄及供救援人員存取醫療資訊、獲取惡劣天氣事件和災難事件警示,以及在需要幫助時通知他人"</string>
<string name="role_emergency_request_title" msgid="8469579020654348567">"要將 <xliff:g id="APP_NAME">%1$s</xliff:g> 設為預設緊急應用程式嗎?"</string>
<string name="role_emergency_request_description" msgid="131645948770262850">"無需任何權限"</string>
<string name="role_emergency_search_keywords" msgid="1920007722599213358">"ICE"</string>
<string name="role_home_label" msgid="3871847846649769412">"預設主畫面應用程式"</string>
<string name="role_home_short_label" msgid="8544733747952272337">"主畫面應用程式"</string>
- <string name="role_home_description" msgid="7997371519626556675">"這類應用程式通常稱為啟動器,可以取代 Android 裝置的主畫面,讓您存取裝置的內容和功能"</string>
+ <string name="role_home_description" msgid="7997371519626556675">"這類應用程式通常稱為啟動器,可以取代 Android 裝置的主畫面,讓你存取裝置的內容和功能"</string>
<string name="role_home_request_title" msgid="738136983453341081">"要將「<xliff:g id="APP_NAME">%1$s</xliff:g>」設為預設主畫面應用程式嗎?"</string>
<string name="role_home_request_description" msgid="2658833966716057673">"無需任何權限"</string>
<string name="role_home_search_keywords" msgid="3830755001192666285">"啟動器"</string>
<string name="role_call_redirection_label" msgid="5785304207206147590">"預設通話重新導向應用程式"</string>
<string name="role_call_redirection_short_label" msgid="7568143419571217757">"通話重新導向應用程式"</string>
- <string name="role_call_redirection_description" msgid="6091669882014664420">"此類應用程式允許您將撥出電話轉駁至其他手機號碼"</string>
+ <string name="role_call_redirection_description" msgid="6091669882014664420">"此類應用程式允許你將撥出電話轉駁至其他手機號碼"</string>
<string name="role_call_redirection_request_title" msgid="2816244455003562925">"要將「<xliff:g id="APP_NAME">%1$s</xliff:g>」設為預設通話重新導向應用程式嗎?"</string>
<string name="role_call_redirection_request_description" msgid="3118895714178527164">"無需任何權限"</string>
<string name="role_call_screening_label" msgid="883935222060878724">"預設來電顯示與騷擾電話應用程式"</string>
<string name="role_call_screening_short_label" msgid="2048465565063130834">"來電顯示與垃圾郵件應用程式"</string>
- <string name="role_call_screening_description" msgid="2349431420497468981">"此類應用程式讓您識別來電,並封鎖垃圾電話、錄音電話或騷擾電話號碼"</string>
+ <string name="role_call_screening_description" msgid="2349431420497468981">"此類應用程式讓你識別來電,並封鎖垃圾電話、錄音電話或騷擾電話號碼"</string>
<string name="role_call_screening_request_title" msgid="7358309224566977290">"要將「<xliff:g id="APP_NAME">%1$s</xliff:g>」設為預設來電顯示與垃圾郵件應用程式嗎?"</string>
<string name="role_call_screening_request_description" msgid="7338511921032446006">"無需任何權限"</string>
<string name="role_automotive_navigation_label" msgid="2701890757955474751">"預設導航應用程式"</string>
<string name="role_automotive_navigation_short_label" msgid="5165823092506922457">"導航應用程式"</string>
- <string name="role_automotive_navigation_description" msgid="7834601873792870134">"可提供名勝地點搜尋和行車路線導航指引的應用程式"</string>
+ <string name="role_automotive_navigation_description" msgid="7834601873792870134">"可提供興趣點搜尋和行車路線導航指引的應用程式"</string>
<string name="role_automotive_navigation_request_title" msgid="7525693151489384300">"要將「<xliff:g id="APP_NAME">%1$s</xliff:g>」設定為預設導航應用程式嗎?"</string>
<string name="role_automotive_navigation_request_description" msgid="7073023813249245540">"無需任何權限"</string>
- <string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> 將可與您的通知互動,並可存取電話、短訊、聯絡人和日曆。"</string>
+ <string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> 將可與你的通知互動,並可存取電話、短訊、聯絡人和日曆。"</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知,並可在已連結的裝置上串流播放應用程式。"</string>
- <string name="role_companion_device_computer_description" msgid="416099879217066377">"此服務會將您手機中的相片、媒體和通知與其他裝置共用。"</string>
+ <string name="role_companion_device_computer_description" msgid="416099879217066377">"此服務會將你手機中的相片、媒體和通知與其他裝置共用。"</string>
<string name="role_notes_label" msgid="7451627001058089536">"預設筆記應用程式"</string>
<string name="role_notes_short_label" msgid="8796604147546125285">"筆記應用程式"</string>
- <string name="role_notes_description" msgid="8496852798616883551">"讓您可以在裝置上寫筆記的應用程式"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"讓你可以在裝置上寫筆記的應用程式"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"筆記"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"目前預設"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"不要再詢問"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"設定為預設"</string>
@@ -436,14 +448,14 @@
<string name="no_special_app_access" msgid="6950277571805106247">"沒有特別應用程式權限"</string>
<string name="special_app_access_no_apps" msgid="4102911722787886970">"沒有應用程式"</string>
<string name="home_missing_work_profile_support" msgid="1756855847669387977">"不支援工作設定檔"</string>
- <string name="encryption_unaware_confirmation_message" msgid="8274491794636402484">"請注意:如果您重新啟動裝置並設定了螢幕鎖定,就必須先將裝置解鎖,才可執行這個應用程式。"</string>
+ <string name="encryption_unaware_confirmation_message" msgid="8274491794636402484">"請注意:如果你重新啟動裝置並設定了螢幕鎖定,就必須先將裝置解鎖,才可執行這個應用程式。"</string>
<string name="assistant_confirmation_message" msgid="7476540402884416212">"這個小幫手將能讀取系統目前使用的應用程式資料,包括螢幕顯示的資料或可在應用程式中存取的資料。"</string>
<string name="incident_report_channel_name" msgid="3144954065936288440">"分享偵錯資料"</string>
<string name="incident_report_notification_title" msgid="4635984625656519773">"要分享詳細的偵錯資料嗎?"</string>
<string name="incident_report_notification_text" msgid="3376480583513587923">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」要求上載偵錯資料。"</string>
<string name="incident_report_dialog_title" msgid="669104389325204095">"分享偵錯資料?"</string>
<string name="incident_report_dialog_intro" msgid="5897733669850951832">"系統偵測到問題。"</string>
- <string name="incident_report_dialog_text" msgid="5675553296891757523">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」要求上載此裝置於 <xliff:g id="DATE">%2$s</xliff:g><xliff:g id="TIME">%3$s</xliff:g>傳送的錯誤報告。錯誤報告包括您的裝置或應用程式記錄的個人資料,例如使用者名稱、位置資料、裝置識別碼和網絡資訊。只與您信任可存取這些資料的使用者和應用程式分享錯誤報告。要允許「<xliff:g id="APP_NAME_1">%4$s</xliff:g>」上載錯誤報告嗎?"</string>
+ <string name="incident_report_dialog_text" msgid="5675553296891757523">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」要求上載此裝置於 <xliff:g id="DATE">%2$s</xliff:g><xliff:g id="TIME">%3$s</xliff:g>傳送的錯誤報告。錯誤報告包括你的裝置或應用程式記錄的個人資料,例如使用者名稱、位置資料、裝置識別碼和網絡資訊。只與你信任可存取這些資料的使用者和應用程式分享錯誤報告。要允許「<xliff:g id="APP_NAME_1">%4$s</xliff:g>」上載錯誤報告嗎?"</string>
<string name="incident_report_error_dialog_text" msgid="4189647113387092272">"系統處理「<xliff:g id="APP_NAME">%1$s</xliff:g>」的錯誤報告時發生錯誤,因此已拒絕分享詳細的偵錯資料。很抱歉發生中斷情況。"</string>
<string name="incident_report_dialog_allow_label" msgid="2970242967721155239">"允許"</string>
<string name="incident_report_dialog_deny_label" msgid="3535314290677579383">"拒絕"</string>
@@ -454,52 +466,79 @@
<string name="adjust_user_sensitive_per_app_header" msgid="4543506440989005648">"突顯以下應用程式的使用情況"</string>
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"顯示「Google 助理」觸發偵測"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"使用麥克風啟用語音助手時,在狀態列中顯示圖示"</string>
- <string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取您裝置上的相片和媒體嗎?"</string>
- <string name="permgrouprequest_contacts" msgid="8391550064551053695">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取您的聯絡人嗎?"</string>
+ <string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取你裝置上的相片和媒體嗎?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的相片和媒體嗎?"</string>
+ <string name="permgrouprequest_contacts" msgid="8391550064551053695">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取你的聯絡人嗎?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的通訊錄嗎?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取此裝置的位置資訊嗎?"</string>
- <string name="permgrouprequestdetail_location" msgid="2635935335778429894">"此應用程式目前只有您在使用時才能存取位置資訊"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"允許 &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">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取此裝置的位置資訊嗎?"</string>
- <string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"此應用程式可能想一直存取您的位置 (包括您沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"允許 &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="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"此應用程式可能想一直存取你的位置 (包括你沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」的位置存取權嗎?"</string>
- <string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"此應用程式想一直存取您的位置 (包括您沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"要變更你&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"此應用程式想一直存取你的位置 (包括你沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"要允許&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;尋找、連接及判斷附近裝置的相對位置嗎?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上尋找、連接及判斷附近裝置的相對位置嗎?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"要允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 尋找、連接及判斷附近裝置的相對位置嗎?"<annotation id="link">"請在設定中授予權限。"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"要將<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>存取的位置資訊從概略位置改為精確位置嗎?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"要將 <xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> 在你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的位置資訊存取權從概略位置變更為精確位置嗎?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取此裝置的概略位置資訊嗎?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$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_calendar" msgid="1493150855673603806">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取您的日曆嗎?"</string>
+ <string name="permgrouprequest_calendar" msgid="1493150855673603806">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取你的日曆嗎?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的日曆嗎?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;傳送和查看短訊嗎?"</string>
- <string name="permgrouprequest_storage" msgid="8717773092518621602">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取您裝置上的相片、媒體和檔案嗎?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上傳送和查看短訊嗎?"</string>
+ <string name="permgrouprequest_storage" msgid="8717773092518621602">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取你裝置上的相片、媒體和檔案嗎?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的相片、媒體和檔案嗎?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"要允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取此裝置上的&lt;b&gt;相片、影片、音樂和音訊&lt;/b&gt;嗎?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"要允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取此裝置上的&lt;b&gt;相片、影片、音樂、音訊和其他檔案&lt;/b&gt;嗎?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"要允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取此裝置上的音樂和音訊嗎?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的音樂和音訊嗎?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"要允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取此裝置上的相片和影片嗎?"</string>
- <string name="permgrouprequest_more_photos" msgid="128933814654231321">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取此裝置上的相片和影片嗎?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的相片和影片嗎?"</string>
+ <string name="permgrouprequest_more_photos" msgid="128933814654231321">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取此裝置上更多的相片和影片?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的相片和影片嗎?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;錄音嗎?"</string>
- <string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"此應用程式將只能在您使用期間錄音"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上錄音嗎?"</string>
+ <string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"此應用程式將只能在你使用期間錄音"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;錄音嗎?"</string>
- <string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"此應用程式可能會要求隨時錄音 (包括您沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上錄音嗎?"</string>
+ <string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"此應用程式可能會要求隨時錄音 (包括你沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;?的麥克風存取權嗎?"</string>
- <string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"此應用程式想隨時錄音 (包括您沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
- <string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取您的體能活動嗎?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"要變更你&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"此應用程式想隨時錄音 (包括你沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
+ <string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取你的體能活動嗎?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的體能活動嗎?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;拍照和錄製影片嗎?"</string>
- <string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"此應用程式將只能在您使用期間拍照及錄影"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上拍照和錄製影片嗎?"</string>
+ <string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"此應用程式將只能在你使用期間拍照及錄影"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;拍照和錄製影片嗎?"</string>
- <string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"此應用程式可能會要求隨時拍照及錄影 (包括您沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上拍照和錄製影片嗎?"</string>
+ <string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"此應用程式可能會要求隨時拍照及錄影 (包括你沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;?的相機存取權嗎?"</string>
- <string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"此應用程式想隨時拍照及錄影 (包括您沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
- <string name="permgrouprequest_calllog" msgid="2065327180175371397">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取您的手機通話記錄嗎?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"要變更你&lt;b&gt;<xliff:g id="DEVICE">%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="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"此應用程式想隨時拍照及錄影 (包括你沒有使用此應用程式時)。"<annotation id="link">"在設定中允許存取。"</annotation></string>
+ <string name="permgrouprequest_calllog" msgid="2065327180175371397">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取你的手機通話記錄嗎?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的手機通話記錄嗎?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;撥打電話和管理通話嗎?"</string>
- <string name="permgrouprequest_sensors" msgid="4397358316850652235">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取與您身體機能相關的感應器資料嗎?"</string>
- <string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"此應用程式要求持續存取與您生命體徵相關的感應器資料 (即使在您沒有使用此應用程式時)。如要變更,請"<annotation id="link">"前往設定。"</annotation></string>
- <string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取與您生命體徵相關的感應器資料嗎?"</string>
- <string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"如要讓此應用程式隨時存取人體感應器資料 (即使在您沒有使用此應用程式時),請"<annotation id="link">"前往設定"</annotation>"。"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上撥打電話和管理通話嗎?"</string>
+ <string name="permgrouprequest_sensors" msgid="4397358316850652235">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取與你身體機能相關的感應器資料嗎?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取與你生命徵象相關的感應器資料嗎?"</string>
+ <string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"此應用程式要求持續存取與你生命體徵相關的感應器資料 (即使在你沒有使用此應用程式時)。如要變更,請"<annotation id="link">"前往設定。"</annotation></string>
+ <string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取與你生命體徵相關的感應器資料嗎?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 存取你&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上與你生命徵象相關的感應器資料嗎?"</string>
+ <string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"如要讓此應用程式隨時存取人體感應器資料 (即使在你沒有使用此應用程式時),請"<annotation id="link">"前往設定"</annotation>"。"</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"要讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」應用程式&lt;b&gt;&lt;/b&gt;在使用時存取人體感應器資料嗎?"</string>
- <string name="permgrouprequest_notifications" msgid="6396739062335106181">"要允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 傳送通知給您嗎?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"要繼續允許&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在應用程式使用期間存取&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;的人體感應器資料嗎?"</string>
+ <string name="permgrouprequest_notifications" msgid="6396739062335106181">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;傳送通知給你嗎?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"允許 &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 在你的&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上傳送通知給你嗎?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"由管理員控制的權限"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」具有位置存取權"</string>
- <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"貴機構允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取你的位置資訊"</string>
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」有位置存取權"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"你的機構允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取位置資訊"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"其他權限"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"系統使用的權限"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"僅系統應用程式使用的權限。"</string>
@@ -512,15 +551,15 @@
<string name="privdash_label_none" msgid="5991866260360484858">"無"</string>
<string name="privdash_label_24h" msgid="1512532123865375319">"過去\n24 小時"</string>
<string name="privdash_label_7d" msgid="5645301995348656931">"過去\n7 天內"</string>
- <string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"<xliff:g id="APP_NAME">%1$s</xliff:g> 受 Android 保護。系統會在此裝置上處理您的資料,因此狀態列或私隱資訊主頁不會顯示此應用程式的權限使用情況。"</string>
- <string name="exempt_info_label" msgid="6286190981253476699">"<xliff:g id="APP_NAME">%1$s</xliff:g> 受 Android 保護。系統會在此裝置上處理您的資料,因此私隱資訊主頁不會顯示此應用程式的權限使用情況。"</string>
+ <string name="exempt_mic_camera_info_label" msgid="6273581737010902815">"<xliff:g id="APP_NAME">%1$s</xliff:g> 受 Android 保護。系統會在此裝置上處理你的資料,因此狀態列或私隱資訊主頁不會顯示此應用程式的權限使用情況。"</string>
+ <string name="exempt_info_label" msgid="6286190981253476699">"<xliff:g id="APP_NAME">%1$s</xliff:g> 受 Android 保護。系統會在此裝置上處理你的資料,因此私隱資訊主頁不會顯示此應用程式的權限使用情況。"</string>
<string name="blocked_camera_title" msgid="1128510551791284384">"已封鎖裝置相機"</string>
<string name="blocked_microphone_title" msgid="1631517143648232585">"已封鎖裝置麥克風"</string>
<string name="blocked_location_title" msgid="2005608279812892383">"已關閉裝置位置"</string>
<string name="blocked_sensor_summary" msgid="4443707628305027375">"應用程式和服務"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"撥打緊急電話號碼時,系統仍可能會分享麥克風資料。"</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"變更"</string>
- <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"安全性和私隱權"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"保安和私隱"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"掃瞄裝置"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"關閉"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"要關閉此警示嗎?"</string>
@@ -531,9 +570,9 @@
<string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"安全性和私隱狀態。<xliff:g id="OVERALL_SAFETY_STATUS">%1$s</xliff:g>。<xliff:g id="SUMMARY_OF_DEVICE_STATUS">%2$s</xliff:g>"</string>
<string name="security_settings" msgid="3808106921175271317">"安全性設定"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"權限"</string>
- <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"安全性和私隱權"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"保安和私隱"</string>
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"檢查狀態"</string>
- <string name="privacy_controls_qs" msgid="5780144882040591169">"您的私隱權設定"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"你的私隱權設定"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"更多設定"</string>
<string name="camera_toggle_label_qs" msgid="3880261453066157285">"相機存取權"</string>
<string name="microphone_toggle_label_qs" msgid="8132912469813396552">"麥克風存取權"</string>
@@ -571,30 +610,31 @@
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"此應用程式不支援 Android 最新版本。如果此應用程式可存取相片和影片,也就能存取音樂和音訊檔案。"</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"此應用程式不支援 Android 最新版本。如果此應用程式無法存取音樂和音訊檔案,也就無法存取相片和影片。"</string>
<string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"查看擁有背景位置資訊存取權的應用程式"</string>
- <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"「<xliff:g id="APP_NAME">%s</xliff:g>」可隨時存取您的位置,即使應用程式關閉時亦然"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"「<xliff:g id="APP_NAME">%s</xliff:g>」可隨時存取你的位置,即使應用程式關閉時亦然"</string>
<string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"查看擁有背景位置資訊存取權的應用程式"</string>
- <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"此應用程式可隨時存取您的位置,即使應用程式關閉時亦然。\n\n部分安全和緊急應用程式需要在背景存取您的位置,才能正常運作。"</string>
+ <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="camera_toggle_title" msgid="1251201397431837666">"相機存取權"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"麥克風存取權"</string>
<string name="perm_toggle_description" msgid="7801326363741451379">"應用程式和服務"</string>
- <string name="mic_toggle_description" msgid="9163104307990677157">"應用程式和服務。如果關閉此設定,系統仍會在您撥打緊急電話號碼時提供麥克風的資料。"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"應用程式和服務。如果關閉此設定,系統仍會在你撥打緊急電話號碼時提供麥克風的資料。"</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"查看有權存取位置的應用程式和服務"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"顯示剪貼簿存取通知"</string>
- <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"系統會在應用程式存取您複製的文字、圖片或其他內容時顯示訊息"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"系統會在應用程式存取你複製的文字、圖片或其他內容時顯示訊息"</string>
<string name="show_password_title" msgid="2877269286984684659">"顯示密碼"</string>
<string name="show_password_summary" msgid="1110166488865981610">"輸入時短暫顯示字元"</string>
<string name="permission_rationale_message_location" msgid="2153841534298068414">"此應用程式表明可能會與第三方分享位置資料"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"資料分享和位置"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"資料分享詳情的來源"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"開發人員向此裝置的製造商提供資料,說明此應用程式的資料分享方式,並可能會隨時間更新。"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"開發人員向"<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>"提供資料,說明此應用程式的資料分享方式,並可能會隨時間更新。"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"應用程式可能分享位置資料作以下用途:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"資料分享方式因情況而異"</string>
<string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"資料處理方法可因應用程式版本、使用情況、所在地區和年齡而異。"<annotation id="link">"進一步瞭解資料分享"</annotation></string>
<string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"資料處理方法可因應用程式版本、使用情況、所在地區和年齡而異。"</string>
- <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"您的位置資料"</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"你的位置資料"</string>
<string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"如要變更此應用程式的存取權,請前往"<annotation id="link">"私隱權設定"</annotation></string>
<string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"應用程式功能"</string>
<string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"數據分析"</string>
@@ -605,19 +645,20 @@
<string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"帳戶管理"</string>
<string name="app_permission_rationale_message" msgid="8511466916077100713">"資料安全"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"系統可能會分享位置資料"</string>
- <string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"此應用程式表明可能會與第三方分享您的位置資料"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"無法開啟此連結"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
+ <string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"此應用程式表明可能會與第三方分享你的位置資料"</string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"位置資料分享更新"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"查看已變更位置資料分享方式的應用程式"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"這些應用程式已變更位置資料分享方式。它們可能未曾分享位置資料,或現在可能分享這些資料作廣告或市場推廣用途。"</string>
<string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"這些應用程式的開發人員向應用程式商店提供資料分享做法相關資料,並可能會隨時間更新這些資料。\n\n資料分享方法可因應用程式版本、使用情況、所在地區和年齡而異。"</string>
<string name="learn_about_data_sharing" msgid="4200480587079488045">"進一步瞭解資料分享"</string>
- <string name="shares_location_with_third_parties" msgid="2278051743742057767">"您的位置資料現已與第三方分享"</string>
- <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"您的位置資料現已與第三方分享,以作廣告或市場推廣用途"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"你的位置資料現已與第三方分享"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"你的位置資料現已與第三方分享,以作廣告或市場推廣用途"</string>
<string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{於過去一天內更新}=1{於過去一天內更新}other{於過去 # 天內更新}}"</string>
<string name="no_updates_at_this_time" msgid="9031085635689982935">"目前沒有更新"</string>
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"資料分享更新"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"部分應用程式已變更位置資料分享方式"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"設定"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"上次存取時間:<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"上次存取時間:昨天<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"上次存取時間:<xliff:g id="TIME_DATE_0">%1$s</xliff:g><xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-zh-rTW-v34/strings.xml b/PermissionController/res/values-zh-rTW-v34/strings.xml
index 2ac35c5d0..533a95e78 100644
--- a/PermissionController/res/values-zh-rTW-v34/strings.xml
+++ b/PermissionController/res/values-zh-rTW-v34/strings.xml
@@ -19,9 +19,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="security_privacy_brand_name" msgid="7303621734258440812">"安全性與隱私權"</string>
<string name="privacy_subpage_controls_header" msgid="4152396976713749322">"控制選項"</string>
- <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"健康資料同步"</string>
<string name="health_connect_summary" msgid="815473513776882296">"管理應用程式的健康資料存取權"</string>
<string name="location_settings" msgid="8863940440881290182">"位置資訊存取權"</string>
- <string name="mic_toggle_description" msgid="1504101620086616040">"適用於應用程式和服務。如果關閉這項設定,系統仍會在你撥打緊急電話號碼時分享麥克風的資料"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"適用於應用程式和服務。即使關閉這項設定,系統仍可能會在你撥打緊急電話號碼時,分享麥克風資料"</string>
<string name="location_settings_subtitle" msgid="6846532794702613851">"應用程式和服務"</string>
</resources>
diff --git a/PermissionController/res/values-zh-rTW/strings.xml b/PermissionController/res/values-zh-rTW/strings.xml
index 90524a7cc..8535ccc6f 100644
--- a/PermissionController/res/values-zh-rTW/strings.xml
+++ b/PermissionController/res/values-zh-rTW/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"更多資訊"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"全部允許"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"一律全部允許"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"允許有限存取"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"選取相片和影片"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"選取更多項目"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"不要選取其他資料"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"應用程式"</string>
<string name="app_permissions" msgid="3369917736607944781">"應用程式權限"</string>
<string name="unused_apps" msgid="2058057455175955094">"未使用的應用程式"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"設定這個應用程式可存取哪些相片"</string>
<string name="no_unused_apps" msgid="12809387670415295">"沒有未使用的應用程式"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"沒有未使用的應用程式"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"最近的權限決定"</string>
@@ -83,7 +85,7 @@
<string name="default_permission_description" msgid="4624464917726285203">"執行不明的動作"</string>
<string name="app_permissions_group_summary" msgid="8788419008958284002">"已授權給 <xliff:g id="COUNT_0">%1$d</xliff:g> 個應用程式 (共 <xliff:g id="COUNT_1">%2$d</xliff:g> 個)"</string>
<string name="app_permissions_group_summary2" msgid="4329922444840521150">"已授權給 <xliff:g id="COUNT_0">%1$d</xliff:g> 個應用程式 (共 <xliff:g id="COUNT_1">%2$d</xliff:g> 個)"</string>
- <string name="menu_show_system" msgid="4254021607027872504">"顯示系統程序"</string>
+ <string name="menu_show_system" msgid="4254021607027872504">"顯示系統設定"</string>
<string name="menu_hide_system" msgid="3855390843744028465">"隱藏系統程序"</string>
<string name="menu_show_7_days_data" msgid="8979611198508523706">"顯示過去 7 天內的使用情況"</string>
<string name="menu_show_24_hours_data" msgid="8228054833323380780">"顯示過去 24 小時內的使用情況"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"所有權限"</string>
<string name="other_permissions" msgid="2901186127193849594">"其他應用程式功能"</string>
<string name="permission_request_title" msgid="8790310151025020126">"權限要求"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Wear 不支援安裝及解除安裝操作。"</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"選擇要授予「<xliff:g id="APP_NAME">%1$s</xliff:g>」的存取權"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」已更新。請選擇要授予這個應用程式的存取權。"</string>
<string name="review_button_cancel" msgid="2191147944056548886">"取消"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"如果應用程式未使用,讓系統移除相關權限"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"移除權限並釋出空間"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"暫停未使用的應用程式活動"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"管理應用程式 (如未使用)"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"移除權限、刪除暫存檔及停止通知"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"移除權限、刪除暫存檔、停止通知並封存應用程式"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"為了保護你的資料,如果你連續幾個月都未使用這個應用程式,系統會移除其權限。"</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"為了保護你的資料,如果應用程式已有數個月未使用,系統將移除以下權限:<xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"為了保護你的資料,針對數個月未使用的應用程式,系統已移除相關權限。"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"記事應用程式"</string>
<string name="role_notes_description" msgid="8496852798616883551">"可在裝置上記事的應用程式"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"記事"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"目前的預設應用程式"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"不要再詢問"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"設為預設"</string>
@@ -455,48 +467,75 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"顯示個人助理觸發偵測圖示"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"使用麥克風啟用語音小幫手時,在狀態列顯示相關圖示"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取裝置中的相片和媒體嗎?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取相片和媒體嗎?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取你的聯絡人嗎?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取你的聯絡人嗎?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取這部裝置的位置資訊嗎?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt;的位置資訊嗎?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"該應用程式只有在你使用時,才能存取位置資訊"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取這部裝置的位置資訊嗎?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>的位置資訊嗎?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"這個應用程式可能會要求隨時存取你的位置資訊 (即使在你未使用此應用程式時)。"<annotation id="link">"如要授予權限,請前往「設定」"</annotation>"。"</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」的位置資訊存取權嗎?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的位置資訊存取權嗎?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"這個應用程式想要隨時存取你的位置資訊 (即使在你未使用此應用程式時)。"<annotation id="link">"如要授予權限,請前往「設定」"</annotation>"。"</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;尋找、連結及判斷附近裝置的相對位置嗎?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上尋找鄰近裝置、與其連線並判斷相對位置嗎?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;尋找、連結及判斷附近裝置的相對位置嗎?"<annotation id="link">"請前往「設定」授予權限。"</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"要將「<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>」可以存取的定位資訊從「概略位置」改為「精確位置」嗎?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"要在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上將「<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>」的位置資訊存取權從大概變更為精確嗎?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取這部裝置的概略位置資訊嗎?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;/b&gt;存取&lt;b&gt;<xliff:g id="DEVICE">%2$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_calendar" msgid="1493150855673603806">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取你的日曆嗎?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取你的日曆嗎?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」傳送及查看簡訊嗎?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上傳送及查看簡訊嗎?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取裝置中的相片、媒體和檔案嗎?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取相片、媒體和檔案嗎?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取這部裝置上的&lt;b&gt;相片、影片、音樂和音訊&lt;/b&gt;嗎?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取這部裝置上的&lt;b&gt;相片、影片、音樂、音訊和其他檔案&lt;/b&gt;嗎?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取這部裝置上的音樂和音訊嗎?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取音樂和音訊嗎?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取這部裝置上的相片和影片嗎?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取相片和影片嗎?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取這部裝置上的其他相片和影片嗎?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取更多相片和影片嗎?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」錄音嗎?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上錄音嗎?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"這個應用程式只有在你使用時才能錄音"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」錄音嗎?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上錄音嗎?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"這個應用程式要求取得隨時都能錄音的權限,即使你當下並未使用該應用程式。"<annotation id="link">"如要授予權限,請前往設定頁面。"</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」的麥克風存取權嗎?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的麥克風存取權嗎?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"這個應用程式想取得隨時都能錄音的權限,即使你當下並未使用該應用程式。"<annotation id="link">"如要授予權限,請前往設定頁面。"</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取你的體能活動記錄嗎?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取你的體能活動嗎?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」拍攝相片及錄製影片嗎?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上拍照及錄影嗎?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"這個應用程式只有在你使用時,才能拍照及錄影"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」拍照及錄影嗎?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上拍照及錄影嗎?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"這個應用程式要求取得隨時都能拍照及錄影的權限,即使你當下並未使用該應用程式。"<annotation id="link">"如要授予權限,請前往設定頁面。"</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」的相機存取權嗎?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"要變更「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的相機存取權嗎?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"這個應用程式想取得隨時都能拍照及錄影的權限,即使你當下並未使用該應用程式。"<annotation id="link">"如要授予權限,請前往設定頁面。"</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取你的通話記錄嗎?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取你的手機通話記錄嗎?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」撥打電話及管理通話嗎?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上撥打電話及管理通話嗎?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取與你生命徵象相關的感應器資料嗎?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取與你生命徵象相關的感應器資料嗎?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"這個應用程式想隨時存取與你生命徵象相關的感應器資料 (即使你當下並未使用該應用程式)。如要變更,請"<annotation id="link">"前往設定"</annotation>"。"</string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;存取與你生命徵象相關的感應器資料嗎?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上存取與你生命徵象相關的感應器資料嗎?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"如要讓這個應用程式能隨時存取人體感應器資料 (即使你當下並未使用該應用程式),請"<annotation id="link">"前往設定"</annotation>"。"</string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"要變更允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;應用程式在使用期間存取人體感應器資料嗎?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"要繼續允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;應用程式在使用期間存取&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上的人體感應器資料嗎?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;傳送通知嗎?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;在&lt;b&gt;<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt;上傳送通知嗎?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"由管理員控管的權限"</string>
<string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」具有位置存取權"</string>
<string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"貴機構允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」存取你的位置資訊"</string>
@@ -520,7 +559,7 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"應用程式和服務"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"當你撥打緊急電話號碼時,系統仍會提供麥克風的資料。"</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"變更"</string>
- <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"安全性與隱私"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"安全性與隱私權"</string>
<string name="safety_center_rescan_button" msgid="4517514567809409596">"掃描裝置"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"關閉"</string>
<string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"要關閉這個警示嗎?"</string>
@@ -531,7 +570,7 @@
<string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"安全性與隱私權狀態。<xliff:g id="OVERALL_SAFETY_STATUS">%1$s</xliff:g>。<xliff:g id="SUMMARY_OF_DEVICE_STATUS">%2$s</xliff:g>"</string>
<string name="security_settings" msgid="3808106921175271317">"安全性設定"</string>
<string name="sensor_permissions_qs" msgid="1022267900031317472">"權限"</string>
- <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"安全性與隱私"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"安全性與隱私權"</string>
<string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"檢查狀態"</string>
<string name="privacy_controls_qs" msgid="5780144882040591169">"你的隱私權控制項"</string>
<string name="security_settings_button_label_qs" msgid="8280343822465962330">"更多設定"</string>
@@ -580,7 +619,7 @@
<string name="camera_toggle_title" msgid="1251201397431837666">"相機存取權"</string>
<string name="mic_toggle_title" msgid="2649991093496110162">"麥克風存取權"</string>
<string name="perm_toggle_description" msgid="7801326363741451379">"應用程式和服務"</string>
- <string name="mic_toggle_description" msgid="9163104307990677157">"應用程式和服務。如果關閉這項設定,系統仍會在你撥打緊急電話號碼時提供麥克風的資料。"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"適用於應用程式和服務。即使關閉這項設定,系統仍可能會在你撥打緊急電話號碼時,分享麥克風資料。"</string>
<string name="location_settings_subtitle" msgid="2328360561197430695">"查看對位置擁有存取權的應用程式與服務"</string>
<string name="show_clip_access_notification_title" msgid="5168467637351109096">"顯示剪貼簿存取通知"</string>
<string name="show_clip_access_notification_summary" msgid="3532020182782112687">"系統會在應用程式存取你複製的文字、圖片或其他內容時顯示通知訊息"</string>
@@ -589,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"這個應用程式表示可能會將位置資料分享給第三方"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"資料分享與位置"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"資料分享的相關資訊來源"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"開發人員已將這個應用程式的資料分享做法相關資訊,提供給這部裝置的製造商,且可能會隨著時間更新這項資訊。"</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"開發人員已將這個應用程式的資料分享做法資訊提供給 "<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>",並可能會隨著時間更新這項資訊。"</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"這個應用程式分享位置資料的可能目的如下:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"資料分享的差異"</string>
@@ -606,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"資料安全"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"可能會分享位置資料"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"這個應用程式表示可能會將位置資料分享給第三方"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"無法開啟這個連結"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"位置資料分享更新"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"查看哪些應用程式變更了分享位置資料的做法"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"以下應用程式變更了分享位置資料的做法。這些應用程式先前可能未曾分享位置資料,也可能是現在為了廣告或行銷目的而分享這些資料。"</string>
@@ -620,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"資料分享方式異動"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"部分應用程式改變了位置資料的分享方式"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"設定"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"上次存取時間:<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"上次存取時間:昨天<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"上次存取時間:<xliff:g id="TIME_DATE_0">%1$s</xliff:g><xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values-zu-v33/strings.xml b/PermissionController/res/values-zu-v33/strings.xml
index bfffa738a..2b1861644 100644
--- a/PermissionController/res/values-zu-v33/strings.xml
+++ b/PermissionController/res/values-zu-v33/strings.xml
@@ -30,8 +30,7 @@
<string name="safety_center_more_issues_card_title" msgid="7425844746197493312">"Ezinye izexwayiso"</string>
<string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Chitha izexwayiso"</string>
<string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Nweba futhi ubone esinye isexwayiso}one{Nweba futhi ubone ezinye izexwayiso ezingu-#}other{Nweba futhi ubone ezinye izexwayiso ezingu-#}}"</string>
- <!-- no translation found for safety_center_issue_card_prefix_content_description (1447445289637043544) -->
- <skip />
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Isexwayiso. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
<string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Isenzo siqediwe"</string>
<string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Hlola amasethingi angangeza ukuvikeleka kudivayisi yakho"</string>
<string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Amasethingi asheshayo wokuvikeleka nobumfihlo"</string>
diff --git a/PermissionController/res/values-zu/strings.xml b/PermissionController/res/values-zu/strings.xml
index d0f30b575..07371a808 100644
--- a/PermissionController/res/values-zu/strings.xml
+++ b/PermissionController/res/values-zu/strings.xml
@@ -34,6 +34,7 @@
<string name="grant_dialog_button_more_info" msgid="213350268561945193">"Olunye ulwazi"</string>
<string name="grant_dialog_button_allow_all" msgid="5939066403732409516">"Vumela konke"</string>
<string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Njalo vumela konke"</string>
+ <string name="grant_dialog_button_allow_limited_access" msgid="5713551784422137594">"Vumela ukufinyelela okulinganiselwe"</string>
<string name="grant_dialog_button_allow_selected_photos" msgid="5497042471576153842">"Khetha izithombe namavidiyo"</string>
<string name="grant_dialog_button_allow_more_selected_photos" msgid="5145657877588697709">"Khetha okuningi"</string>
<string name="grant_dialog_button_dont_select_more" msgid="6643552729129461268">"Ungakhethi okuningi"</string>
@@ -60,6 +61,7 @@
<string name="app_permissions_breadcrumb" msgid="5136969550489411650">"Izinhlelo zokusebenza"</string>
<string name="app_permissions" msgid="3369917736607944781">"Izimvume zohlelo lokusebenza"</string>
<string name="unused_apps" msgid="2058057455175955094">"Izinhlelo zokusebenza ezingasetshenzisiwe"</string>
+ <string name="edit_photos_description" msgid="5540108003480078892">"Hlela izithobe ezikhethiwe zale App"</string>
<string name="no_unused_apps" msgid="12809387670415295">"Awekho ama-app angasetshenzisiwe"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Ama-app angasetshenzisiwe angu-0"</string>
<string name="review_permission_decisions" msgid="309559429150613632">"Izinqumo zemvume yakamuva"</string>
@@ -114,8 +116,6 @@
<string name="all_permissions" msgid="6911125611996872522">"Zonke izimvume"</string>
<string name="other_permissions" msgid="2901186127193849594">"Amanye amakhono wohlelo lokusebenza"</string>
<string name="permission_request_title" msgid="8790310151025020126">"Isicelo semvume"</string>
- <string name="wear_not_allowed_dlg_title" msgid="1429467891296932713">"I-Android Wear"</string>
- <string name="wear_not_allowed_dlg_text" msgid="512340555334769098">"Izenzo zokufaka/ukukhipha azisekelwe ku-Wear."</string>
<string name="permission_review_title_template_install" msgid="1284337937156289081">"Khetha ukuthi uzovumela ini ukuthi i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifinyelele kuyo"</string>
<string name="permission_review_title_template_update" msgid="3232333580548588657">"I-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ibuyekeziwe. Khetha ukuthi uzovumela ini ukuthi ifinyelelwe ilolu hlelo lokusebenza."</string>
<string name="review_button_cancel" msgid="2191147944056548886">"Khansela"</string>
@@ -204,7 +204,9 @@
<string name="auto_revoke_label" msgid="5068393642936571656">"Susa izimvume uma uhlelo lokusebenza lungasetshenziswa"</string>
<string name="unused_apps_label" msgid="2595428768404901064">"Susa izimvume uphinde ukhulule isikhala"</string>
<string name="unused_apps_label_v2" msgid="7058776770056517980">"Misa okwesikhashana umsebenzi we-app uma ingasetshenziswa"</string>
+ <string name="unused_apps_label_v3" msgid="693340578642156657">"Lawula i-app uma ingasetsheziswa"</string>
<string name="unused_apps_summary" msgid="8839466950318403115">"Susa izimvume, sula amafayela wesikhashana, futhi umise izaziso"</string>
+ <string name="unused_apps_summary_v2" msgid="5011313200815115802">"Susa izimvume, sula amafayela esikhashana, futhi ufake i-app kungobo yomlando"</string>
<string name="auto_revoke_summary" msgid="5867548789805911683">"Ukuze kuvikelwe idatha yakho, izimvume zalolu hlelo lokusebenza zizosuswa uma uhlelo lokusebenza lungasetshenziswa izinyanga ezimbalwa."</string>
<string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Ukuze kuvikelwe idatha yakho, uma uhlelo lokusebenza lungasetshenzisiwe, izimvume ezilandelayo zizosuswa: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_revoked_apps_page_summary" msgid="6594753657893756536">"Ukuze kuvikelwe idatha yakho, izimvume zisusiwe kusukela kuzinhlelo zokusebenza ongazange uzisebenzise ezinyangeni ezimbalwa."</string>
@@ -218,7 +220,7 @@
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> imvume isusiwe"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> nezimvume ze-<xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> zisusiwe"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> nezinye izimvume ezingu-<xliff:g id="NUMBER">%2$s</xliff:g> zisusiwe"</string>
- <string name="unused_apps_page_title" msgid="6986983535677572559">"Unused apps"</string>
+ <string name="unused_apps_page_title" msgid="6986983535677572559">"Ama-app angasetshenzisiwe"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Uma i-app ingasetshenziswa izinyanga ezimbalwa:\n\n• Izimvume ziyasuswa ukuze kuvikelwe idatha yakho\n• Izaziso ziyamiswa ukonga ibhethri\n• Amafayela okwesikhashana ayasuswa ukukhulula isikhala\n\nUkuze uphinde uvumele izimvume nezaziso, vula i-app."</string>
<string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Uma i-app ingasetshenziswa inyanga:\n\n• Izimvume ziyasuswa ukuze kuvikelwe idatha yakho\n• Amafayela esikhashana ayasuswa ukuze kuvulwe isikhala\n\nUkuze uphinde uvumele izimvume, vula i-app."</string>
<string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Kugcine ukuvulwa ngaphezu kwenyanga e-# edlule}one{Kugcine ukuvulwa ngaphezu kwezinyanga ezingu-# ezedlule}other{Kugcine ukuvulwa ngaphezu kwezinyanga ezingu-# ezedlule}}"</string>
@@ -226,13 +228,13 @@
<string name="last_opened_summary_short" msgid="1646067226191176825">"Kugcine ukuvulwa ngo-<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Uma uvumela ukuphathwa kwawo wonke amafayela, lolu hlelo lokusebenza lungafinyelela, lulungise, futhi lususe noma yimaphi amafayela akusitoreji esifanayo kule divayisi noma isitoreji samadivayisi axhunyiwe. Uhlelo lokusebenza lungafinyelela amafayela ngaphandle kokukubuza."</string>
<string name="special_file_access_dialog" msgid="583804114020740610">"Uvumela lolu hlelo lokusebenza lufinyelele, lulungise futhi lususe amafayela kudivayisi, noma kunoma yiziphi izitoreji zamadivayisi axhunyiwe? Lolu hlelo lokusebenza lungafinyelela amafayela ngaphandle kokukubuza."</string>
- <string name="permission_description_summary_generic" msgid="5401399408814903391">"Izinhlelo zokusebenza ezinale mvume zingenza lokhu <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
+ <string name="permission_description_summary_generic" msgid="5401399408814903391">"Ama-app anale mvume angakwazi <xliff:g id="DESCRIPTION">%1$s</xliff:g>"</string>
<string name="permission_description_summary_activity_recognition" msgid="2652850576497070146">"Izinhlelo zokusebenza ezinale mvume zingafinyelela umsebenzi wakho, njengokuhamba, ukugibela ibhayisikili, ukushayela, ukubala izinyathelo, nokuningi"</string>
<string name="permission_description_summary_calendar" msgid="103329982944411010">"Izinhlelo zokusebenza ezinale mvume zingafinyelela kukhalenda yakho"</string>
<string name="permission_description_summary_call_log" msgid="7321437186317577624">"Izinhlelo zokusebenza ezinale mvume zingafunda ziphinde zibhale irekhodi lamakholi"</string>
<string name="permission_description_summary_camera" msgid="108004375101882069">"Izinhlelo zokusebenza ezinale mvume zingathatha izithombe ziphinde zirekhode ividiyo"</string>
<string name="permission_description_summary_contacts" msgid="2337798886460408996">"Izinhlelo zokusebenza ezinale mvume zingafinyelela koxhumana nabo"</string>
- <string name="permission_description_summary_location" msgid="2817531799933480694">"Izinhlelo zokusebenza ezinale mvume zingafinyelela kundawo yale divayisi"</string>
+ <string name="permission_description_summary_location" msgid="2817531799933480694">"Ama-app anale mvume angafinyelela kundawo yale divayisi"</string>
<string name="permission_description_summary_nearby_devices" msgid="8269183818275073741">"Ama-app anale mvume angathola, axhume, futhi anqume ukuma okuhlobene kwamadivayisi aseduze"</string>
<string name="permission_description_summary_microphone" msgid="630834800308329907">"Izinhlelo zokusebenza ezinale mvume zingarekhoda umsindo"</string>
<string name="permission_description_summary_phone" msgid="4515277217435233619">"Izinhlelo zokusebenza ezinale mvume zingenza ziphinde ziphathe amakholi efoni"</string>
@@ -337,7 +339,7 @@
<string name="app_perms_content_provider_7d_all_files" msgid="7962416229708835558">"Kufinyelelwe ezinsukwini ezi-7 ezedlule • Wonke Amafayela"</string>
<string name="no_permissions_allowed" msgid="6081976856354669209">"Azikho izimvume ezivunyelwe"</string>
<string name="no_permissions_denied" msgid="8159923922804043282">"Azikho izimvume ezinqatshelwe"</string>
- <string name="no_apps_allowed" msgid="7718822655254468631">"Azikho izinhlelo zokusebenza ezivunyelwe"</string>
+ <string name="no_apps_allowed" msgid="7718822655254468631">"Ama-app avunyelwe"</string>
<string name="no_apps_allowed_full" msgid="8011716991498934104">"Azikho izinhlelo zokusebenza ezivunyelwe kuwo wonke amafayela"</string>
<string name="no_apps_allowed_scoped" msgid="4908850477787659501">"Azikho izinhlelo zokusebenza ezivunyelwe imidiya kuphela"</string>
<string name="no_apps_denied" msgid="7663435886986784743">"Azikho izinhlelo zokusebenza ezinqatshelwe"</string>
@@ -401,6 +403,16 @@
<string name="role_notes_short_label" msgid="8796604147546125285">"I-App yamanothi"</string>
<string name="role_notes_description" msgid="8496852798616883551">"Ama-app akuvumela ukuthi uthathe amanothi kudivayisi yakho"</string>
<string name="role_notes_search_keywords" msgid="7710756695666744631">"amanothi"</string>
+ <!-- no translation found for role_wallet_label (3719419175656204207) -->
+ <skip />
+ <!-- no translation found for role_wallet_short_label (6521288403762457452) -->
+ <skip />
+ <!-- no translation found for role_wallet_description (3726535836165949838) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_title (4770217108262737093) -->
+ <skip />
+ <!-- no translation found for role_wallet_request_description (6305487425777483053) -->
+ <skip />
<string name="request_role_current_default" msgid="738722892438247184">"Okuzenzakalelayo kwamanje"</string>
<string name="request_role_dont_ask_again" msgid="3556017886029520306">"Ungabuzi futhi"</string>
<string name="request_role_set_as_default" msgid="4253949643984172880">"Setha njengokuzenzekelayo"</string>
@@ -455,53 +467,78 @@
<string name="assistant_record_audio_user_sensitive_title" msgid="5532123360322362378">"Bonisa ukutholwa okucushwe umsizi"</string>
<string name="assistant_record_audio_user_sensitive_summary" msgid="6482937591816401619">"Bonisa isithonjana kwibha yesaziso uma imakrofoni isetshenzisiwe ukusebenzisa umsizi wezwi"</string>
<string name="permgrouprequest_storage_isolated" msgid="4892154224026852295">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele izithombe kanye nemidiya kudivayisi yakho?"</string>
+ <string name="permgrouprequest_device_aware_storage_isolated" msgid="5934218468708513375">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele izithombe nemidiya &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ithole ukufinyelela koxhumana nabo?"</string>
+ <string name="permgrouprequest_device_aware_contacts" msgid="2270563860206654757">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele koxhumana nabo bakho &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_location" msgid="6990232580121067883">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele kundawo yale divayisi?"</string>
+ <string name="permgrouprequest_device_aware_location" msgid="6641436550953715107">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukufinyelela endaweni &lt;b&gt;ye-<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\'s&lt;/b&gt; yakho?"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"Uhlelo lokusebenza luzoba nokufinyelela kuphela kundawo ngenkathi usebenzisa uhlelo lokusebenza"</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele kundawo yale divayisi?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_location" msgid="7660465507029650527">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele endaweni ye-&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g> yakho?"</string>
<string name="permgroupbackgroundrequestdetail_location" msgid="8021219324989662957">"Lolu hlelo lokusebenza lungafuna ukufinyelela indawo yakho ngaso sonke isikhathi, ngisho noma ungasebenzisi uhlelo lokusebenza. "<annotation id="link">"Vumela kokuthi izilungiselelo"</annotation>"."</string>
<string name="permgroupupgraderequest_location" msgid="8328408946822691636">"Shintsha ukufinyelela kwendawo kwe-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_location" msgid="4528266408056426513">"Shintsha ukufinyelela kwendawo &lt;b&gt;kwe-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgroupupgraderequestdetail_location" msgid="1550899076845189165">"Lolu hlelo lokusebenza lufuna ukufinyelela kundawo yakho ngaso sonke isikhathi, nanoma ungasebenzisi uhlelo lokusebenza. "<annotation id="link">"Vumela kokuthi izilungiselelo"</annotation>"."</string>
<string name="permgrouprequest_nearby_devices" msgid="2272829282660436700">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ithole, ixhume, futhi anqume ukuma okuhlobene kwamadivayisi aseduze?"</string>
+ <string name="permgrouprequest_device_aware_nearby_devices" msgid="7919687165848885665">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze uthole, uxhume, futhi unqume ukuma okuhlobene kwamadivayisi aseduze &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgroupupgraderequestdetail_nearby_devices" msgid="6877531270654738614">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ithole, ixhume, futhi anqume ukuma okuhlobene kwamadivayisi aseduze? "<annotation id="link">"Vumela kumasethingi."</annotation></string>
<string name="permgrouprequest_fineupgrade" msgid="2334242928821697672">"Shintsha ukufinyelela indawo kwe-<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> kusuka kokulinganiselwayo kuya kokunembile?"</string>
+ <string name="permgrouprequest_device_aware_fineupgrade" msgid="3947134846432067176">"Shintsha ukufinyelela kwendawo kwe-<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g> &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&amp;gt yakho; kusuka ekulinganiseni kuya kokunembayo?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele indawo elinganiselwe yale divayisi?"</string>
+ <string name="permgrouprequest_device_aware_coarselocation" msgid="9001956706241104626">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele endaweni elinganiselwe yakho &lt;b&gt;ye-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"Kunembile"</string>
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Cishe"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele kukhalenda yakho?"</string>
+ <string name="permgrouprequest_device_aware_calendar" msgid="3103987548035171850">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele kukhalenda yakho &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ithumele iphinde ibuke imilayezo ye-SMS?"</string>
+ <string name="permgrouprequest_device_aware_sms" msgid="7212083972999874267">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthumela nokubuka imilayezo ye-SMS &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele kuzithombe, imidiya, namafayela akudivayisi yakho?"</string>
+ <string name="permgrouprequest_device_aware_storage" msgid="872629037299467086">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele izithombe, imidiya, namafayela &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"Vumela i-<xliff:g id="APP_NAME">%1$s</xliff:g> ukuba ifinyelele izithombe, amavidiyo, umculo, nokulalelwayo, kule divayisi?"</string>
<string name="permgrouprequest_storage_pre_q" msgid="168130651144569428">"Vumela i-<xliff:g id="APP_NAME">%1$s</xliff:g> ukuba ifinyelele izithombe, amavidiyo, umculo, okulalelwayo, namanye amafayela kule divayisi?"</string>
<string name="permgrouprequest_read_media_aural" msgid="2593365397347577812">"Vumela i-<xliff:g id="APP_NAME">%1$s</xliff:g> ukuba ifinyelele umculo nokulalelwayo kule divayisi?"</string>
+ <string name="permgrouprequest_device_aware_read_media_aural" msgid="3331524384339036668">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukufinyelela kumculo nomsindo &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_read_media_visual" msgid="5548780620779729975">"Vumela i-<xliff:g id="APP_NAME">%1$s</xliff:g> ukuba ifinyelele izithombe namavidiyo kule divayisi?"</string>
+ <string name="permgrouprequest_device_aware_read_media_visual" msgid="5492319750632751551">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele izithombe namavidiyo &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_more_photos" msgid="128933814654231321">"Vumela &lt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&gt; ukuba ifinyelele izithombe namavidiyo kule divayisi?"</string>
+ <string name="permgrouprequest_device_aware_more_photos" msgid="8946782319103584021">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele izithombe namavidiyo engeziwe &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_microphone" msgid="2825208549114811299">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi irekhode umsindo?"</string>
+ <string name="permgrouprequest_device_aware_microphone" msgid="1266843551173029370">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze urekhode umsindo &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Uhlelo lokusebenza luzokwazi ukurekhoda imisindo kuphela kuyilapho usebenzisa uhlelo lokusebenza"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi irekhode umsindo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_microphone" msgid="4990337225146130185">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze urekhode umsindo &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgroupbackgroundrequestdetail_microphone" msgid="553702902263681838">"Lolu hlelo lokusebenza lungafuna ukurekhoda imisindo ngaso sonke isikhathi, ngisho nalapho ungasebenzisi uhlelo lokusebenza. "<annotation id="link">"Vumela kumasethingi."</annotation></string>
<string name="permgroupupgraderequest_microphone" msgid="1362781696161233341">"Shintsha ukufinyelela kwemakrofoni kwe-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_microphone" msgid="222471025997100107">"Shintsha ukufinyelela kwemakrofoni &lt;b&gt;kwe-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgroupupgraderequestdetail_microphone" msgid="2870497719571464239">"Lolu hlelo lokusebenza lufuna ukurekhoda imisindo ngaso sonke isikhathi, ngisho nalapho ungasebenzisi uhlelo lokusebenza. "<annotation id="link">"Vumela kumasethingi."</annotation></string>
<string name="permgrouprequest_activityRecognition" msgid="5415121592794230330">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele kumsebenzi wakho womzimba?"</string>
+ <string name="permgrouprequest_device_aware_activityRecognition" msgid="3408326850847755759">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele umsebenzi wakho womzimba &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_camera" msgid="5123097035410002594">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthatha izithombe iphinde irekhode ividiyo?"</string>
+ <string name="permgrouprequest_device_aware_camera" msgid="3525106924487608868">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthatha izithombe nokurekhoda ividiyo &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequestdetail_camera" msgid="9085323239764667883">"Lolu hlelo lokusebenza luzokwazi ukuthatha izithombe futhi lirekhode ividiyo kuphela kuyilapho usebenzisa uhlelo lokusebenza"</string>
<string name="permgroupbackgroundrequest_camera" msgid="1274286575704213875">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthatha izithombe iphinde irekhode ividiyo?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_camera" msgid="6718286540040964849">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthatha izithombe nokurekhoda ividiyo &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgroupbackgroundrequestdetail_camera" msgid="4458783509089859078">"Lolu hlelo lokusebenza lungafuna ukuthatha izithombe futhi lirekhode ividiyo ngaso sonke isikhathi, ngisho nalapho ungasebenzi uhlelo lokusebenza. "<annotation id="link">"Vumela kumasethingi."</annotation></string>
<string name="permgroupupgraderequest_camera" msgid="640758449200241582">"Shintsha ukufinyelela kwekhamera kwe-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="permgroupupgraderequest_device_aware_camera" msgid="4198765626608612156">"Shintsha ukufinyelela kwekhamera &lt;b&gt;kwe-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgroupupgraderequestdetail_camera" msgid="6642747548010962597">"Lolu hlelo lokusebenza lufuna ukuthatha izithombe futhi lirekhode ividiyo ngaso sonke isikhathi, ngisho nalapho ungasebenzi uhlelo lokusebenza. "<annotation id="link">"Vumela kumasethingi."</annotation></string>
<string name="permgrouprequest_calllog" msgid="2065327180175371397">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukufinyelela kurekhodi lakho lamakholi wefoni?"</string>
+ <string name="permgrouprequest_device_aware_calllog" msgid="735079772627778095">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele kumarekhodi wamakholi wakho &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_phone" msgid="1829234136997316752">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi yenze iphinde iphathe amakholi efoni?"</string>
+ <string name="permgrouprequest_device_aware_phone" msgid="4389610977195521813">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukwenza nokuphatha amakholi efoni yakho &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgrouprequest_sensors" msgid="4397358316850652235">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele kudatha yenzwa emayelana nezimpawu zakho ezibalulekile?"</string>
+ <string name="permgrouprequest_device_aware_sensors" msgid="1900598688488188225">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele idatha yezinzwa mayelana nezimpawu zakho ezibalulekile &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgroupupgraderequestdetail_sensors" msgid="6651914048792092835">"Le app ifuna ukufinyelela kudatha yenzwa emayelana nezimpawu zakho ezibalulekile ngaso sonke isikhathi, ngisho noma ungasebenzisi i-app. "<annotation id="link">"iya kumasethingi."</annotation></string>
<string name="permgroupbackgroundrequest_sensors" msgid="5661924322018503886">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ifinyelele kudatha yenzwa emayelana nezimpawu zakho ezibalulekile?"</string>
+ <string name="permgroupbackgroundrequest_device_aware_sensors" msgid="7691308331448239716">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele kudatha yenzwa mayelana nezimpawu zakho ezibalulekile &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="permgroupbackgroundrequestdetail_sensors" msgid="7726767635834043501">"Ukuze uvumele le app ukuba ifinyelele idatha yenzwa yomzimba ngaso sonke isikhathi, ngisho nalapho ungasebenzisi i-app, "<annotation id="link">"iya kumasethingi."</annotation></string>
<string name="permgroupupgraderequest_sensors" msgid="7576527638411370468">"Qhubeka uvumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuba ifinyelele inzwa yedatha yomzimba kuyilapho i-app isebenza?"</string>
+ <string name="permgroupupgraderequest_device_aware_sensors" msgid="3310667992344623159">"Qhubeka uvumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze ufinyelele idatha yenzwa yomzimba &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&amp;gt yakho; ngenkathi i-app isetshenziswa?"</string>
<string name="permgrouprequest_notifications" msgid="6396739062335106181">"Vumela i-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuthi ikuthumele izaziso?"</string>
+ <string name="permgrouprequest_device_aware_notifications" msgid="7307588961166360244">"Vumela &lt;b&gt;i-<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ukuze sikuthumelele izaziso &lt;b&gt;ku-<xliff:g id="DEVICE">%2$s</xliff:g>&lt;/b&gt; yakho?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Izimvume ezilawuliwe"</string>
- <!-- no translation found for auto_granted_location_permission_notification_title (7570818224669050377) -->
- <skip />
- <!-- no translation found for auto_granted_permission_notification_body (5040234389205471318) -->
- <skip />
+ <string name="auto_granted_location_permission_notification_title" msgid="7570818224669050377">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> inokufinyelela kwendawo"</string>
+ <string name="auto_granted_permission_notification_body" msgid="5040234389205471318">"Inhlangano yakho ivumela i-<xliff:g id="APP_NAME">%1$s</xliff:g> ukufinyelela indawo yakho"</string>
<string name="other_permissions_label" msgid="8986184335503271992">"Ezinye izimvume"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Izimvume ezisetshenziswa yisistimu"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Izimvume ezisetshenziswa yizinhlelo zokusebenza zesistimu kuphela."</string>
@@ -591,6 +628,7 @@
<string name="permission_rationale_message_location" msgid="2153841534298068414">"Le-app ithi ingabelana ngedatha yendawo nezinkampani engahlangene ngqo"</string>
<string name="permission_rationale_location_title" msgid="2404797182678793506">"Ukwabelana ngedatha nendawo"</string>
<string name="permission_rationale_data_sharing_source_title" msgid="6874604543125814316">"Lapho ulwazi lokwabelana ngedatha luvela khona"</string>
+ <string name="permission_rationale_data_sharing_device_manufacturer_message" msgid="7569261218145653185">"Unjiniyela unikezele ngolwazi kumkhiqizi wale divayisi mayelana nokuthi le app yabelana kanjani ngedatha. Unjiniyela angase abuyekeze lolu lwazi ngokuhamba kwesikhathi."</string>
<string name="permission_rationale_data_sharing_source_message" msgid="8330794595417986883">"Unjiniyela unikeze ulwazi ku-"<annotation id="link"><annotation id="install_source" example="App Store">"%1$s"</annotation></annotation>" mayelana nokuthi le-app yabelana kanjani ngedatha. Unjiniyela angase abuyekeze lolu lwazi ngokuhamba kwesikhathi."</string>
<string name="permission_rationale_location_purpose_title" msgid="5115877143670012618">"Le app ingabelana ngedatha yendawo ye-:"</string>
<string name="permission_rationale_permission_data_sharing_varies_title" msgid="9103718980919908316">"Ukwabelana ngedatha kuyahlukahluka"</string>
@@ -608,8 +646,6 @@
<string name="app_permission_rationale_message" msgid="8511466916077100713">"Ukuphepha kwedatha"</string>
<string name="app_location_permission_rationale_title" msgid="925420340572401350">"Idatha yendawo ingase yabiwe"</string>
<string name="app_location_permission_rationale_subtitle" msgid="6986985722752868692">"Le-app ithe ingabelana ngedatha yendawo nezinkampani ezingahlangene ngqo"</string>
- <string name="permission_rationale_data_sharing_link_error_title" msgid="4496607694785370249">"Ayikwazi ukuvula lelinki"</string>
- <string name="permission_rationale_data_sharing_link_error_message" msgid="8118116480850030215"></string>
<string name="data_sharing_updates_title" msgid="7996933386875213859">"Izibuyekezo zokwabelana ngedatha zendawo"</string>
<string name="data_sharing_updates_summary" msgid="764113985772233889">"Buyekeza ama-app aguqule indlela angabelana ngayo ngedatha yendawo yakho"</string>
<string name="data_sharing_updates_subtitle" msgid="6311537708950632329">"Lama-app ashintshe indlela angabelana ngayo ngedatha yendawo yakho. Kungenzeka abakaze babelane ngayo ngaphambili, noma manje sebengase babelane ngayo ngezinjongo zokukhangisa noma zokumaketha."</string>
@@ -622,4 +658,7 @@
<string name="safety_label_changes_notification_title" msgid="4479955083472203839">"Izibuyekezo zokwabelana ngedatha"</string>
<string name="safety_label_changes_notification_desc" msgid="7808764283266234675">"Amanye ama-app aguqule indlela angabelana ngayo ngedatha yendawo yakho"</string>
<string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Amasethingi"</string>
+ <string name="wear_app_perms_24h_access" msgid="8668121661337328895">"Kufinyelelwe ngo-<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_24h_access_yest" msgid="7069312481704735679">"Kufinyelelwe izolo ngo-<xliff:g id="TIME_DATE">%1$s</xliff:g>"</string>
+ <string name="wear_app_perms_7d_access" msgid="4608069019194676432">"Kufinyelelwe ngo-<xliff:g id="TIME_DATE_0">%1$s</xliff:g> <xliff:g id="TIME_DATE_1">%2$s</xliff:g>"</string>
</resources>
diff --git a/PermissionController/res/values/bools.xml b/PermissionController/res/values/bools.xml
index e97761843..b5f33b081 100644
--- a/PermissionController/res/values/bools.xml
+++ b/PermissionController/res/values/bools.xml
@@ -19,4 +19,5 @@
<resources>
<bool name="is_at_least_t">false</bool>
<bool name="is_at_least_u">false</bool>
+ <bool name="is_at_least_v">false</bool>
</resources>
diff --git a/PermissionController/res/values/colors.xml b/PermissionController/res/values/colors.xml
index e54edb506..b1d285104 100644
--- a/PermissionController/res/values/colors.xml
+++ b/PermissionController/res/values/colors.xml
@@ -32,4 +32,7 @@
<!-- overviewBackground is not visible from mainline, so UX provided this alternative.
system_neutral2_200 is v31+ so use this placeholder provided by ux -->
<color name="permission_rationale_overview_background">#DADCE0</color>
+
+ <!-- Wear related colors -->
+ <color name="wear_material_gray_600">#FF80868B</color>
</resources>
diff --git a/PermissionController/res/values/overlayable.xml b/PermissionController/res/values/overlayable.xml
index 850b5df40..8f81e446b 100644
--- a/PermissionController/res/values/overlayable.xml
+++ b/PermissionController/res/values/overlayable.xml
@@ -37,12 +37,24 @@
<item type="style" name="PermissionGrantTitleMessage" />
<item type="style" name="PermissionGrantDetailMessage" />
+ <item type="style" name="PermissionGrantPermissionRationaleContent" />
+ <item type="style" name="PermissionGrantPermissionRationaleIcon" />
+ <item type="style" name="PermissionGrantPermissionRationaleMessage" />
+ <item type="style" name="PermissionGrantPermissionRationaleMoreInfoIcon" />
+
+ <item type="color" name="permission_rationale_overview_background" />
+
+ <item type="style" name="PermissionLocationAccuracyRadioGroupMaterial3" />
+ <item type="style" name="PermissionLocationAccuracyFineImageViewMaterial3" />
+ <item type="style" name="PermissionLocationAccuracyCoarseImageViewMaterial3" />
+
+ <item type="style" name="PermissionLocationAccuracyRadioFine" />
+ <item type="style" name="PermissionLocationAccuracyRadioCoarse" />
+
<item type="style" name="PermissionGrantButtonList" />
<item type="style" name="PermissionGrantButtonBarSpace" />
<item type="style" name="PermissionGrantButton" />
- <!-- IDs for V31 only -->
-
<item type="style" name="PermissionGrantButtonTop" />
<item type="style" name="PermissionGrantButtonMiddle" />
<item type="style" name="PermissionGrantButtonBottom" />
@@ -52,23 +64,27 @@
<item type="style" name="PermissionGrantButtonAllowMaterial3" />
<item type="style" name="PermissionGrantButtonAllowForegroundMaterial3" />
<item type="style" name="PermissionGrantButtonAllowOneTimeMaterial3" />
+ <item type="style" name="PermissionGrantButtonAllowSelectedMaterial3" />
+ <item type="style" name="PermissionGrantButtonAllowAllMaterial3" />
<item type="style" name="PermissionGrantButtonDenyMaterial3" />
<item type="style" name="PermissionGrantButtonNoUpgradeMaterial3" />
+ <item type="style" name="PermissionGrantButtonDontAllowMoreMaterial3" />
+
+ <!-- Used in V30 only -->
- <!-- END IDs for V31 only -->
+ <item type="style" name="PermissionLocationAccuracyFineImageView" />
+ <item type="style" name="PermissionLocationAccuracyCoarseImageView" />
<item type="style" name="PermissionGrantButtonAllow" />
<item type="style" name="PermissionGrantButtonAllowForeground" />
<item type="style" name="PermissionGrantButtonAllowOneTime" />
+ <item type="style" name="PermissionGrantButtonAllowSelected" />
+ <item type="style" name="PermissionGrantButtonAllowAll" />
<item type="style" name="PermissionGrantButtonDeny" />
<item type="style" name="PermissionGrantButtonNoUpgrade" />
+ <item type="style" name="PermissionGrantButtonDontAllowMore" />
- <item type="style" name="PermissionGrantPermissionRationaleContent" />
- <item type="style" name="PermissionGrantPermissionRationaleIcon" />
- <item type="style" name="PermissionGrantPermissionRationaleMessage" />
- <item type="style" name="PermissionGrantPermissionRationaleMoreInfoIcon" />
-
- <item type="color" name="permission_rationale_overview_background" />
+ <!-- END Used in V30 only -->
<!-- END PERMISSION GRANT DIALOG -->
@@ -526,4 +542,4 @@
</policy>
</overlayable>
-</resources> \ No newline at end of file
+</resources>
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml
index 08d1b6b2d..5e1c7d162 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -73,6 +73,10 @@
<!-- Title for the dialog button to allow access to all of a resource always. [CHAR LIMIT=60] -->
<string name="grant_dialog_button_always_allow_all">Always allow all</string>
+ <!-- Title for the dialog button to allow limited access. [CHAR LIMIT=60] -->
+ <string name="grant_dialog_button_allow_limited_access">Allow limited access</string>
+ <!-- TODO: b/310657469 add app_permission version of this string -->
+
<!-- Title for the dialog button to allow access to select photos to be shared. [CHAR LIMIT=60] -->
<string name="grant_dialog_button_allow_selected_photos">Select photos and videos</string>
@@ -164,6 +168,9 @@
<!-- Title for the page of manage unused apps [CHAR LIMIT=30] -->
<string name="unused_apps">Unused apps</string>
+ <!-- Description for the button that lets users change which photos an app has access to [CHAR LIMIT=none] -->
+ <string name="edit_photos_description">Edit selected photos for this app</string>
+
<!-- Label when there are no unused apps [CHAR LIMIT=30] -->
<string name="no_unused_apps">No unused apps</string>
@@ -330,11 +337,6 @@
<!-- Title of the permission dialog for accessibility purposes- spoken to the user. [CHAR LIMIT=none] -->
<string name="permission_request_title">Permission request</string>
- <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=30] -->
- <string name="wear_not_allowed_dlg_title">Android Wear</string>
- <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=none] -->
- <string name="wear_not_allowed_dlg_text">Install/Uninstall actions not supported on Wear.</string>
-
<!-- Review of runtime permissions for legacy apps -->
<!-- Template for the screen title when app permissions are reviewed on install. [CHAR LIMIT=none] -->
@@ -643,9 +645,15 @@
<!-- Label for the hibernation / auto revoke switch on T+ devices [CHAR LIMIT=40] -->
<string name="unused_apps_label_v2">Pause app activity if unused</string>
+ <!-- Label of a switch preference that controls whether the system will pause app activity when the app has not been used for a while [CHAR LIMIT=40]-->
+ <string name="unused_apps_label_v3">Manage app if unused</string>
+
<!-- Hibernation switch preference summary which describes what the toggle does on T+ devices [CHAR LIMIT=NONE] -->
<string name="unused_apps_summary">Remove permissions, delete temporary files, and stop notifications</string>
+ <!-- Summary of the switch preference that controls whether the system will pause app activity when the app has not been used for a while [CHAR LIMIT=NONE]-->
+ <string name="unused_apps_summary_v2">Remove permissions, delete temporary files, stop notifications, and archive the app</string>
+
<!-- Summary for stating that permissions will be removed [CHAR LIMIT=none] -->
<string name="auto_revoke_summary">To protect your data, permissions for this app will be removed if the app is unused for a few months.</string>
@@ -1215,6 +1223,15 @@
<!-- Search keywords for the NOTES role. [CHAR LIMIT=NONE] -->
<string name="role_notes_search_keywords">notes</string>
+ <!-- Label for the wallet role. [CHAR LIMIT=30] -->
+ <string name="role_wallet_label">Default wallet app</string>
+ <!-- Short label for the wallet role. [CHAR LIMIT=30] -->
+ <string name="role_wallet_short_label">Wallet app</string>
+ <!-- Description for the wallet role. [CHAR LIMIT=NONE] -->
+ <string name="role_wallet_description">Wallet apps can store your credit and loyalty cards, car keys and other things to help with various forms of transactions.</string>
+ <string name="role_wallet_request_title">Set <xliff:g id="app_name" example="Super Wallet">%1$s</xliff:g> as your default wallet app?</string>
+ <string name="role_wallet_request_description">No permissions needed</string>
+
<!-- Subtitle for the application that is the current default application [CHAR LIMIT=30] -->
<string name="request_role_current_default">Current default</string>
@@ -1390,36 +1407,59 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<!-- Message shown to the user when the apps requests permission from this group. Shows in the isolated storage case. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_storage_isolated">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access photos and media on your device?</string>
+ <!-- Message shown to the user when the apps requests permission from this group. Shows in the isolated storage case. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_storage_isolated">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access photos and media on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_contacts">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your contacts?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_contacts">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your contacts on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
+
+
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_location">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access this device\u2019s location?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_location">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your &lt;b><xliff:g id="device_name" example="tablet">%2$s</xliff:g>\u2019s&lt;/b> location?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the location only while app is in foreground [CHAR LIMIT=150]-->
<string name="permgrouprequestdetail_location">The app will only have access to the location while you\u2019re using the app</string>
<!-- Message shown to the user when the apps requests permission to use the location while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgroupbackgroundrequest_location">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access this device\u2019s location?</string>
+ <!-- Message shown to the user when the apps requests permission to use the location while app is in foreground and background. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgroupbackgroundrequest_device_aware_location">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your &lt;b><xliff:g id="device_name" example="tablet">%2$s</xliff:g>\u2019s location?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the location while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=150] -->
<string name="permgroupbackgroundrequestdetail_location">This app may want to access your location all the time, even when you\u2019re not using the app. <annotation id="link">Allow in settings.</annotation></string>
<!-- Message shown to the user when the apps requests permission to use the location while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgroupupgraderequest_location">Change location access for &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b>?</string>
+ <!-- Message shown to the user when the apps requests permission to use the location while app is in foreground and background on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgroupupgraderequest_device_aware_location">Change location access for &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the location while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=150] -->
<string name="permgroupupgraderequestdetail_location">This app wants to access your location all the time, even when you\u2019re not using the app. <annotation id="link">Allow in settings.</annotation></string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_nearby_devices">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to find, connect to, and determine the relative position of nearby devices?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_nearby_devices">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to find, connect to, and determine the relative position of nearby devices on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to discovery and connect to nearby devices while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=150] -->
<string name="permgroupupgraderequestdetail_nearby_devices">Allow &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to find, connect to, and determine the relative position of nearby devices? <annotation id="link">Allow in settings.</annotation></string>
<!-- Message shown to the user when the app requests permission to upgrade to fine location [CHAR LIMIT=120] -->
<string name="permgrouprequest_fineupgrade">Change <xliff:g id="app_name" example="Gmail">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>\u2019s location access from approximate to precise?</string>
+ <!-- Message shown to the user when the app requests permission to upgrade to fine location on a specific device [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_fineupgrade">Change <xliff:g id="app_name" example="Gmail">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>\u2019s location access on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b> from approximate to precise?</string>
<!-- Message shown to the user when the app requests permission to use coarse location [CHAR LIMIT=120] -->
<string name="permgrouprequest_coarselocation">Allow &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access this device\u2019s approximate location?</string>
+ <!-- Message shown to the user when the app requests permission to use coarse location for a specific device [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_coarselocation">Allow &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>\u2019s approximate location?</string>
<!-- Text for the FINE location image [CHAR LIMIT=20] -->
<string name="permgrouprequest_finelocation_imagetext">Precise</string>
<!-- Text for the COARSE location image [CHAR LIMIT=20] -->
@@ -1429,14 +1469,26 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<string name="permgrouprequest_calendar">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your calendar?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_calendar">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your calendar on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
+
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_sms">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to send and view SMS messages?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_sms">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to send and view SMS messages on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
+
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_storage">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access photos, media, and files on your device?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_storage">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access photos, media, and files on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
+
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_storage_q_to_s">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access &lt;b>photos, videos, music, and audio&lt;/b> on this device?</string>
@@ -1448,25 +1500,42 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_read_media_aural">Allow &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access music and audio on this device?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_read_media_aural">Allow &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access music and audio on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
+
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_read_media_visual">Allow &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access photos and videos on this device?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_read_media_visual">Allow &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access photos and videos on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
+
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_more_photos">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access more photos and videos on this device?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_more_photos">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access more photos and videos on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_microphone">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to record audio?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_microphone">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to record audio on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the microphone only while app is in foreground [CHAR LIMIT=150]-->
<string name="permgrouprequestdetail_microphone">The app will only be able to record audio while you\u2019re using the app</string>
<!-- Message shown to the user when the apps requests permission to use the microphone while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgroupbackgroundrequest_microphone">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to record audio?</string>
+ <!-- Message shown to the user when the apps requests permission to use the microphone while app is in foreground and background. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgroupbackgroundrequest_device_aware_microphone">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to record audio on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the microphone while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=150] -->
<string name="permgroupbackgroundrequestdetail_microphone">This app may want to record audio all the time, even when you\u2019re not using the app. <annotation id="link">Allow in settings.</annotation></string>
<!-- Message shown to the user when the apps requests permission to use the microphone while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgroupupgraderequest_microphone">Change microphone access for &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b>?</string>
+ <!-- Message shown to the user when the apps requests permission to use the microphone while app is in foreground and background. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgroupupgraderequest_device_aware_microphone">Change microphone access for &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the microphone while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=150] -->
<string name="permgroupupgraderequestdetail_microphone">This app wants to record audio all the time, even when you\u2019re not using the app. <annotation id="link">Allow in settings.</annotation></string>
@@ -1474,46 +1543,76 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<string name="permgrouprequest_activityRecognition">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your physical activity?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_activityRecognition">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your physical activity on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
+
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_camera">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to take pictures and record video?</string>
+
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_camera">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to take pictures and record video on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the camera only while app is in foreground [CHAR LIMIT=150]-->
<string name="permgrouprequestdetail_camera">The app will only be able to take pictures and record video while you\u2019re using the app</string>
<!-- Message shown to the user when the apps requests permission to use the camera while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgroupbackgroundrequest_camera">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to take pictures and record video?</string>
+ <!-- Message shown to the user when the apps requests permission to use the camera while app is in foreground and background on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgroupbackgroundrequest_device_aware_camera">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to take pictures and record video on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the camera while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=150] -->
<string name="permgroupbackgroundrequestdetail_camera">This app may want to take pictures and record video all the time, even when you\u2019re not using the app. <annotation id="link">Allow in settings.</annotation></string>
<!-- Message shown to the user when the apps requests permission to use the camera while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgroupupgraderequest_camera">Change camera access for &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b>?</string>
+ <!-- Message shown to the user when the apps requests permission to use the camera while app is in foreground and background on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgroupupgraderequest_device_aware_camera">Change camera access for &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the camera while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=150] -->
<string name="permgroupupgraderequestdetail_camera">This app wants to take pictures and record video all the time, even when you\u2019re not using the app. <annotation id="link">Allow in settings.</annotation></string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_calllog">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your phone call logs?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_calllog">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your phone call logs on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_phone">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to make and manage phone calls?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_phone">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to make and manage phone calls on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_sensors">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access sensor data about your vital signs?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_sensors">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access sensor data about your vital signs on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the body sensors while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=NONE] -->
<string name="permgroupupgraderequestdetail_sensors">This app wants to access sensor data about your vital signs all the time, even when you\u2019re not using the app. To make this change, <annotation id="link">go to settings.</annotation></string>
- <!-- Message shown to the user when the apps requests permission to use the bosy sensors while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
+ <!-- Message shown to the user when the apps requests permission to use the bosy sensors while app is in foreground and background. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=120] -->
<string name="permgroupbackgroundrequest_sensors">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access the sensor data about your vital signs?</string>
+ <!-- Message shown to the user when the apps requests permission to use the bosy sensors while app is in foreground and background on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgroupbackgroundrequest_device_aware_sensors">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access the sensor data about your vital signs on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Subtitle of the message shown to the user when the apps requests permission to use the body sensors while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=NONE] -->
<string name="permgroupbackgroundrequestdetail_sensors">To let this app access body sensor data all the time, even when you\u2019re not using the app, <annotation id="link">go to settings.</annotation></string>
<!-- Message shown to the user when the apps requests permission to use the body sensors while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgroupupgraderequest_sensors">Keep allowing &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access body sensor data while app is in use?</string>
+ <!-- Message shown to the user when the apps requests permission to use the body sensors while app is in foreground and background on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgroupupgraderequest_device_aware_sensors">Keep allowing &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access body sensor data on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b> while app is in use?</string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_notifications">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to send you notifications?</string>
+ <!-- Message shown to the user when the apps requests permission from this group on a specific device. If ever possible this should stay below 120 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 180 characters though. [CHAR LIMIT=180] -->
+ <string name="permgrouprequest_device_aware_notifications">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to send you notifications on your &lt;b><xliff:g id="device" example="tablet">%2$s</xliff:g>&lt;/b>?</string>
<!-- Notification shown to the user when location permissions are auto-granted by admin policy. These are for when the admin is forcing the permission and the user cannot control it. [CHAR LIMIT=120]-->
<string name="auto_granted_permissions">Controlled permissions</string>
@@ -1850,4 +1949,13 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<string name="safety_label_changes_gear_description">Settings</string>
<!-- Safety Label Change Notifications End -->
+
+ <!-- Summary for showing the last access text for today for Wear [CHAR LIMIT=50] -->
+ <string name="wear_app_perms_24h_access">Accessed <xliff:g id="time_date" example="12:42 PM">%1$s</xliff:g></string>
+
+ <!-- Summary for showing the last access text for yesterday for Wear [CHAR LIMIT=50] -->
+ <string name="wear_app_perms_24h_access_yest">Accessed yesterday <xliff:g id="time_date" example="12:42 PM">%1$s</xliff:g></string>
+
+ <!-- Summary for showing the last access text for 7 days for Wear [CHAR LIMIT=50] -->
+ <string name="wear_app_perms_7d_access">Accessed <xliff:g id="time_date" example="Jan 3">%1$s</xliff:g> <xliff:g id="time_date" example="12:42 PM">%2$s</xliff:g></string>
</resources>
diff --git a/PermissionController/res/values/styles.xml b/PermissionController/res/values/styles.xml
index 11b9ebec1..b6acf82a7 100644
--- a/PermissionController/res/values/styles.xml
+++ b/PermissionController/res/values/styles.xml
@@ -51,7 +51,7 @@
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:orientation">vertical</item>
- <item name="android:paddingTop">18dp</item>
+ <item name="android:paddingTop">24dp</item>
<item name="android:paddingBottom">24dp</item>
<item name="android:paddingLeft">24dp</item>
<item name="android:paddingRight">24dp</item>
@@ -195,6 +195,8 @@
<item name="android:paddingEnd">16dp</item>
<item name="android:orientation">horizontal</item>
<item name="android:background">@drawable/grant_dialog_permission_rationale_background</item>
+ <item name="android:minWidth">48dp</item>
+ <item name="android:minHeight">48dp</item>
</style>
<style name="PermissionGrantPermissionRationaleIcon">
@@ -233,16 +235,16 @@
parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonAllowOneTime"
parent="@style/PermissionGrantButton"></style>
- <style name="PermissionGrantButtonAllowAll"
- parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonAllowSelected"
parent="@style/PermissionGrantButton"></style>
- <style name="PermissionGrantButtonDontAllowMore"
+ <style name="PermissionGrantButtonAllowAll"
parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonDeny"
parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonNoUpgrade"
parent="@style/PermissionGrantButton"></style>
+ <style name="PermissionGrantButtonDontAllowMore"
+ parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonAllowMaterial3"
parent="@style/PermissionGrantButton"></style>
@@ -256,10 +258,6 @@
parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonAllowAllMaterial3"
parent="@style/PermissionGrantButton"></style>
- <style name="PermissionGrantButtonAllowSelectedPhotosMaterial3"
- parent="@style/PermissionGrantButton"></style>
- <style name="PermissionGrantButtonDontAllowMorePhotosMaterial3"
- parent="@style/PermissionGrantButton"></style>
<!-- END PERMISSION GRANT DIALOG -->
diff --git a/PermissionController/res/values/themes.xml b/PermissionController/res/values/themes.xml
index 76196a050..4f59ec29d 100644
--- a/PermissionController/res/values/themes.xml
+++ b/PermissionController/res/values/themes.xml
@@ -138,4 +138,6 @@
<item name="android:filterTouchesWhenObscured">true</item>
</style>
+ <style name="Theme.PermissionController.IncidentReportDialog"
+ parent="@style/Theme.DeviceDefault.Dialog.NoActionBar.DayNight" />
</resources>
diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml
index 2f8f5a291..f09056f73 100644
--- a/PermissionController/res/xml/roles.xml
+++ b/PermissionController/res/xml/roles.xml
@@ -78,6 +78,7 @@
<permission name="android.permission.READ_MEDIA_AUDIO" minSdkVersion="33" />
<permission name="android.permission.READ_MEDIA_VIDEO" minSdkVersion="33" />
<permission name="android.permission.READ_MEDIA_IMAGES" minSdkVersion="33" />
+ <permission name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" minSdkVersion="34" />
</permission-set>
<permission-set name="nearby_devices">
@@ -163,8 +164,7 @@
overrideUserWhenGranting="true"
requestDescription="@string/role_browser_request_description"
requestTitle="@string/role_browser_request_title"
- shortLabel="@string/role_browser_short_label"
- uiBehavior="BrowserRoleUiBehavior">
+ shortLabel="@string/role_browser_short_label">
<!--
~ Required components matching is handled in BrowserRoleBehavior because it needs the
~ PackageManager.MATCH_ALL flag and other manual filtering, which cannot fit in our
@@ -545,10 +545,15 @@
<permission-set name="sms" />
<permission-set name="contacts" />
<permission-set name="nearby_devices" />
+ <permission-set name="notifications" minSdkVersion="35" />
+ <!-- If this role holder has a NotificationListenerService, let that service receive
+ notifications with sensitive content unredacted-->
+ <permission name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" minSdkVersion="35"/>
</permissions>
<app-op-permissions>
<app-op-permission name="android.permission.MANAGE_ONGOING_CALLS" />
<app-op-permission name="android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER" />
+ <app-op-permission name="android.permission.MEDIA_ROUTING_CONTROL" minSdkVersion="35" />
</app-op-permissions>
</role>
@@ -579,6 +584,9 @@
<permission name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION" minSdkVersion="33" />
<permission name="android.permission.ADD_TRUSTED_DISPLAY" minSdkVersion="34"/>
<permission name="android.permission.ASSOCIATE_COMPANION_DEVICES" minSdkVersion="34"/>
+ <!-- If this role holder has a NotificationListenerService, let that service receive
+ notifications with sensitive content unredacted-->
+ <permission name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" minSdkVersion="35"/>
</permissions>
</role>
@@ -667,6 +675,7 @@
<permission name="android.permission.SET_TIME" minSdkVersion="34" />
<permission name="android.permission.SET_TIME_ZONE" minSdkVersion="34" />
<permission name="android.permission.SATELLITE_COMMUNICATION" minSdkVersion="34" />
+ <permission name="android.permission.ALWAYS_UPDATE_WALLPAPER" minSdkVersion="35" />
</permissions>
</role>
@@ -959,6 +968,9 @@
<permission-set name="notifications" />
<permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
<permission name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
+ <!-- If this role holder has a NotificationListenerService, let that service receive
+ notifications with sensitive content unredacted-->
+ <permission name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" minSdkVersion="35"/>
</permissions>
</role>
@@ -1101,7 +1113,6 @@
-->
<role
name="android.app.role.SYSTEM_UI"
- behavior="SystemUiRoleBehavior"
defaultHolders="config_systemUi"
exclusive="true"
minSdkVersion="31"
@@ -1113,6 +1124,9 @@
<permission name="android.permission.MANAGE_SENSOR_PRIVACY" />
<permission name="android.permission.OBSERVE_SENSOR_PRIVACY" />
<permission name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT" minSdkVersion="33"/>
+ <!-- If this role holder has a NotificationListenerService, let that service receive
+ notifications with sensitive content unredacted-->
+ <permission name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" minSdkVersion="35"/>
</permissions>
</role>
@@ -1175,6 +1189,9 @@
<permissions>
<permission-set name="notifications" />
<permission-set name="storage" />
+ <!-- If this role holder has a NotificationListenerService, let that service receive
+ notifications with sensitive content unredacted-->
+ <permission name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" minSdkVersion="35"/>
</permissions>
</role>
@@ -1192,6 +1209,9 @@
<permission-set name="notifications" />
<permission-set name="phone" />
<permission-set name="sms" />
+ <!-- If this role holder has a NotificationListenerService, let that service receive
+ notifications with sensitive content unredacted-->
+ <permission name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" minSdkVersion="35"/>
</permissions>
<app-op-permissions>
<app-op-permission name="android.permission.MANAGE_ONGOING_CALLS" />
@@ -1610,4 +1630,47 @@
</service>
</required-components>
</role>
+
+ <role
+ name="android.app.role.RETAIL_DEMO"
+ behavior="RetailDemoRoleBehavior"
+ defaultHolders="config_defaultRetailDemo"
+ exclusive="true"
+ minSdkVersion="35"
+ static="true"
+ visible="false">
+ <permissions>
+ <permission name="android.permission.ACCESS_BLOBS_ACROSS_USERS" />
+ <permission name="android.permission.CHANGE_CONFIGURATION" />
+ <permission name="android.permission.MODIFY_DAY_NIGHT_MODE" />
+ <permission name="android.permission.MODIFY_PHONE_STATE" />
+ <permission name="android.permission.OBSERVE_APP_USAGE" />
+ <permission name="android.permission.QUERY_USERS" />
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+ <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
+ <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" />
+ <permission name="android.permission.WRITE_SETTINGS" />
+ </permissions>
+ <app-op-permissions>
+ <app-op-permission name="android.permission.PACKAGE_USAGE_STATS" />
+ </app-op-permissions>
+ </role>
+
+ <role
+ name="android.app.role.WALLET"
+ behavior="WalletRoleBehavior"
+ defaultHolders="config_defaultWallet"
+ description="@string/role_wallet_description"
+ exclusive="true"
+ label="@string/role_wallet_label"
+ minSdkVersion="35"
+ overrideUserWhenGranting="true"
+ requestable="true"
+ requestDescription="@string/role_wallet_request_description"
+ requestTitle="@string/role_wallet_request_title"
+ showNone="true"
+ shortLabel="@string/role_wallet_short_label"
+ uiBehavior="WalletRoleUiBehavior"/>
+
+
</roles>
diff --git a/PermissionController/res/xml/safety_center_dashboard.xml b/PermissionController/res/xml/safety_center_dashboard.xml
index 216ef318e..e3951ca83 100644
--- a/PermissionController/res/xml/safety_center_dashboard.xml
+++ b/PermissionController/res/xml/safety_center_dashboard.xml
@@ -29,6 +29,11 @@
android:layout="@layout/preference_category_no_label"
app:selectable="false" />
+ <!-- TODO: b/291574390 - Move this to the issue drawer or status card view instead of having a
+ separate preference just for this margin/padding -->
+ <com.android.permissioncontroller.safetycenter.ui.EntriesTopPaddingPreference
+ android:key="entries_top_padding" />
+
<com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
android:key="entries_group"
android:title="@string/safety_center_entries_category_title"
@@ -36,7 +41,7 @@
<com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
android:key="static_entries_group"
- android:layout="@layout/spaced_preference_category_no_label"
+ android:layout="@layout/preference_category_no_label"
app:selectable="false" />
<com.android.permissioncontroller.safetycenter.ui.SpacerPreference
diff --git a/PermissionController/role-controller/Android.bp b/PermissionController/role-controller/Android.bp
index 8f8195003..6d4bf52c6 100644
--- a/PermissionController/role-controller/Android.bp
+++ b/PermissionController/role-controller/Android.bp
@@ -26,6 +26,7 @@ java_library {
],
static_libs: [
"modules-utils-build_system",
+ "android.permission.flags-aconfig-java",
],
apex_available: [
"com.android.permission",
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java
index 12710cfd3..c20734cde 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java
@@ -20,12 +20,12 @@ import android.app.ActivityManager;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
-import android.os.Process;
import android.os.UserHandle;
import android.service.voice.VoiceInteractionService;
import android.util.ArraySet;
@@ -38,6 +38,7 @@ import androidx.annotation.Nullable;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.model.VisibilityMixin;
import com.android.role.controller.util.UserUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -54,20 +55,17 @@ public class AssistantRoleBehavior implements RoleBehavior {
private static final String LOG_TAG = AssistantRoleBehavior.class.getSimpleName();
- private static final Intent ASSIST_SERVICE_PROBE =
- new Intent(VoiceInteractionService.SERVICE_INTERFACE);
- private static final Intent ASSIST_ACTIVITY_PROBE = new Intent(Intent.ACTION_ASSIST);
-
@Override
- public void onRoleAdded(@NonNull Role role, @NonNull Context context) {
+ public void onRoleAddedAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
PackageManager packageManager = context.getPackageManager();
if (packageManager.isDeviceUpgrading()) {
RoleManager roleManager = context.getSystemService(RoleManager.class);
- List<String> packageNames = roleManager.getRoleHolders(role.getName());
+ List<String> packageNames = roleManager.getRoleHoldersAsUser(role.getName(), user);
if (packageNames.isEmpty()) {
// If the device was upgraded, and there isn't any legacy role holders, it means
// user selected "None" in Settings and we need to keep that.
- role.onNoneHolderSelectedAsUser(Process.myUserHandle(), context);
+ role.onNoneHolderSelectedAsUser(user, context);
}
}
}
@@ -82,81 +80,72 @@ public class AssistantRoleBehavior implements RoleBehavior {
@Override
public List<String> getQualifyingPackagesAsUser(@NonNull Role role, @NonNull UserHandle user,
@NonNull Context context) {
+ return getQualifyingPackagesInternal(null, user, context);
+ }
+
+ @Nullable
+ @Override
+ public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return !getQualifyingPackagesInternal(packageName, user, context)
+ .isEmpty();
+ }
+
+ @NonNull
+ private List<String> getQualifyingPackagesInternal(@Nullable String filterPackageName,
+ @NonNull UserHandle user, @NonNull Context context) {
Context userContext = UserUtils.getUserContext(context, user);
ActivityManager userActivityManager = userContext.getSystemService(ActivityManager.class);
PackageManager userPackageManager = userContext.getPackageManager();
- Set<String> availableAssistants = new ArraySet<>();
+ Set<String> packageNames = new ArraySet<>();
if (!userActivityManager.isLowRamDevice()) {
- List<ResolveInfo> services = userPackageManager.queryIntentServices(
- ASSIST_SERVICE_PROBE, PackageManager.GET_META_DATA
+ Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+ if (filterPackageName != null) {
+ serviceIntent.setPackage(filterPackageName);
+ }
+ List<ResolveInfo> serviceResolveInfos = userPackageManager.queryIntentServices(
+ serviceIntent, PackageManager.GET_META_DATA
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- int numServices = services.size();
- for (int i = 0; i < numServices; i++) {
- ResolveInfo service = services.get(i);
-
- if (isAssistantVoiceInteractionService(userPackageManager, service.serviceInfo)) {
- availableAssistants.add(service.serviceInfo.packageName);
+ int serviceResolveInfosSize = serviceResolveInfos.size();
+ for (int i = 0; i < serviceResolveInfosSize; i++) {
+ ResolveInfo serviceResolveInfo = serviceResolveInfos.get(i);
+
+ ServiceInfo serviceInfo = serviceResolveInfo.serviceInfo;
+ if (!isAssistantVoiceInteractionService(userPackageManager, serviceInfo)) {
+ if (filterPackageName != null) {
+ Log.w(LOG_TAG, "Package " + filterPackageName
+ + " has an unqualified voice interaction service");
+ }
+ continue;
}
+
+ packageNames.add(serviceInfo.packageName);
}
}
- List<ResolveInfo> activities = userPackageManager.queryIntentActivities(
- ASSIST_ACTIVITY_PROBE, PackageManager.MATCH_DEFAULT_ONLY
+ Intent activityIntent = new Intent(Intent.ACTION_ASSIST);
+ if (filterPackageName != null) {
+ activityIntent.setPackage(filterPackageName);
+ }
+ List<ResolveInfo> activityResolveInfos = userPackageManager.queryIntentActivities(
+ activityIntent, PackageManager.MATCH_DEFAULT_ONLY
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- int numActivities = activities.size();
- for (int i = 0; i < numActivities; i++) {
- availableAssistants.add(activities.get(i).activityInfo.packageName);
- }
-
- return new ArrayList<>(availableAssistants);
- }
-
- @Nullable
- @Override
- public Boolean isPackageQualified(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
- ActivityManager activityManager = context.getSystemService(ActivityManager.class);
- PackageManager packageManager = context.getPackageManager();
-
- boolean hasAssistantService = false;
- if (!activityManager.isLowRamDevice()) {
- Intent pkgServiceProbe = new Intent(ASSIST_SERVICE_PROBE).setPackage(packageName);
- List<ResolveInfo> services = packageManager.queryIntentServices(pkgServiceProbe,
- PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- hasAssistantService = !services.isEmpty();
- int numServices = services.size();
- for (int i = 0; i < numServices; i++) {
- ResolveInfo service = services.get(i);
+ int activityResolveInfosSize = activityResolveInfos.size();
+ for (int i = 0; i < activityResolveInfosSize; i++) {
+ ResolveInfo activityResolveInfo = activityResolveInfos.get(i);
- if (isAssistantVoiceInteractionService(packageManager, service.serviceInfo)) {
- return true;
- }
+ ActivityInfo activityInfo = activityResolveInfo.activityInfo;
+ if (!activityInfo.exported) {
+ continue;
}
- }
- Intent pkgActivityProbe = new Intent(ASSIST_ACTIVITY_PROBE).setPackage(packageName);
- boolean hasAssistantActivity = !packageManager.queryIntentActivities(pkgActivityProbe,
- PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE).isEmpty();
- if (!hasAssistantActivity) {
- Log.w(LOG_TAG, "Package " + packageName + " not qualified for " + role.getName()
- + " due to " + (hasAssistantService ? "unqualified" : "missing")
- + " service and missing activity");
+ packageNames.add(activityInfo.packageName);
}
- return hasAssistantActivity;
- }
-
- @Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- }
-
- @Override
- public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
+ return new ArrayList<>(packageNames);
}
private boolean isAssistantVoiceInteractionService(@NonNull PackageManager pm,
@@ -205,4 +194,10 @@ public class AssistantRoleBehavior implements RoleBehavior {
return true;
}
+
+ @Override
+ public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return VisibilityMixin.isVisible("config_showDefaultAssistant", false, user, context);
+ }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java
index 2cf6a0b14..0261e1eee 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java
@@ -21,7 +21,6 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
-import android.os.Process;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -32,6 +31,7 @@ import com.android.modules.utils.build.SdkLevel;
import com.android.role.controller.model.Permissions;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.model.VisibilityMixin;
import com.android.role.controller.util.CollectionUtils;
import com.android.role.controller.util.PackageUtils;
import com.android.role.controller.util.UserUtils;
@@ -61,10 +61,10 @@ public class BrowserRoleBehavior implements RoleBehavior {
@Nullable
@Override
- public String getFallbackHolder(@NonNull Role role, @NonNull Context context) {
- UserHandle user = Process.myUserHandle();
- List<String> qualifyingPackageNames = getQualifyingPackagesAsUserInternal(null, false, user,
- context);
+ public String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ List<String> qualifyingPackageNames = getQualifyingPackagesAsUserInternal(null, false,
+ user, context);
if (qualifyingPackageNames.size() == 1) {
return qualifyingPackageNames.get(0);
}
@@ -76,7 +76,7 @@ public class BrowserRoleBehavior implements RoleBehavior {
return qualifyingSystemPackageNames.get(0);
}
- List<String> defaultPackageNames = role.getDefaultHolders(context);
+ List<String> defaultPackageNames = role.getDefaultHoldersAsUser(user, context);
return CollectionUtils.firstOrNull(defaultPackageNames);
} else {
return null;
@@ -95,10 +95,10 @@ public class BrowserRoleBehavior implements RoleBehavior {
@Nullable
@Override
- public Boolean isPackageQualified(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
+ public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
List<String> packageNames = getQualifyingPackagesAsUserInternal(packageName, false,
- Process.myUserHandle(), context);
+ user, context);
return !packageNames.isEmpty();
}
@@ -133,24 +133,32 @@ public class BrowserRoleBehavior implements RoleBehavior {
}
@Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
+ public void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
// @see com.android.server.pm.permission.DefaultPermissionGrantPolicy
// #grantDefaultPermissionsToDefaultBrowser(java.lang.String, int)
if (SdkLevel.isAtLeastS()) {
- if (PackageUtils.isSystemPackage(packageName, context)) {
- Permissions.grant(packageName, SYSTEM_BROWSER_PERMISSIONS, false, false, true,
- false, false, context);
+ if (PackageUtils.isSystemPackageAsUser(packageName, user, context)) {
+ Permissions.grantAsUser(packageName, SYSTEM_BROWSER_PERMISSIONS, false, false,
+ true, false, false, user, context);
}
}
}
@Override
- public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
+ public void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
if (SdkLevel.isAtLeastT()) {
- if (PackageUtils.isSystemPackage(packageName, context)) {
- Permissions.revoke(packageName, SYSTEM_BROWSER_PERMISSIONS, true, false, false,
- context);
+ if (PackageUtils.isSystemPackageAsUser(packageName, user, context)) {
+ Permissions.revokeAsUser(packageName, SYSTEM_BROWSER_PERMISSIONS, true, false,
+ false, user, context);
}
}
}
+
+ @Override
+ public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return VisibilityMixin.isVisible("config_showBrowserRole", true, user, context);
+ }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java
index 131690fd7..c164de3d8 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java
@@ -17,12 +17,14 @@
package com.android.role.controller.behavior;
import android.content.Context;
+import android.os.UserHandle;
import androidx.annotation.NonNull;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
import com.android.role.controller.util.NotificationUtils;
+import com.android.role.controller.util.UserUtils;
/**
* Class for behavior of the "App Streaming" Companion device profile role.
@@ -30,12 +32,18 @@ import com.android.role.controller.util.NotificationUtils;
public class CompanionDeviceAppStreamingRoleBehavior implements RoleBehavior {
@Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- NotificationUtils.grantNotificationAccessForPackage(context, packageName);
+ public void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!UserUtils.isManagedProfile(user, context)) {
+ NotificationUtils.grantNotificationAccessForPackageAsUser(packageName, user, context);
+ }
}
@Override
- public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- NotificationUtils.revokeNotificationAccessForPackage(context, packageName);
+ public void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!UserUtils.isManagedProfile(user, context)) {
+ NotificationUtils.revokeNotificationAccessForPackageAsUser(packageName, user, context);
+ }
}
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java
index c59d5e58d..e5d996675 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java
@@ -17,12 +17,14 @@
package com.android.role.controller.behavior;
import android.content.Context;
+import android.os.UserHandle;
import androidx.annotation.NonNull;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
import com.android.role.controller.util.NotificationUtils;
+import com.android.role.controller.util.UserUtils;
/**
* Class for behavior of the "Computer" Companion device profile role.
@@ -30,12 +32,18 @@ import com.android.role.controller.util.NotificationUtils;
public class CompanionDeviceComputerRoleBehavior implements RoleBehavior {
@Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- NotificationUtils.grantNotificationAccessForPackage(context, packageName);
+ public void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!UserUtils.isManagedProfile(user, context)) {
+ NotificationUtils.grantNotificationAccessForPackageAsUser(packageName, user, context);
+ }
}
@Override
- public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- NotificationUtils.revokeNotificationAccessForPackage(context, packageName);
+ public void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!UserUtils.isManagedProfile(user, context)) {
+ NotificationUtils.revokeNotificationAccessForPackageAsUser(packageName, user, context);
+ }
}
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java
index 2e4691b9c..5464a1518 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java
@@ -17,12 +17,14 @@
package com.android.role.controller.behavior;
import android.content.Context;
+import android.os.UserHandle;
import androidx.annotation.NonNull;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
import com.android.role.controller.util.NotificationUtils;
+import com.android.role.controller.util.UserUtils;
/**
* Class for behavior of the "glasses" Companion device profile role.
@@ -30,12 +32,18 @@ import com.android.role.controller.util.NotificationUtils;
public class CompanionDeviceGlassesRoleBehavior implements RoleBehavior {
@Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- NotificationUtils.grantNotificationAccessForPackage(context, packageName);
+ public void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!UserUtils.isManagedProfile(user, context)) {
+ NotificationUtils.grantNotificationAccessForPackageAsUser(packageName, user, context);
+ }
}
@Override
- public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- NotificationUtils.revokeNotificationAccessForPackage(context, packageName);
+ public void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!UserUtils.isManagedProfile(user, context)) {
+ NotificationUtils.revokeNotificationAccessForPackageAsUser(packageName, user, context);
+ }
}
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java
index 233c0d92e..0645c84d1 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java
@@ -17,12 +17,14 @@
package com.android.role.controller.behavior;
import android.content.Context;
+import android.os.UserHandle;
import androidx.annotation.NonNull;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
import com.android.role.controller.util.NotificationUtils;
+import com.android.role.controller.util.UserUtils;
/**
* Class for behavior of the "watch" Companion device profile role.
@@ -30,12 +32,18 @@ import com.android.role.controller.util.NotificationUtils;
public class CompanionDeviceWatchRoleBehavior implements RoleBehavior {
@Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- NotificationUtils.grantNotificationAccessForPackage(context, packageName);
+ public void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!UserUtils.isManagedProfile(user, context)) {
+ NotificationUtils.grantNotificationAccessForPackageAsUser(packageName, user, context);
+ }
}
@Override
- public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- NotificationUtils.revokeNotificationAccessForPackage(context, packageName);
+ public void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!UserUtils.isManagedProfile(user, context)) {
+ NotificationUtils.revokeNotificationAccessForPackageAsUser(packageName, user, context);
+ }
}
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java
index 79c139cee..57b5412dc 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java
@@ -26,6 +26,7 @@ import com.android.modules.utils.build.SdkLevel;
import com.android.role.controller.model.Permissions;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.model.VisibilityMixin;
import com.android.role.controller.util.PackageUtils;
import java.util.Arrays;
@@ -55,20 +56,28 @@ public class DialerRoleBehavior implements RoleBehavior {
}
@Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
+ public void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
if (SdkLevel.isAtLeastS()) {
- if (PackageUtils.isSystemPackage(packageName, context)) {
- Permissions.grant(packageName, SYSTEM_DIALER_PERMISSIONS, false, false,
- true, false, false, context);
+ if (PackageUtils.isSystemPackageAsUser(packageName, user, context)) {
+ Permissions.grantAsUser(packageName, SYSTEM_DIALER_PERMISSIONS, false, false,
+ true, false, false, user, context);
}
}
}
@Override
- public void revoke(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
+ public void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
if (SdkLevel.isAtLeastS()) {
- Permissions.revoke(packageName, SYSTEM_DIALER_PERMISSIONS, true, false, false, context);
+ Permissions.revokeAsUser(packageName, SYSTEM_DIALER_PERMISSIONS, true, false, false,
+ user, context);
}
}
+
+ @Override
+ public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return VisibilityMixin.isVisible("config_showDialerRole", true, user, context);
+ }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java
index ee7984274..fa030a00a 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java
@@ -17,7 +17,7 @@
package com.android.role.controller.behavior;
import android.content.Context;
-import android.os.Process;
+import android.os.UserHandle;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -36,9 +36,9 @@ public class DocumentManagerRoleBehavior implements RoleBehavior {
@NonNull
@Override
- public List<String> getDefaultHolders(@NonNull Role role, @NonNull Context context) {
- List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser(
- Process.myUserHandle(), context);
+ public List<String> getDefaultHoldersAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser(user, context);
if (qualifyingPackageNames.size() == 1) {
return qualifyingPackageNames;
} else {
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java
index a54006bb5..f19c86596 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java
@@ -18,7 +18,6 @@ package com.android.role.controller.behavior;
import android.content.Context;
import android.content.pm.PackageInfo;
-import android.os.Process;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
@@ -27,6 +26,7 @@ import androidx.annotation.Nullable;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.model.VisibilityMixin;
import com.android.role.controller.util.PackageUtils;
import java.util.List;
@@ -49,15 +49,16 @@ public class EmergencyRoleBehavior implements RoleBehavior {
@Nullable
@Override
- public String getFallbackHolder(@NonNull Role role, @NonNull Context context) {
- List<String> packageNames = role.getQualifyingPackagesAsUser(Process.myUserHandle(),
- context);
+ public String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ List<String> packageNames = role.getQualifyingPackagesAsUser(user, context);
PackageInfo fallbackPackageInfo = null;
int packageNamesSize = packageNames.size();
for (int i = 0; i < packageNamesSize; i++) {
String packageName = packageNames.get(i);
- PackageInfo packageInfo = PackageUtils.getPackageInfo(packageName, 0, context);
+ PackageInfo packageInfo = PackageUtils.getPackageInfoAsUser(packageName, 0,
+ user, context);
if (packageInfo == null) {
continue;
}
@@ -68,4 +69,10 @@ public class EmergencyRoleBehavior implements RoleBehavior {
}
return fallbackPackageInfo != null ? fallbackPackageInfo.packageName : null;
}
+
+ @Override
+ public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return VisibilityMixin.isVisible("config_showDefaultEmergency", false, user, context);
+ }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java
index 3254bc6e4..4bf5a6294 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java
@@ -22,15 +22,20 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
+import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+import com.android.role.controller.model.AppOpPermissions;
import com.android.role.controller.model.Permissions;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.model.VisibilityMixin;
import com.android.role.controller.util.UserUtils;
import java.util.Arrays;
@@ -51,6 +56,18 @@ public class HomeRoleBehavior implements RoleBehavior {
android.Manifest.permission.WRITE_CALL_LOG,
android.Manifest.permission.READ_CONTACTS);
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private static final List<String> WEAR_PERMISSIONS_T = Arrays.asList(
+ android.Manifest.permission.POST_NOTIFICATIONS,
+ android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY);
+
+ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static final List<String> WEAR_PERMISSIONS_V = Arrays.asList(
+ android.Manifest.permission.ALWAYS_UPDATE_WALLPAPER);
+
+ private static final List<String> WEAR_APP_OP_PERMISSIONS = Arrays.asList(
+ android.Manifest.permission.SYSTEM_ALERT_WINDOW);
+
@Override
public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user,
@NonNull Context context) {
@@ -62,10 +79,12 @@ public class HomeRoleBehavior implements RoleBehavior {
*/
@Nullable
@Override
- public String getFallbackHolder(@NonNull Role role, @NonNull Context context) {
- PackageManager packageManager = context.getPackageManager();
+ public String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
Intent intent = role.getRequiredComponents().get(0).getIntentFilterData().createIntent();
- List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent,
+ List<ResolveInfo> resolveInfos = userPackageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
@@ -78,7 +97,8 @@ public class HomeRoleBehavior implements RoleBehavior {
// Leave the fallback to PackageManagerService if there is only the fallback home in
// Settings, because if we fallback to it here, we cannot fallback to a normal home
// later, and user cannot see the fallback home in the UI anyway.
- if (isSettingsApplication(resolveInfo.activityInfo.applicationInfo, context)) {
+ if (isSettingsApplicationAsUser(resolveInfo.activityInfo.applicationInfo, user,
+ context)) {
continue;
}
if (resolveInfo.priority > priority) {
@@ -94,14 +114,16 @@ public class HomeRoleBehavior implements RoleBehavior {
/**
* Check if the application is a settings application
*/
- public static boolean isSettingsApplication(@NonNull ApplicationInfo applicationInfo,
- @NonNull Context context) {
- PackageManager packageManager = context.getPackageManager();
- ResolveInfo resolveInfo = packageManager.resolveActivity(new Intent(
- Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY
+ private static boolean isSettingsApplicationAsUser(@NonNull ApplicationInfo applicationInfo,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
+ ResolveInfo resolveInfo = userPackageManager.resolveActivity(
+ new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- if (resolveInfo == null || resolveInfo.activityInfo == null) {
+ if (resolveInfo == null || resolveInfo.activityInfo == null
+ || !resolveInfo.activityInfo.exported) {
return false;
}
return Objects.equals(applicationInfo.packageName, resolveInfo.activityInfo.packageName);
@@ -119,31 +141,62 @@ public class HomeRoleBehavior implements RoleBehavior {
}
@Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
+ public void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- Permissions.grant(packageName, AUTOMOTIVE_PERMISSIONS,
- true, false, true, false, false, context);
+ Permissions.grantAsUser(packageName, AUTOMOTIVE_PERMISSIONS,
+ true, false, true, false, false, user, context);
}
// Before T, ALLOW_SLIPPERY_TOUCHES may either not exist, or may not be a role permission
if (isRolePermission(android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES, context)) {
- Permissions.grant(packageName,
+ Permissions.grantAsUser(packageName,
Arrays.asList(android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES),
- true, false, true, false, false, context);
+ true, false, true, false, false, user, context);
+ }
+
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (SdkLevel.isAtLeastT()) {
+ Permissions.grantAsUser(packageName, WEAR_PERMISSIONS_T,
+ true, false, true, false, false, user, context);
+ for (String permission : WEAR_APP_OP_PERMISSIONS) {
+ AppOpPermissions.grantAsUser(packageName, permission, true, user, context);
+ }
+ }
+ if (SdkLevel.isAtLeastV()) {
+ Permissions.grantAsUser(packageName, WEAR_PERMISSIONS_V,
+ true, false, true, false, false, user, context);
+ }
}
}
@Override
- public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
+ public void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- Permissions.revoke(packageName, AUTOMOTIVE_PERMISSIONS, true, false, false, context);
+ Permissions.revokeAsUser(packageName, AUTOMOTIVE_PERMISSIONS, true, false, false,
+ user, context);
}
// Before T, ALLOW_SLIPPERY_TOUCHES may either not exist, or may not be a role permission
if (isRolePermission(android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES, context)) {
- Permissions.revoke(packageName,
+ Permissions.revokeAsUser(packageName,
Arrays.asList(android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES),
- true, false, false, context);
+ true, false, false, user, context);
+ }
+
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (SdkLevel.isAtLeastT()) {
+ Permissions.revokeAsUser(packageName, WEAR_PERMISSIONS_T, true, false, false,
+ user, context);
+ for (String permission : WEAR_APP_OP_PERMISSIONS) {
+ AppOpPermissions.revokeAsUser(packageName, permission, user, context);
+ }
+ }
+ if (SdkLevel.isAtLeastV()) {
+ Permissions.revokeAsUser(packageName, WEAR_PERMISSIONS_V, true, false, false,
+ user, context);
+ }
}
}
@@ -161,4 +214,17 @@ public class HomeRoleBehavior implements RoleBehavior {
final int flags = permissionInfo.getProtectionFlags();
return (flags & PermissionInfo.PROTECTION_FLAG_ROLE) == PermissionInfo.PROTECTION_FLAG_ROLE;
}
+
+ @Override
+ public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return VisibilityMixin.isVisible("config_showDefaultHome", false, user, context);
+ }
+
+ @Override
+ public boolean isApplicationVisibleAsUser(@NonNull Role role,
+ @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return !isSettingsApplicationAsUser(applicationInfo, user, context);
+ }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/RetailDemoRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/RetailDemoRoleBehavior.java
new file mode 100644
index 000000000..6dcdafd4c
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/RetailDemoRoleBehavior.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 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.role.controller.behavior;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Build;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.UserUtils;
+
+/**
+ * Class for behavior of the Retail Demo role.
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+public class RetailDemoRoleBehavior implements RoleBehavior {
+
+ @Override
+ public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.DEVICE_DEMO_MODE, 0) == 0) {
+ return false;
+ }
+ Context userContext = UserUtils.getUserContext(context, user);
+ DevicePolicyManager userDevicePolicyManager =
+ userContext.getSystemService(DevicePolicyManager.class);
+ if (!(userDevicePolicyManager.isDeviceOwnerApp(packageName)
+ || userDevicePolicyManager.isProfileOwnerApp(packageName))) {
+ return false;
+ }
+ // Fallback to do additional default check.
+ return null;
+ }
+
+ @Override
+ public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ UserManager userUserManager = userContext.getSystemService(UserManager.class);
+ return userUserManager.isSystemUser() || userUserManager.isMainUser()
+ || userUserManager.isDemoUser();
+ }
+}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java
index c1186a930..b614594c5 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java
@@ -19,7 +19,6 @@ package com.android.role.controller.behavior;
import android.app.admin.DevicePolicyManager;
import android.app.admin.ManagedSubscriptionsPolicy;
import android.content.Context;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.TelephonyManager;
@@ -31,6 +30,7 @@ import com.android.modules.utils.build.SdkLevel;
import com.android.role.controller.model.Permissions;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.model.VisibilityMixin;
import com.android.role.controller.util.CollectionUtils;
import com.android.role.controller.util.PackageUtils;
import com.android.role.controller.util.UserUtils;
@@ -90,7 +90,7 @@ public class SmsRoleBehavior implements RoleBehavior {
TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
if (!telephonyManager.isSmsCapable()
// Ensure sms role is present on car despite !isSmsCapable config (b/132972702)
- && role.getDefaultHolders(context).isEmpty()) {
+ && role.getDefaultHoldersAsUser(user, context).isEmpty()) {
return false;
}
return true;
@@ -98,8 +98,9 @@ public class SmsRoleBehavior implements RoleBehavior {
@Nullable
@Override
- public String getFallbackHolder(@NonNull Role role, @NonNull Context context) {
- List<String> defaultPackageNames = role.getDefaultHolders(context);
+ public String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ List<String> defaultPackageNames = role.getDefaultHoldersAsUser(user, context);
if (!defaultPackageNames.isEmpty()) {
return defaultPackageNames.get(0);
}
@@ -107,24 +108,32 @@ public class SmsRoleBehavior implements RoleBehavior {
// TODO(b/132916161): This was the previous behavior, however this may allow any third-party
// app to suddenly become the default SMS app and get the permissions, if no system default
// SMS app is available.
- List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser(
- Process.myUserHandle(), context);
+ List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser(user, context);
return CollectionUtils.firstOrNull(qualifyingPackageNames);
}
@Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- if (SdkLevel.isAtLeastS() && PackageUtils.isSystemPackage(packageName, context)) {
- Permissions.grant(packageName, SYSTEM_SMS_PERMISSIONS, false, false,
- true, false, false, context);
+ public void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (SdkLevel.isAtLeastS() && PackageUtils.isSystemPackageAsUser(packageName, user,
+ context)) {
+ Permissions.grantAsUser(packageName, SYSTEM_SMS_PERMISSIONS, false, false, true,
+ false, false, user, context);
}
}
@Override
- public void revoke(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
+ public void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
if (SdkLevel.isAtLeastS()) {
- Permissions.revoke(packageName, SYSTEM_SMS_PERMISSIONS, true, false, false, context);
+ Permissions.revokeAsUser(packageName, SYSTEM_SMS_PERMISSIONS, true, false, false,
+ user, context);
}
}
+
+ @Override
+ public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return VisibilityMixin.isVisible("config_showSmsRole", true, user, context);
+ }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java
index c0cbe9c25..621955770 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java
@@ -26,6 +26,7 @@ import androidx.annotation.Nullable;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.UserUtils;
/**
* Class for behavior of the system shell role.
@@ -33,12 +34,13 @@ import com.android.role.controller.model.RoleBehavior;
public class SystemShellRoleBehavior implements RoleBehavior {
@Nullable
@Override
- public Boolean isPackageQualified(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
- PackageManager packageManager = context.getPackageManager();
+ public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
int uid;
try {
- uid = packageManager.getPackageUid(packageName, 0);
+ uid = userPackageManager.getPackageUid(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java
deleted file mode 100644
index 210c2313f..000000000
--- a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.role.controller.behavior;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-import androidx.annotation.NonNull;
-
-import com.android.modules.utils.build.SdkLevel;
-import com.android.role.controller.model.AppOpPermissions;
-import com.android.role.controller.model.Role;
-import com.android.role.controller.model.RoleBehavior;
-
-import java.util.Arrays;
-import java.util.List;
-
-/** The role behavior for system ui. */
-public class SystemUiRoleBehavior implements RoleBehavior {
-
- private static final List<String> WEAR_APP_OP_PERMISSIONS =
- Arrays.asList(android.Manifest.permission.SYSTEM_ALERT_WINDOW);
-
- @Override
- public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- if (SdkLevel.isAtLeastT()) {
- if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
- for (String permission : WEAR_APP_OP_PERMISSIONS) {
- AppOpPermissions.grant(packageName, permission, true, context);
- }
- }
- }
- }
-
- @Override
- public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
- if (SdkLevel.isAtLeastT()) {
- if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
- for (String permission : WEAR_APP_OP_PERMISSIONS) {
- AppOpPermissions.revoke(packageName, permission, context);
- }
- }
- }
- }
-}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/WalletRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/WalletRoleBehavior.java
new file mode 100644
index 000000000..170c42c3d
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/WalletRoleBehavior.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 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.role.controller.behavior;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.nfc.NfcAdapter;
+import android.nfc.cardemulation.ApduServiceInfo;
+import android.nfc.cardemulation.CardEmulation;
+import android.nfc.cardemulation.HostApduService;
+import android.nfc.cardemulation.OffHostApduService;
+import android.os.Build;
+import android.os.UserHandle;
+import android.permission.flags.Flags;
+import android.service.quickaccesswallet.QuickAccessWalletService;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.UserUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Handles the behavior of the wallet role.
+ */
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+public class WalletRoleBehavior implements RoleBehavior {
+
+ private static final String LOG_TAG = WalletRoleBehavior.class.getSimpleName();
+
+ @Override
+ public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return SdkLevel.isAtLeastV() && Flags.walletRoleEnabled()
+ && !UserUtils.isProfile(user, context);
+ }
+
+ @Nullable
+ @Override
+ public List<String> getDefaultHoldersAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ CardEmulation cardEmulation;
+ Context userContext = UserUtils.getUserContext(context, user);
+ try {
+ cardEmulation =
+ CardEmulation.getInstance(NfcAdapter.getDefaultAdapter(userContext));
+ } catch (UnsupportedOperationException e) {
+ Log.e(LOG_TAG, "Unsupported Card Emulation Operation.", e);
+ return null;
+ }
+ ApduServiceInfo preferredPaymentService = cardEmulation
+ .getPreferredPaymentService();
+ if (preferredPaymentService != null) {
+ return Collections.singletonList(preferredPaymentService.getComponent()
+ .getPackageName());
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return !getQualifyingPackageNamesInternal(packageName, user, context).isEmpty();
+ }
+
+ @Nullable
+ @Override
+ public List<String> getQualifyingPackagesAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return new ArrayList<>(getQualifyingPackageNamesInternal(null, user, context));
+ }
+
+ @NonNull
+ private static Set<String> getQualifyingPackageNamesInternal(@Nullable String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Set<String> packageNames =
+ resolvePackageNames(HostApduService.SERVICE_INTERFACE, packageName, user,
+ context);
+ packageNames.addAll(
+ resolvePackageNames(OffHostApduService.SERVICE_INTERFACE, packageName, user,
+ context));
+ packageNames.addAll(
+ resolvePackageNames(QuickAccessWalletService.SERVICE_INTERFACE, packageName, user,
+ context));
+ return packageNames;
+ }
+
+ @NonNull
+ private static Set<String> resolvePackageNames(@NonNull String action,
+ @Nullable String packageName, @NonNull UserHandle user, @NonNull Context context) {
+ Intent intent = new Intent(action).setPackage(packageName);
+ PackageManager packageManager = context.getPackageManager();
+ List<ResolveInfo> resolveInfos = packageManager
+ .queryIntentServicesAsUser(intent, 0, user);
+ Set<String> packageNames = new ArraySet<>();
+ int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ packageNames.add(resolveInfos.get(i).serviceInfo.packageName);
+ }
+ return packageNames;
+ }
+}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java b/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java
index 3efa68bc9..6647a4f94 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java
@@ -18,7 +18,7 @@ package com.android.role.controller.model;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.os.Process;
+import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -73,39 +73,44 @@ public class AppOp {
* Grant this app op to an application.
*
* @param packageName the package name of the application
+ * @param user the user of the application
* @param context the {@code Context} to retrieve system services
*
* @return whether any app mode has changed
*/
- public boolean grant(@NonNull String packageName, @NonNull Context context) {
- if (!checkTargetSdkVersion(packageName, context)) {
+ public boolean grantAsUser(@NonNull String packageName, @NonNull UserHandle user,
+ @NonNull Context context) {
+ if (!checkTargetSdkVersionAsUser(packageName, user, context)) {
return false;
}
- return Permissions.setAppOpUidMode(packageName, mName, mMode, context);
+ return Permissions.setAppOpUidModeAsUser(packageName, mName, mMode, user, context);
}
/**
* Revoke this app op from an application.
*
* @param packageName the package name of the application
+ * @param user the user of the application
* @param context the {@code Context} to retrieve system services
*
* @return whether any app mode has changed
*/
- public boolean revoke(@NonNull String packageName, @NonNull Context context) {
- if (!checkTargetSdkVersion(packageName, context)) {
+ public boolean revokeAsUser(@NonNull String packageName, @NonNull UserHandle user,
+ @NonNull Context context) {
+ if (!checkTargetSdkVersionAsUser(packageName, user, context)) {
return false;
}
int defaultMode = Permissions.getDefaultAppOpMode(mName);
- return Permissions.setAppOpUidMode(packageName, mName, defaultMode, context);
+ return Permissions.setAppOpUidModeAsUser(packageName, mName, defaultMode, user, context);
}
- private boolean checkTargetSdkVersion(@NonNull String packageName, @NonNull Context context) {
+ private boolean checkTargetSdkVersionAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
if (mMaxTargetSdkVersion == null) {
return true;
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
- Process.myUserHandle(), context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user,
+ context);
if (applicationInfo == null) {
return false;
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java b/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java
index 29939a1a5..edd74e31e 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -42,14 +43,15 @@ public class AppOpPermissions {
* @param appOpPermission the name of the app op permission
* @param overrideNonDefaultMode whether to override the app opp mode if it isn't in the default
* mode
+ * @param user the user of the application
* @param context the {@code Context} to retrieve system services
*
* @return whether any app op mode has changed
*/
- public static boolean grant(@NonNull String packageName, @NonNull String appOpPermission,
- boolean overrideNonDefaultMode, @NonNull Context context) {
- PackageInfo packageInfo = PackageUtils.getPackageInfo(packageName,
- PackageManager.GET_PERMISSIONS, context);
+ public static boolean grantAsUser(@NonNull String packageName, @NonNull String appOpPermission,
+ boolean overrideNonDefaultMode, @NonNull UserHandle user, @NonNull Context context) {
+ PackageInfo packageInfo = PackageUtils.getPackageInfoAsUser(packageName,
+ PackageManager.GET_PERMISSIONS, user, context);
if (packageInfo == null) {
return false;
}
@@ -58,14 +60,16 @@ public class AppOpPermissions {
}
String appOp = AppOpsManagerCompat.permissionToOp(appOpPermission);
if (!overrideNonDefaultMode) {
- Integer currentMode = Permissions.getAppOpMode(packageName, appOp, context);
+ Integer currentMode = Permissions.getAppOpModeAsUser(packageName, appOp, user, context);
if (currentMode != null && currentMode != Permissions.getDefaultAppOpMode(appOp)) {
return false;
}
}
- boolean changed = setAppOpMode(packageName, appOp, AppOpsManager.MODE_ALLOWED, context);
+ boolean changed = setAppOpModeAsUser(packageName, appOp, AppOpsManager.MODE_ALLOWED, user,
+ context);
if (changed) {
- Permissions.setPermissionGrantedByRole(packageName, appOpPermission, true, context);
+ Permissions.setPermissionGrantedByRoleAsUser(packageName, appOpPermission, true,
+ user, context);
}
return changed;
}
@@ -75,24 +79,27 @@ public class AppOpPermissions {
*
* @param packageName the package name of the application
* @param appOpPermission the name of the app op permission
+ * @param user the user of the application
* @param context the {@code Context} to retrieve system services
*
* @return whether any app op mode has changed
*/
- public static boolean revoke(@NonNull String packageName, @NonNull String appOpPermission,
- @NonNull Context context) {
- if (!Permissions.isPermissionGrantedByRole(packageName, appOpPermission, context)) {
+ public static boolean revokeAsUser(@NonNull String packageName, @NonNull String appOpPermission,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (!Permissions.isPermissionGrantedByRoleAsUser(packageName, appOpPermission, user,
+ context)) {
return false;
}
String appOp = AppOpsManager.permissionToOp(appOpPermission);
int defaultMode = Permissions.getDefaultAppOpMode(appOp);
- boolean changed = setAppOpMode(packageName, appOp, defaultMode, context);
- Permissions.setPermissionGrantedByRole(packageName, appOpPermission, false, context);
+ boolean changed = setAppOpModeAsUser(packageName, appOp, defaultMode, user, context);
+ Permissions.setPermissionGrantedByRoleAsUser(packageName, appOpPermission, false,
+ user, context);
return changed;
}
- private static boolean setAppOpMode(@NonNull String packageName, @NonNull String appOp,
- int mode, @NonNull Context context) {
+ private static boolean setAppOpModeAsUser(@NonNull String packageName, @NonNull String appOp,
+ int mode, @NonNull UserHandle user, @NonNull Context context) {
switch (appOp) {
case AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS:
case AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW:
@@ -105,22 +112,25 @@ public class AppOpPermissions {
case AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS:
case AppOpsManager.OPSTR_INSTANT_APP_START_FOREGROUND:
case AppOpsManager.OPSTR_LOADER_USAGE_STATS:
- return Permissions.setAppOpPackageMode(packageName, appOp, mode, context);
+ return Permissions.setAppOpPackageModeAsUser(packageName, appOp, mode, user,
+ context);
case AppOpsManager.OPSTR_INTERACT_ACROSS_PROFILES:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// We fixed OP_INTERACT_ACROSS_PROFILES to use UID mode on S and backported it
// to R, but still, we might have an out-of-date platform or an upgraded
// platform with old state.
boolean changed = false;
- changed |= Permissions.setAppOpUidMode(packageName, appOp, mode, context);
- changed |= Permissions.setAppOpPackageMode(packageName, appOp,
- Permissions.getDefaultAppOpMode(appOp), context);
+ changed |= Permissions.setAppOpUidModeAsUser(packageName, appOp, mode, user,
+ context);
+ changed |= Permissions.setAppOpPackageModeAsUser(packageName, appOp,
+ Permissions.getDefaultAppOpMode(appOp), user, context);
return changed;
} else {
- return Permissions.setAppOpPackageMode(packageName, appOp, mode, context);
+ return Permissions.setAppOpPackageModeAsUser(packageName, appOp, mode, user,
+ context);
}
default:
- return Permissions.setAppOpUidMode(packageName, appOp, mode, context);
+ return Permissions.setAppOpUidModeAsUser(packageName, appOp, mode, user, context);
}
}
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java b/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java
index 0c4a14574..6ded32d58 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java
@@ -60,14 +60,29 @@ public class Permission {
* @return whether this permission is available
*/
public boolean isAvailable() {
- // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization.
- if (mMinSdkVersion >= 34) {
- return SdkLevel.isAtLeastU();
+ // Workaround to match the value 35+ for V+ in roles.xml before SDK finalization.
+ if (mMinSdkVersion >= 35) {
+ return SdkLevel.isAtLeastV();
} else {
return Build.VERSION.SDK_INT >= mMinSdkVersion;
}
}
+ /**
+ * Return a new permission with the specified minimum SDK version, or this permission if it
+ * already has the same minimum SDK version.
+ *
+ * @param minSdkVersion the minimum SDK version
+ * @return a permission with the specified minimum SDK version
+ */
+ @NonNull
+ public Permission withMinSdkVersion(int minSdkVersion) {
+ if (mMinSdkVersion == minSdkVersion) {
+ return this;
+ }
+ return new Permission(mName, minSdkVersion);
+ }
+
@Override
public String toString() {
return "Permission{"
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java b/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java
index f55a84c07..8a15612b9 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java
@@ -24,7 +24,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.os.Build;
-import android.os.Process;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.util.ArrayMap;
@@ -37,6 +36,7 @@ import androidx.annotation.Nullable;
import com.android.role.controller.util.ArrayUtils;
import com.android.role.controller.util.CollectionUtils;
import com.android.role.controller.util.PackageUtils;
+import com.android.role.controller.util.UserUtils;
import java.util.ArrayList;
import java.util.List;
@@ -89,6 +89,7 @@ public class Permissions {
* @param setGrantedByRole whether the permissions will be granted as granted-by-role
* @param setGrantedByDefault whether the permissions will be granted as granted-by-default
* @param setSystemFixed whether the permissions will be granted as system-fixed
+ * @param user the user of the application
* @param context the {@code Context} to retrieve system services
*
* @return whether any permission or app op changed
@@ -96,16 +97,16 @@ public class Permissions {
* @see com.android.server.pm.permission.DefaultPermissionGrantPolicy#grantRuntimePermissions(
* PackageInfo, java.util.Set, boolean, boolean, int)
*/
- public static boolean grant(@NonNull String packageName, @NonNull List<String> permissions,
- boolean overrideDisabledSystemPackage, boolean overrideUserSetAndFixed,
- boolean setGrantedByRole, boolean setGrantedByDefault, boolean setSystemFixed,
- @NonNull Context context) {
+ public static boolean grantAsUser(@NonNull String packageName,
+ @NonNull List<String> permissions, boolean overrideDisabledSystemPackage,
+ boolean overrideUserSetAndFixed, boolean setGrantedByRole, boolean setGrantedByDefault,
+ boolean setSystemFixed, @NonNull UserHandle user, @NonNull Context context) {
if (setGrantedByRole == setGrantedByDefault) {
throw new IllegalArgumentException("Permission must be either granted by role, or"
+ " granted by default, but not both");
}
- PackageInfo packageInfo = getPackageInfo(packageName, context);
+ PackageInfo packageInfo = getPackageInfoAsUser(packageName, user, context);
if (packageInfo == null) {
return false;
}
@@ -142,7 +143,8 @@ public class Permissions {
// apps, (default grants on first boot and user creation) we don't grant default
// permissions if the version on the system image does not declare them.
if (!overrideDisabledSystemPackage && isUpdatedSystemApp(packageInfo)) {
- PackageInfo disabledSystemPackageInfo = getFactoryPackageInfo(packageName, context);
+ PackageInfo disabledSystemPackageInfo = getFactoryPackageInfoAsUser(packageName, user,
+ context);
if (disabledSystemPackageInfo != null) {
if (ArrayUtils.isEmpty(disabledSystemPackageInfo.requestedPermissions)) {
return false;
@@ -176,9 +178,10 @@ public class Permissions {
boolean permissionOrAppOpChanged = false;
- PackageManager packageManager = context.getPackageManager();
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
Set<String> whitelistedRestrictedPermissions = new ArraySet<>(
- packageManager.getWhitelistedRestrictedPermissions(packageName,
+ userPackageManager.getWhitelistedRestrictedPermissions(packageName,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM));
int sortedPermissionsToGrantLength = sortedPermissionsToGrant.length;
@@ -187,24 +190,26 @@ public class Permissions {
if (isRestrictedPermission(permission, context)
&& whitelistedRestrictedPermissions.add(permission)) {
- packageManager.addWhitelistedRestrictedPermission(packageName, permission,
+ userPackageManager.addWhitelistedRestrictedPermission(packageName, permission,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
}
- permissionOrAppOpChanged |= grantSingle(packageName, permission,
+ permissionOrAppOpChanged |= grantSingleAsUser(packageName, permission,
overrideUserSetAndFixed, setGrantedByRole, setGrantedByDefault, setSystemFixed,
- context);
+ user, context);
}
return permissionOrAppOpChanged;
}
- private static boolean grantSingle(@NonNull String packageName, @NonNull String permission,
- boolean overrideUserSetAndFixed, boolean setGrantedByRole, boolean setGrantedByDefault,
- boolean setSystemFixed, @NonNull Context context) {
- boolean wasPermissionOrAppOpGranted = isPermissionAndAppOpGranted(packageName, permission,
- context);
- if (isPermissionFixed(packageName, permission, false, overrideUserSetAndFixed, context)
+ private static boolean grantSingleAsUser(@NonNull String packageName,
+ @NonNull String permission, boolean overrideUserSetAndFixed, boolean setGrantedByRole,
+ boolean setGrantedByDefault, boolean setSystemFixed, @NonNull UserHandle user,
+ @NonNull Context context) {
+ boolean wasPermissionOrAppOpGranted = isPermissionAndAppOpGrantedAsUser(packageName,
+ permission, user, context);
+ if (isPermissionFixedAsUser(packageName, permission, false,
+ overrideUserSetAndFixed, user, context)
&& !wasPermissionOrAppOpGranted) {
// Stop granting if this permission is fixed to revoked.
return false;
@@ -217,7 +222,8 @@ public class Permissions {
for (int i = 0; i < foregroundPermissionsSize; i++) {
String foregroundPermission = foregroundPermissions.get(i);
- if (isPermissionAndAppOpGranted(packageName, foregroundPermission, context)) {
+ if (isPermissionAndAppOpGrantedAsUser(packageName, foregroundPermission, user,
+ context)) {
isAnyForegroundPermissionGranted = true;
break;
}
@@ -230,8 +236,8 @@ public class Permissions {
}
}
- boolean permissionOrAppOpChanged = grantPermissionAndAppOp(packageName, permission,
- context);
+ boolean permissionOrAppOpChanged = grantPermissionAndAppOpAsUser(packageName, permission,
+ user, context);
// Update permission flags.
int newFlags = 0;
@@ -254,7 +260,7 @@ public class Permissions {
// If a component gets a permission for being the default handler A and also default handler
// B, we grant the weaker grant form. This only applies to default permission grant.
if (setGrantedByDefault && !setSystemFixed) {
- int oldFlags = getPermissionFlags(packageName, permission, context);
+ int oldFlags = getPermissionFlagsAsUser(packageName, permission, user, context);
if ((oldFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
&& (oldFlags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
if (DEBUG) {
@@ -265,20 +271,22 @@ public class Permissions {
}
}
- setPermissionFlags(packageName, permission, newFlags, newMask, context);
+ setPermissionFlagsAsUser(packageName, permission, newFlags, newMask,
+ user, context);
return permissionOrAppOpChanged;
}
- private static boolean isPermissionAndAppOpGranted(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
+ private static boolean isPermissionAndAppOpGrantedAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
// Check this permission.
- if (!isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) {
+ if (!isPermissionGrantedWithoutCheckingAppOpAsUser(packageName, permission, user,
+ context)) {
return false;
}
// Check if the permission is review required.
- if (isPermissionReviewRequired(packageName, permission, context)) {
+ if (isPermissionReviewRequiredAsUser(packageName, permission, user, context)) {
return false;
}
@@ -288,7 +296,7 @@ public class Permissions {
if (appOp == null) {
return true;
}
- Integer appOpMode = getAppOpMode(packageName, appOp, context);
+ Integer appOpMode = getAppOpModeAsUser(packageName, appOp, user, context);
if (appOpMode == null) {
return false;
}
@@ -314,7 +322,8 @@ public class Permissions {
if (foregroundAppOp == null) {
continue;
}
- Integer foregroundAppOpMode = getAppOpMode(packageName, foregroundAppOp, context);
+ Integer foregroundAppOpMode = getAppOpModeAsUser(packageName, foregroundAppOp,
+ user, context);
if (foregroundAppOpMode == null) {
continue;
}
@@ -326,11 +335,11 @@ public class Permissions {
}
}
- private static boolean grantPermissionAndAppOp(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
+ private static boolean grantPermissionAndAppOpAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
// Grant the permission.
- boolean permissionOrAppOpChanged = grantPermissionWithoutAppOp(packageName, permission,
- context);
+ boolean permissionOrAppOpChanged = grantPermissionWithoutAppOpAsUser(packageName,
+ permission, user, context);
// Grant the app op.
if (!isBackgroundPermission(permission, context)) {
@@ -345,13 +354,15 @@ public class Permissions {
// This permission is a foreground permission, set its app op mode according to
// whether its background permission is granted.
String backgroundPermission = getBackgroundPermission(permission, context);
- if (!isPermissionAndAppOpGranted(packageName, backgroundPermission, context)) {
+ if (!isPermissionAndAppOpGrantedAsUser(packageName, backgroundPermission,
+ user, context)) {
appOpMode = AppOpsManager.MODE_FOREGROUND;
} else {
appOpMode = AppOpsManager.MODE_ALLOWED;
}
}
- permissionOrAppOpChanged |= setAppOpUidMode(packageName, appOp, appOpMode, context);
+ permissionOrAppOpChanged |= setAppOpUidModeAsUser(packageName, appOp, appOpMode,
+ user, context);
}
} else {
// This permission is a background permission, set all its foreground permissions' app
@@ -365,8 +376,8 @@ public class Permissions {
if (foregroundAppOp == null) {
continue;
}
- permissionOrAppOpChanged |= setAppOpUidMode(packageName, foregroundAppOp,
- AppOpsManager.MODE_ALLOWED, context);
+ permissionOrAppOpChanged |= setAppOpUidModeAsUser(packageName, foregroundAppOp,
+ AppOpsManager.MODE_ALLOWED, user, context);
}
}
@@ -382,16 +393,18 @@ public class Permissions {
* @param onlyIfGrantedByDefault revoke the permission only if it is granted by default
* @param overrideSystemFixed whether system-fixed permissions can be revoked
* @param context the {@code Context} to retrieve system services
+ * @param user the user of the application
*
* @return whether any permission or app op changed
*
* @see com.android.server.pm.permission.DefaultPermissionGrantPolicy#revokeRuntimePermissions(
* String, java.util.Set, boolean, int)
*/
- public static boolean revoke(@NonNull String packageName, @NonNull List<String> permissions,
- boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault,
- boolean overrideSystemFixed, @NonNull Context context) {
- PackageInfo packageInfo = getPackageInfo(packageName, context);
+ public static boolean revokeAsUser(@NonNull String packageName,
+ @NonNull List<String> permissions, boolean onlyIfGrantedByRole,
+ boolean onlyIfGrantedByDefault, boolean overrideSystemFixed, @NonNull UserHandle user,
+ @NonNull Context context) {
+ PackageInfo packageInfo = getPackageInfoAsUser(packageName, user, context);
if (packageInfo == null) {
return false;
}
@@ -425,9 +438,10 @@ public class Permissions {
}
}
- PackageManager packageManager = context.getPackageManager();
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
Set<String> whitelistedRestrictedPermissions =
- packageManager.getWhitelistedRestrictedPermissions(packageName,
+ userPackageManager.getWhitelistedRestrictedPermissions(packageName,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
| PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
@@ -438,13 +452,14 @@ public class Permissions {
for (int i = 0; i < sortedPermissionsToRevokeLength; i++) {
String permission = sortedPermissionsToRevoke[i];
- permissionOrAppOpChanged |= revokeSingle(packageName, permission, onlyIfGrantedByRole,
- onlyIfGrantedByDefault, overrideSystemFixed, context);
+ permissionOrAppOpChanged |= revokeSingleAsUser(packageName, permission,
+ onlyIfGrantedByRole, onlyIfGrantedByDefault, overrideSystemFixed, user,
+ context);
// Remove from the system whitelist only if not granted by default.
- if (!isPermissionGrantedByDefault(packageName, permission, context)
+ if (!isPermissionGrantedByDefaultAsUser(packageName, permission, user, context)
&& whitelistedRestrictedPermissions.remove(permission)) {
- packageManager.removeWhitelistedRestrictedPermission(packageName, permission,
+ userPackageManager.removeWhitelistedRestrictedPermission(packageName, permission,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
}
}
@@ -452,59 +467,62 @@ public class Permissions {
return permissionOrAppOpChanged;
}
- private static boolean revokeSingle(@NonNull String packageName, @NonNull String permission,
- boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault,
- boolean overrideSystemFixed, @NonNull Context context) {
+ private static boolean revokeSingleAsUser(@NonNull String packageName,
+ @NonNull String permission, boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault,
+ boolean overrideSystemFixed, @NonNull UserHandle user, @NonNull Context context) {
if (onlyIfGrantedByRole == onlyIfGrantedByDefault) {
throw new IllegalArgumentException("Permission can be revoked only if either granted by"
+ " role, or granted by default, but not both");
}
if (onlyIfGrantedByRole) {
- if (!isPermissionGrantedByRole(packageName, permission, context)) {
+ if (!isPermissionGrantedByRoleAsUser(packageName, permission, user, context)) {
return false;
}
- setPermissionFlags(packageName, permission, 0,
- PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, context);
+ setPermissionFlagsAsUser(packageName, permission, 0,
+ PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, user, context);
}
if (onlyIfGrantedByDefault) {
- if (!isPermissionGrantedByDefault(packageName, permission, context)) {
+ if (!isPermissionGrantedByDefaultAsUser(packageName, permission, user, context)) {
return false;
}
// Remove the granted-by-default permission flag.
- setPermissionFlags(packageName, permission, 0,
- PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, context);
+ setPermissionFlagsAsUser(packageName, permission, 0,
+ PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, user, context);
// Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains sticky once
// set.
}
- if (isPermissionFixed(packageName, permission, overrideSystemFixed, false, context)
- && isPermissionAndAppOpGranted(packageName, permission, context)) {
+ if (isPermissionFixedAsUser(packageName, permission, overrideSystemFixed, false,
+ user, context)
+ && isPermissionAndAppOpGrantedAsUser(packageName, permission, user, context)) {
// Stop revoking if this permission is fixed to granted.
return false;
}
if (isForegroundPermission(permission, context)) {
String backgroundPermission = getBackgroundPermission(permission, context);
- if (isPermissionAndAppOpGranted(packageName, backgroundPermission, context)) {
+ if (isPermissionAndAppOpGrantedAsUser(packageName, backgroundPermission, user,
+ context)) {
// Stop revoking if this foreground permission has a granted background permission.
return false;
}
}
- return revokePermissionAndAppOp(packageName, permission, context);
+ return revokePermissionAndAppOpAsUser(packageName, permission, user, context);
}
- private static boolean revokePermissionAndAppOp(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
+ private static boolean revokePermissionAndAppOpAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
boolean permissionOrAppOpChanged = false;
- boolean isRuntimePermissionsSupported = isRuntimePermissionsSupported(packageName, context);
+ boolean isRuntimePermissionsSupported = isRuntimePermissionsSupportedAsUser(packageName,
+ user, context);
if (isRuntimePermissionsSupported) {
// Revoke the permission.
- permissionOrAppOpChanged |= revokePermissionWithoutAppOp(packageName, permission,
- context);
+ permissionOrAppOpChanged |= revokePermissionWithoutAppOpAsUser(packageName, permission,
+ user, context);
}
// Revoke the app op.
@@ -514,7 +532,8 @@ public class Permissions {
// This permission is an ordinary or foreground permission, reset its app op mode to
// default.
int appOpMode = getDefaultAppOpMode(appOp);
- boolean appOpModeChanged = setAppOpUidMode(packageName, appOp, appOpMode, context);
+ boolean appOpModeChanged = setAppOpUidModeAsUser(packageName, appOp, appOpMode,
+ user, context);
permissionOrAppOpChanged |= appOpModeChanged;
if (appOpModeChanged) {
@@ -523,9 +542,9 @@ public class Permissions {
|| appOpMode == AppOpsManager.MODE_ALLOWED)) {
// We've reset this permission's app op mode to be permissive, so we'll need
// the user to review it again.
- setPermissionFlags(packageName, permission,
+ setPermissionFlagsAsUser(packageName, permission,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED,
- PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, context);
+ PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, user, context);
}
}
}
@@ -537,7 +556,8 @@ public class Permissions {
for (int i = 0; i < foregroundPermissionsSize; i++) {
String foregroundPermission = foregroundPermissions.get(i);
- if (!isPermissionAndAppOpGranted(packageName, foregroundPermission, context)) {
+ if (!isPermissionAndAppOpGrantedAsUser(packageName, foregroundPermission, user,
+ context)) {
continue;
}
@@ -545,8 +565,8 @@ public class Permissions {
if (foregroundAppOp == null) {
continue;
}
- permissionOrAppOpChanged |= setAppOpUidMode(packageName, foregroundAppOp,
- AppOpsManager.MODE_FOREGROUND, context);
+ permissionOrAppOpChanged |= setAppOpUidModeAsUser(packageName, foregroundAppOp,
+ AppOpsManager.MODE_FOREGROUND, user, context);
}
}
@@ -554,24 +574,25 @@ public class Permissions {
}
@Nullable
- private static PackageInfo getPackageInfo(@NonNull String packageName,
- @NonNull Context context) {
- return getPackageInfo(packageName, 0, context);
+ private static PackageInfo getPackageInfoAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return getPackageInfoAsUser(packageName, 0, user, context);
}
@Nullable
- private static PackageInfo getFactoryPackageInfo(@NonNull String packageName,
- @NonNull Context context) {
- return getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY, context);
+ private static PackageInfo getFactoryPackageInfoAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return getPackageInfoAsUser(packageName, PackageManager.MATCH_FACTORY_ONLY,
+ user, context);
}
@Nullable
- private static PackageInfo getPackageInfo(@NonNull String packageName, int extraFlags,
- @NonNull Context context) {
- return PackageUtils.getPackageInfo(packageName, extraFlags
+ private static PackageInfo getPackageInfoAsUser(@NonNull String packageName, int extraFlags,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return PackageUtils.getPackageInfoAsUser(packageName, extraFlags
// TODO: Why MATCH_UNINSTALLED_PACKAGES?
| PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS,
- context);
+ user, context);
}
private static boolean isUpdatedSystemApp(@NonNull PackageInfo packageInfo) {
@@ -579,27 +600,26 @@ public class Permissions {
& ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
- static boolean isRuntimePermissionsSupported(@NonNull String packageName,
- @NonNull Context context) {
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
- Process.myUserHandle(), context);
+ static boolean isRuntimePermissionsSupportedAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user,
+ context);
if (applicationInfo == null) {
return false;
}
return applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
}
- private static int getPermissionFlags(@NonNull String packageName, @NonNull String permission,
- @NonNull Context context) {
+ private static int getPermissionFlagsAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
PackageManager packageManager = context.getPackageManager();
- UserHandle user = Process.myUserHandle();
return packageManager.getPermissionFlags(permission, packageName, user);
}
- private static boolean isPermissionFixed(@NonNull String packageName,
+ private static boolean isPermissionFixedAsUser(@NonNull String packageName,
@NonNull String permission, boolean overrideSystemFixed,
- boolean overrideUserSetAndFixed, @NonNull Context context) {
- int flags = getPermissionFlags(packageName, permission, context);
+ boolean overrideUserSetAndFixed, @NonNull UserHandle user, @NonNull Context context) {
+ int flags = getPermissionFlagsAsUser(packageName, permission, user, context);
int fixedFlags = PackageManager.FLAG_PERMISSION_POLICY_FIXED;
if (!overrideSystemFixed) {
fixedFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
@@ -611,67 +631,69 @@ public class Permissions {
return (flags & fixedFlags) != 0;
}
- private static boolean isPermissionGrantedByDefault(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
- int flags = getPermissionFlags(packageName, permission, context);
+ private static boolean isPermissionGrantedByDefaultAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
+ int flags = getPermissionFlagsAsUser(packageName, permission, user, context);
return (flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0;
}
- static boolean isPermissionGrantedByRole(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
- int flags = getPermissionFlags(packageName, permission, context);
+ static boolean isPermissionGrantedByRoleAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
+ int flags = getPermissionFlagsAsUser(packageName, permission, user, context);
return (flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE) != 0;
}
- private static boolean isPermissionReviewRequired(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
- int flags = getPermissionFlags(packageName, permission, context);
+ private static boolean isPermissionReviewRequiredAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
+ int flags = getPermissionFlagsAsUser(packageName, permission, user, context);
return (flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
}
- private static void setPermissionFlags(@NonNull String packageName, @NonNull String permission,
- int flags, int mask, @NonNull Context context) {
+ private static void setPermissionFlagsAsUser(@NonNull String packageName,
+ @NonNull String permission, int flags, int mask, @NonNull UserHandle user,
+ @NonNull Context context) {
PackageManager packageManager = context.getPackageManager();
- UserHandle user = Process.myUserHandle();
packageManager.updatePermissionFlags(permission, packageName, mask, flags, user);
}
- static void setPermissionGrantedByRole(@NonNull String packageName,
- @NonNull String permission, boolean grantedByRole, @NonNull Context context) {
- setPermissionFlags(packageName, permission,
+ static void setPermissionGrantedByRoleAsUser(@NonNull String packageName,
+ @NonNull String permission, boolean grantedByRole, @NonNull UserHandle user,
+ @NonNull Context context) {
+ setPermissionFlagsAsUser(packageName, permission,
grantedByRole ? PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE : 0,
- PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, context);
+ PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, user, context);
}
/**
* Most of the time {@link #isPermissionAndAppOpGranted(String, String, Context)} should be used
* instead.
*/
- private static boolean isPermissionGrantedWithoutCheckingAppOp(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
- PackageManager packageManager = context.getPackageManager();
- return packageManager.checkPermission(permission, packageName)
+ private static boolean isPermissionGrantedWithoutCheckingAppOpAsUser(
+ @NonNull String packageName, @NonNull String permission, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
+ return userPackageManager.checkPermission(permission, packageName)
== PackageManager.PERMISSION_GRANTED;
}
- private static boolean grantPermissionWithoutAppOp(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
- if (isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) {
+ private static boolean grantPermissionWithoutAppOpAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
+ if (isPermissionGrantedWithoutCheckingAppOpAsUser(packageName, permission, user, context)) {
return false;
}
PackageManager packageManager = context.getPackageManager();
- UserHandle user = Process.myUserHandle();
packageManager.grantRuntimePermission(packageName, permission, user);
return true;
}
- private static boolean revokePermissionWithoutAppOp(@NonNull String packageName,
- @NonNull String permission, @NonNull Context context) {
- if (!isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) {
+ private static boolean revokePermissionWithoutAppOpAsUser(@NonNull String packageName,
+ @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) {
+ if (!isPermissionGrantedWithoutCheckingAppOpAsUser(packageName, permission, user,
+ context)) {
return false;
}
PackageManager packageManager = context.getPackageManager();
- UserHandle user = Process.myUserHandle();
packageManager.revokeRuntimePermission(packageName, permission, user);
return true;
}
@@ -816,10 +838,10 @@ public class Permissions {
}
@Nullable
- static Integer getAppOpMode(@NonNull String packageName, @NonNull String appOp,
- @NonNull Context context) {
+ static Integer getAppOpModeAsUser(@NonNull String packageName, @NonNull String appOp,
+ @NonNull UserHandle user, @NonNull Context context) {
ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
- Process.myUserHandle(), context);
+ user, context);
if (applicationInfo == null) {
return null;
}
@@ -831,24 +853,24 @@ public class Permissions {
return AppOpsManager.opToDefaultMode(appOp);
}
- static boolean setAppOpUidMode(@NonNull String packageName, @NonNull String appOp, int mode,
- @NonNull Context context) {
- return setAppOpMode(packageName, appOp, mode, true, context);
+ static boolean setAppOpUidModeAsUser(@NonNull String packageName, @NonNull String appOp,
+ int mode, @NonNull UserHandle user, @NonNull Context context) {
+ return setAppOpModeAsUser(packageName, appOp, mode, true, user, context);
}
- static boolean setAppOpPackageMode(@NonNull String packageName, @NonNull String appOp, int mode,
- @NonNull Context context) {
- return setAppOpMode(packageName, appOp, mode, false, context);
+ static boolean setAppOpPackageModeAsUser(@NonNull String packageName, @NonNull String appOp,
+ int mode, @NonNull UserHandle user, @NonNull Context context) {
+ return setAppOpModeAsUser(packageName, appOp, mode, false, user, context);
}
- private static boolean setAppOpMode(@NonNull String packageName, @NonNull String appOp,
- int mode, boolean setUidMode, @NonNull Context context) {
- Integer currentMode = getAppOpMode(packageName, appOp, context);
+ private static boolean setAppOpModeAsUser(@NonNull String packageName, @NonNull String appOp,
+ int mode, boolean setUidMode, @NonNull UserHandle user, @NonNull Context context) {
+ Integer currentMode = getAppOpModeAsUser(packageName, appOp, user, context);
if (currentMode != null && currentMode == mode) {
return false;
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
- Process.myUserHandle(), context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user,
+ context);
if (applicationInfo == null) {
Log.e(LOG_TAG, "Cannot get ApplicationInfo for package to set app op mode: "
+ packageName);
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java b/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java
index 5b9c22b67..7ea7de046 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java
@@ -22,9 +22,12 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
import androidx.annotation.NonNull;
+import com.android.role.controller.util.UserUtils;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -67,18 +70,21 @@ public class PreferredActivity {
* Configure this preferred activity specification for an application.
*
* @param packageName the package name of the application
+ * @param user the user of the application
* @param context the {@code Context} to retrieve system services
*/
- public void configure(@NonNull String packageName, @NonNull Context context) {
- ComponentName packageActivity = mActivity.getQualifyingComponentForPackage(
- packageName, context);
+ public void configureAsUser(@NonNull String packageName, @NonNull UserHandle user,
+ @NonNull Context context) {
+ ComponentName packageActivity = mActivity.getQualifyingComponentForPackageAsUser(
+ packageName, user, context);
if (packageActivity == null) {
// We might be running into some race condition here, but we can't do anything about it.
// This should be handled by a future reconciliation started by the package change.
return;
}
- PackageManager packageManager = context.getPackageManager();
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
int intentFilterDatasSize = mIntentFilterDatas.size();
for (int i = 0; i < intentFilterDatasSize; i++) {
IntentFilterData intentFilterData = mIntentFilterDatas.get(i);
@@ -92,7 +98,7 @@ public class PreferredActivity {
? IntentFilter.MATCH_CATEGORY_SCHEME : IntentFilter.MATCH_CATEGORY_EMPTY;
Intent intent = intentFilterData.createIntent();
- List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent,
+ List<ResolveInfo> resolveInfos = userPackageManager.queryIntentActivities(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DEFAULT_ONLY);
@@ -107,7 +113,7 @@ public class PreferredActivity {
set.add(componentName);
}
- packageManager.replacePreferredActivity(intentFilter, match, set, packageActivity);
+ userPackageManager.replacePreferredActivity(intentFilter, match, set, packageActivity);
}
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java
index 58c878e56..25c97aefb 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java
@@ -16,12 +16,11 @@
package com.android.role.controller.model;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.Bundle;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -52,11 +51,15 @@ public class RequiredActivity extends RequiredComponent {
return userPackageManager.queryIntentActivities(intent, flags);
}
+ @Override
+ protected boolean isComponentQualified(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.activityInfo.exported;
+ }
+
@NonNull
@Override
- protected ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo) {
- return new ComponentName(resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name);
+ protected ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.activityInfo;
}
@Override
@@ -69,10 +72,4 @@ public class RequiredActivity extends RequiredComponent {
protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) {
return resolveInfo.activityInfo.permission;
}
-
- @Nullable
- @Override
- protected Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo) {
- return resolveInfo.activityInfo.metaData;
- }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java
index 945fda3c3..1e23af256 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java
@@ -16,12 +16,11 @@
package com.android.role.controller.model;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.Bundle;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -53,9 +52,8 @@ public class RequiredBroadcastReceiver extends RequiredComponent {
@NonNull
@Override
- protected ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo) {
- return new ComponentName(resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name);
+ protected ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.activityInfo;
}
@Override
@@ -68,10 +66,4 @@ public class RequiredBroadcastReceiver extends RequiredComponent {
protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) {
return resolveInfo.activityInfo.permission;
}
-
- @Nullable
- @Override
- protected Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo) {
- return resolveInfo.activityInfo.metaData;
- }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java
index ae6156e7f..6e067488c 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java
@@ -20,11 +20,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
-import android.os.Process;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -108,9 +108,9 @@ public abstract class RequiredComponent {
* @return whether this required component is available
*/
public boolean isAvailable() {
- // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization.
- if (mMinTargetSdkVersion >= 34) {
- return SdkLevel.isAtLeastU();
+ // Workaround to match the value 35+ for V+ in roles.xml before SDK finalization.
+ if (mMinTargetSdkVersion >= 35) {
+ return SdkLevel.isAtLeastV();
} else {
return Build.VERSION.SDK_INT >= mMinTargetSdkVersion;
}
@@ -144,15 +144,16 @@ public abstract class RequiredComponent {
* Get the component that matches this required component within a package, if any.
*
* @param packageName the package name for this query
+ * @param user the user of the component
* @param context the {@code Context} to retrieve system services
*
* @return the matching component, or {@code null} if none.
*/
@Nullable
- public ComponentName getQualifyingComponentForPackage(@NonNull String packageName,
- @NonNull Context context) {
- List<ComponentName> componentNames = getQualifyingComponentsInternal(packageName,
- Process.myUserHandle(), context);
+ public ComponentName getQualifyingComponentForPackageAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ List<ComponentName> componentNames = getQualifyingComponentsAsUserInternal(packageName,
+ user, context);
return !componentNames.isEmpty() ? componentNames.get(0) : null;
}
@@ -170,11 +171,11 @@ public abstract class RequiredComponent {
@NonNull
public List<ComponentName> getQualifyingComponentsAsUser(@NonNull UserHandle user,
@NonNull Context context) {
- return getQualifyingComponentsInternal(null, user, context);
+ return getQualifyingComponentsAsUserInternal(null, user, context);
}
@NonNull
- private List<ComponentName> getQualifyingComponentsInternal(@Nullable String packageName,
+ private List<ComponentName> getQualifyingComponentsAsUserInternal(@Nullable String packageName,
@NonNull UserHandle user, @NonNull Context context) {
Intent intent = mIntentFilterData.createIntent();
if (packageName != null) {
@@ -195,6 +196,10 @@ public abstract class RequiredComponent {
for (int resolveInfosIndex = 0; resolveInfosIndex < resolveInfosSize; resolveInfosIndex++) {
ResolveInfo resolveInfo = resolveInfos.get(resolveInfosIndex);
+ if (!isComponentQualified(resolveInfo)) {
+ continue;
+ }
+
if (mFlags != 0) {
int componentFlags = getComponentFlags(resolveInfo);
if ((componentFlags & mFlags) != mFlags) {
@@ -209,8 +214,9 @@ public abstract class RequiredComponent {
}
}
+ ComponentInfo componentInfo = getComponentComponentInfo(resolveInfo);
if (hasMetaData) {
- Bundle componentMetaData = getComponentMetaData(resolveInfo);
+ Bundle componentMetaData = componentInfo.metaData;
if (componentMetaData == null) {
componentMetaData = Bundle.EMPTY;
}
@@ -229,13 +235,14 @@ public abstract class RequiredComponent {
}
}
- ComponentName componentName = getComponentComponentName(resolveInfo);
- String componentPackageName = componentName.getPackageName();
+ String componentPackageName = componentInfo.packageName;
if (componentPackageNames.contains(componentPackageName)) {
continue;
}
-
componentPackageNames.add(componentPackageName);
+
+ ComponentName componentName = new ComponentName(componentPackageName,
+ componentInfo.name);
componentNames.add(componentName);
}
return componentNames;
@@ -256,15 +263,19 @@ public abstract class RequiredComponent {
protected abstract List<ResolveInfo> queryIntentComponentsAsUser(@NonNull Intent intent,
int flags, @NonNull UserHandle user, @NonNull Context context);
+ protected boolean isComponentQualified(@NonNull ResolveInfo resolveInfo) {
+ return true;
+ }
+
/**
- * Get the {@code ComponentName} of a component.
+ * Get the {@code ComponentInfo} of a component.
*
* @param resolveInfo the {@code ResolveInfo} of the component
*
- * @return the {@code ComponentName} of the component
+ * @return the {@code ComponentInfo} of the component
*/
@NonNull
- protected abstract ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo);
+ protected abstract ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo);
/**
* Get the flags that have been set on a component.
@@ -285,16 +296,6 @@ public abstract class RequiredComponent {
@Nullable
protected abstract String getComponentPermission(@NonNull ResolveInfo resolveInfo);
- /**
- * Get the meta data associated with a component.
- *
- * @param resolveInfo the {@code ResolveInfo} of the component
- *
- * @return the meta data associated with a component
- */
- @Nullable
- protected abstract Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo);
-
@Override
public String toString() {
return "RequiredComponent{"
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java
index 7b53a25bb..b02062b11 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java
@@ -16,12 +16,11 @@
package com.android.role.controller.model;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.Bundle;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -53,9 +52,8 @@ public class RequiredContentProvider extends RequiredComponent {
@NonNull
@Override
- protected ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo) {
- return new ComponentName(resolveInfo.providerInfo.packageName,
- resolveInfo.providerInfo.name);
+ protected ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.providerInfo;
}
@Override
@@ -70,10 +68,4 @@ public class RequiredContentProvider extends RequiredComponent {
//return resolveInfo.providerInfo.readPermission;
throw new UnsupportedOperationException();
}
-
- @Nullable
- @Override
- protected Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo) {
- return resolveInfo.providerInfo.metaData;
- }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java
index f27aae013..0532e53b2 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java
@@ -16,12 +16,11 @@
package com.android.role.controller.model;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.Bundle;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -53,8 +52,8 @@ public class RequiredService extends RequiredComponent {
@NonNull
@Override
- protected ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo) {
- return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
+ protected ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.serviceInfo;
}
@Override
@@ -67,10 +66,4 @@ public class RequiredService extends RequiredComponent {
protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) {
return resolveInfo.serviceInfo.permission;
}
-
- @Nullable
- @Override
- protected Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo) {
- return resolveInfo.serviceInfo.metaData;
- }
}
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 9ff16db0f..fe062ef53 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.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.os.Build;
-import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -129,6 +128,11 @@ public class Role {
private final int mMinSdkVersion;
/**
+ * Whether this role should only grant privileges when a role holder is actively added.
+ */
+ private final boolean mOnlyGrantWhenAdded;
+
+ /**
* Whether this role should override user's choice about privileges when granting.
*/
private final boolean mOverrideUserWhenGranting;
@@ -225,11 +229,11 @@ public class Role {
@Nullable RoleBehavior behavior, @Nullable String defaultHoldersResourceName,
@StringRes int descriptionResource, boolean exclusive, boolean fallBackToDefaultHolder,
@StringRes int labelResource, int maxSdkVersion, int minSdkVersion,
- boolean overrideUserWhenGranting, @StringRes int requestDescriptionResource,
- @StringRes int requestTitleResource, boolean requestable,
- @StringRes int searchKeywordsResource, @StringRes int shortLabelResource,
- boolean showNone, boolean statik, boolean systemOnly, boolean visible,
- @NonNull List<RequiredComponent> requiredComponents,
+ boolean onlyGrantWhenAdded, boolean overrideUserWhenGranting,
+ @StringRes int requestDescriptionResource, @StringRes int requestTitleResource,
+ boolean requestable, @StringRes int searchKeywordsResource,
+ @StringRes int shortLabelResource, boolean showNone, boolean statik, boolean systemOnly,
+ boolean visible, @NonNull List<RequiredComponent> requiredComponents,
@NonNull List<Permission> permissions, @NonNull List<Permission> appOpPermissions,
@NonNull List<AppOp> appOps, @NonNull List<PreferredActivity> preferredActivities,
@Nullable String uiBehaviorName) {
@@ -243,6 +247,7 @@ public class Role {
mLabelResource = labelResource;
mMaxSdkVersion = maxSdkVersion;
mMinSdkVersion = minSdkVersion;
+ mOnlyGrantWhenAdded = onlyGrantWhenAdded;
mOverrideUserWhenGranting = overrideUserWhenGranting;
mRequestDescriptionResource = requestDescriptionResource;
mRequestTitleResource = requestTitleResource;
@@ -310,6 +315,13 @@ public class Role {
}
/**
+ * @see #mOnlyGrantWhenAdded
+ */
+ public boolean shouldOnlyGrantWhenAdded() {
+ return mOnlyGrantWhenAdded;
+ }
+
+ /**
* @see #mOverrideUserWhenGranting
*/
public boolean shouldOverrideUserWhenGranting() {
@@ -360,11 +372,12 @@ public class Role {
/**
* Callback when this role is added to the system for the first time.
*
+ * @param user the user to add the role for
* @param context the {@code Context} to retrieve system services
*/
- public void onRoleAdded(@NonNull Context context) {
+ public void onRoleAddedAsUser(@NonNull UserHandle user, @NonNull Context context) {
if (mBehavior != null) {
- mBehavior.onRoleAdded(this, context);
+ mBehavior.onRoleAddedAsUser(this, user, context);
}
}
@@ -392,26 +405,15 @@ public class Role {
* @return whether this role is available based on SDK version
*/
boolean isAvailableBySdkVersion() {
- // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization.
- if (mMinSdkVersion >= 34) {
- return SdkLevel.isAtLeastU();
+ // Workaround to match the value 35+ for V+ in roles.xml before SDK finalization.
+ if (mMinSdkVersion >= 35) {
+ return SdkLevel.isAtLeastV();
} else {
return Build.VERSION.SDK_INT >= mMinSdkVersion
&& Build.VERSION.SDK_INT <= mMaxSdkVersion;
}
}
- /**
- * Check whether this role is available, for current user.
- *
- * @param context the {@code Context} to retrieve system services
- *
- * @return whether this role is available.
- */
- public boolean isAvailable(@NonNull Context context) {
- return isAvailableAsUser(Process.myUserHandle(), context);
- }
-
public boolean isStatic() {
return mStatic;
}
@@ -420,16 +422,21 @@ public class Role {
* Get the default holders of this role, which will be added when the role is added for the
* first time.
*
+ * @param user the user of the role
* @param context the {@code Context} to retrieve system services
- *
* @return the list of package names of the default holders
*/
@NonNull
- public List<String> getDefaultHolders(@NonNull Context context) {
- if (mDefaultHoldersResourceName == null) {
- if (mBehavior != null) {
- return mBehavior.getDefaultHolders(this, context);
+ public List<String> getDefaultHoldersAsUser(@NonNull UserHandle user,
+ @NonNull Context context) {
+ if (mBehavior != null) {
+ List<String> defaultHolders = mBehavior.getDefaultHoldersAsUser(this, user, context);
+ if (defaultHolders != null) {
+ return defaultHolders;
}
+ }
+
+ if (mDefaultHoldersResourceName == null) {
return Collections.emptyList();
}
@@ -454,7 +461,8 @@ public class Role {
}
if (isExclusive()) {
- String packageName = getQualifiedDefaultHolderPackageName(defaultHolders, context);
+ String packageName = getQualifiedDefaultHolderPackageNameAsUser(defaultHolders, user,
+ context);
if (packageName == null) {
return Collections.emptyList();
}
@@ -462,7 +470,8 @@ public class Role {
} else {
List<String> packageNames = new ArrayList<>();
for (String defaultHolder : defaultHolders.split(DEFAULT_HOLDER_SEPARATOR)) {
- String packageName = getQualifiedDefaultHolderPackageName(defaultHolder, context);
+ String packageName = getQualifiedDefaultHolderPackageNameAsUser(defaultHolder,
+ user, context);
if (packageName != null) {
packageNames.add(packageName);
}
@@ -472,8 +481,8 @@ public class Role {
}
@Nullable
- private String getQualifiedDefaultHolderPackageName(@NonNull String defaultHolder,
- @NonNull Context context) {
+ private String getQualifiedDefaultHolderPackageNameAsUser(@NonNull String defaultHolder,
+ @NonNull UserHandle user, @NonNull Context context) {
String packageName;
byte[] certificate;
int certificateSeparatorIndex = defaultHolder.indexOf(CERTIFICATE_SEPARATOR);
@@ -492,8 +501,9 @@ public class Role {
}
if (certificate != null) {
- PackageManager packageManager = context.getPackageManager();
- if (!packageManager.hasSigningCertificate(packageName, certificate,
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
+ if (!userPackageManager.hasSigningCertificate(packageName, certificate,
PackageManager.CERT_INPUT_SHA256)) {
Log.w(LOG_TAG, "Default holder doesn't have required signing certificate: "
+ defaultHolder);
@@ -501,7 +511,7 @@ public class Role {
}
} else {
ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
- Process.myUserHandle(), context);
+ user, context);
if (applicationInfo == null) {
Log.w(LOG_TAG, "Cannot get ApplicationInfo for default holder: " + packageName);
return null;
@@ -521,20 +531,20 @@ public class Role {
* <p>
* Should return {@code null} if this role {@link #mShowNone shows a "None" item}.
*
+ * @param user the user of the role
* @param context the {@code Context} to retrieve system services
- *
* @return the package name of the fallback holder, or {@code null} if none
*/
@Nullable
- public String getFallbackHolder(@NonNull Context context) {
- if (!RoleManagerCompat.isRoleFallbackEnabledAsUser(this, Process.myUserHandle(), context)) {
+ public String getFallbackHolderAsUser(@NonNull UserHandle user, @NonNull Context context) {
+ if (!RoleManagerCompat.isRoleFallbackEnabledAsUser(this, user, context)) {
return null;
}
if (mFallBackToDefaultHolder) {
- return CollectionUtils.firstOrNull(getDefaultHolders(context));
+ return CollectionUtils.firstOrNull(getDefaultHoldersAsUser(user, context));
}
if (mBehavior != null) {
- return mBehavior.getFallbackHolder(this, context);
+ return mBehavior.getFallbackHolderAsUser(this, user, context);
}
return null;
}
@@ -562,29 +572,32 @@ public class Role {
* components (plus meeting some other general restrictions).
*
* @param packageName the package name to check for
+ * @param user the user to check for
* @param context the {@code Context} to retrieve system services
*
* @return whether the package is qualified for a role
*/
- public boolean isPackageQualified(@NonNull String packageName, @NonNull Context context) {
+ public boolean isPackageQualifiedAsUser(@NonNull String packageName, @NonNull UserHandle user,
+ @NonNull Context context) {
RoleManager roleManager = context.getSystemService(RoleManager.class);
if (shouldAllowBypassingQualification(context)
&& RoleManagerCompat.isBypassingRoleQualification(roleManager)) {
return true;
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
- Process.myUserHandle(), context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user,
+ context);
if (applicationInfo == null) {
Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName);
return false;
}
- if (!isPackageMinimallyQualifiedAsUser(applicationInfo, Process.myUserHandle(), context)) {
+ if (!isPackageMinimallyQualifiedAsUser(applicationInfo, user, context)) {
return false;
}
if (mBehavior != null) {
- Boolean isPackageQualified = mBehavior.isPackageQualified(this, packageName, context);
+ Boolean isPackageQualified = mBehavior.isPackageQualifiedAsUser(this, packageName,
+ user, context);
if (isPackageQualified != null) {
return isPackageQualified;
}
@@ -598,14 +611,15 @@ public class Role {
continue;
}
- if (requiredComponent.getQualifyingComponentForPackage(packageName, context) == null) {
+ if (requiredComponent.getQualifyingComponentForPackageAsUser(packageName, user, context)
+ == null) {
Log.i(LOG_TAG, packageName + " not qualified for " + mName
+ " due to missing " + requiredComponent);
return false;
}
}
- if (mStatic && !getDefaultHolders(context).contains(packageName)) {
+ if (mStatic && !getDefaultHoldersAsUser(user, context).contains(packageName)) {
return false;
}
@@ -778,41 +792,42 @@ public class Role {
* @param packageName the package name of the application to be granted this role to
* @param dontKillApp whether this application should not be killed despite changes
* @param overrideUser whether to override user when granting privileges
+ * @param user the user of the application
* @param context the {@code Context} to retrieve system services
*/
- public void grant(@NonNull String packageName, boolean dontKillApp,
- boolean overrideUser, @NonNull Context context) {
- boolean permissionOrAppOpChanged = Permissions.grant(packageName,
+ public void grantAsUser(@NonNull String packageName, boolean dontKillApp,
+ boolean overrideUser, @NonNull UserHandle user, @NonNull Context context) {
+ boolean permissionOrAppOpChanged = Permissions.grantAsUser(packageName,
Permissions.filterBySdkVersion(mPermissions),
SdkLevel.isAtLeastS() ? !mSystemOnly : true, overrideUser, true, false, false,
- context);
+ user, context);
List<String> appOpPermissionsToGrant = Permissions.filterBySdkVersion(mAppOpPermissions);
int appOpPermissionsSize = appOpPermissionsToGrant.size();
for (int i = 0; i < appOpPermissionsSize; i++) {
String appOpPermission = appOpPermissionsToGrant.get(i);
- AppOpPermissions.grant(packageName, appOpPermission, overrideUser, context);
+ AppOpPermissions.grantAsUser(packageName, appOpPermission, overrideUser, user, context);
}
int appOpsSize = mAppOps.size();
for (int i = 0; i < appOpsSize; i++) {
AppOp appOp = mAppOps.get(i);
- appOp.grant(packageName, context);
+ appOp.grantAsUser(packageName, user, context);
}
int preferredActivitiesSize = mPreferredActivities.size();
for (int i = 0; i < preferredActivitiesSize; i++) {
PreferredActivity preferredActivity = mPreferredActivities.get(i);
- preferredActivity.configure(packageName, context);
+ preferredActivity.configureAsUser(packageName, user, context);
}
if (mBehavior != null) {
- mBehavior.grant(this, packageName, context);
+ mBehavior.grantAsUser(this, packageName, user, context);
}
- if (!dontKillApp && permissionOrAppOpChanged && !Permissions.isRuntimePermissionsSupported(
- packageName, context)) {
- killApp(packageName, context);
+ if (!dontKillApp && permissionOrAppOpChanged
+ && !Permissions.isRuntimePermissionsSupportedAsUser(packageName, user, context)) {
+ killAppAsUser(packageName, user, context);
}
}
@@ -822,12 +837,15 @@ public class Role {
* @param packageName the package name of the application to be granted this role to
* @param dontKillApp whether this application should not be killed despite changes
* @param overrideSystemFixedPermissions whether system-fixed permissions can be revoked
+ * @param user the user of the role
* @param context the {@code Context} to retrieve system services
*/
- public void revoke(@NonNull String packageName, boolean dontKillApp,
- boolean overrideSystemFixedPermissions, @NonNull Context context) {
- RoleManager roleManager = context.getSystemService(RoleManager.class);
- List<String> otherRoleNames = roleManager.getHeldRolesFromController(packageName);
+ public void revokeAsUser(@NonNull String packageName, boolean dontKillApp,
+ boolean overrideSystemFixedPermissions, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ RoleManager userRoleManager = userContext.getSystemService(RoleManager.class);
+ List<String> otherRoleNames = userRoleManager.getHeldRolesFromController(packageName);
otherRoleNames.remove(mName);
List<String> permissionsToRevoke = Permissions.filterBySdkVersion(mPermissions);
@@ -839,8 +857,8 @@ public class Role {
permissionsToRevoke.removeAll(Permissions.filterBySdkVersion(role.mPermissions));
}
- boolean permissionOrAppOpChanged = Permissions.revoke(packageName, permissionsToRevoke,
- true, false, overrideSystemFixedPermissions, context);
+ boolean permissionOrAppOpChanged = Permissions.revokeAsUser(packageName,
+ permissionsToRevoke, true, false, overrideSystemFixedPermissions, user, context);
List<String> appOpPermissionsToRevoke = Permissions.filterBySdkVersion(mAppOpPermissions);
for (int i = 0; i < otherRoleNamesSize; i++) {
@@ -852,7 +870,7 @@ public class Role {
int appOpPermissionsSize = appOpPermissionsToRevoke.size();
for (int i = 0; i < appOpPermissionsSize; i++) {
String appOpPermission = appOpPermissionsToRevoke.get(i);
- AppOpPermissions.revoke(packageName, appOpPermission, context);
+ AppOpPermissions.revokeAsUser(packageName, appOpPermission, user, context);
}
List<AppOp> appOpsToRevoke = new ArrayList<>(mAppOps);
@@ -864,7 +882,7 @@ public class Role {
int appOpsSize = appOpsToRevoke.size();
for (int i = 0; i < appOpsSize; i++) {
AppOp appOp = appOpsToRevoke.get(i);
- appOp.revoke(packageName, context);
+ appOp.revokeAsUser(packageName, user, context);
}
// TODO: Revoke preferred activities? But this is unnecessary for most roles using it as
@@ -873,22 +891,23 @@ public class Role {
// wrong thing when we are removing a exclusive role holder for adding another.
if (mBehavior != null) {
- mBehavior.revoke(this, packageName, context);
+ mBehavior.revokeAsUser(this, packageName, user, context);
}
if (!dontKillApp && permissionOrAppOpChanged) {
- killApp(packageName, context);
+ killAppAsUser(packageName, user, context);
}
}
- private void killApp(@NonNull String packageName, @NonNull Context context) {
+ private void killAppAsUser(@NonNull String packageName, @NonNull UserHandle user,
+ @NonNull Context context) {
if (DEBUG) {
Log.i(LOG_TAG, "Killing " + packageName + " due to "
+ Thread.currentThread().getStackTrace()[3].getMethodName()
+ "(" + mName + ")");
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
- Process.myUserHandle(), context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user,
+ context);
if (applicationInfo == null) {
Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName);
return;
@@ -947,6 +966,40 @@ public class Role {
RoleManagerCompat.setRoleFallbackEnabledAsUser(this, false, user, context);
}
+ /**
+ * Check whether this role should be visible to user.
+ *
+ * @param user the user to check for
+ * @param context the `Context` to retrieve system services
+ *
+ * @return whether this role should be visible to user
+ */
+ public boolean isVisibleAsUser(@NonNull UserHandle user, @NonNull Context context) {
+ RoleBehavior behavior = getBehavior();
+ if (behavior == null) {
+ return isVisible();
+ }
+ return isVisible() && behavior.isVisibleAsUser(this, user, context);
+ }
+
+ /**
+ * Check whether a qualifying application should be visible to user.
+ *
+ * @param applicationInfo the {@link ApplicationInfo} for the application
+ * @param user the user for the application
+ * @param context the {@code Context} to retrieve system services
+ *
+ * @return whether the qualifying application should be visible to user
+ */
+ public boolean isApplicationVisibleAsUser(@NonNull ApplicationInfo applicationInfo,
+ @NonNull UserHandle user, @NonNull Context context) {
+ RoleBehavior behavior = getBehavior();
+ if (behavior == null) {
+ return true;
+ }
+ return behavior.isApplicationVisibleAsUser(this, applicationInfo, user, context);
+ }
+
@Override
public String toString() {
return "Role{"
@@ -960,6 +1013,7 @@ public class Role {
+ ", mLabelResource=" + mLabelResource
+ ", mMaxSdkVersion=" + mMaxSdkVersion
+ ", mMinSdkVersion=" + mMinSdkVersion
+ + ", mOnlyGrantWhenAdded=" + mOnlyGrantWhenAdded
+ ", mOverrideUserWhenGranting=" + mOverrideUserWhenGranting
+ ", mRequestDescriptionResource=" + mRequestDescriptionResource
+ ", mRequestTitleResource=" + mRequestTitleResource
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java
index f0c4fc018..3849a50e3 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java
@@ -17,6 +17,7 @@
package com.android.role.controller.model;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -31,9 +32,10 @@ import java.util.List;
public interface RoleBehavior {
/**
- * @see Role#onRoleAdded(Context)
+ * @see Role#onRoleAddedAsUser(UserHandle, Context)
*/
- default void onRoleAdded(@NonNull Role role, @NonNull Context context) {}
+ default void onRoleAddedAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {}
/**
* @see Role#isAvailableAsUser(UserHandle, Context)
@@ -46,16 +48,18 @@ public interface RoleBehavior {
/**
* @see Role#getDefaultHolders(Context)
*/
- @NonNull
- default List<String> getDefaultHolders(@NonNull Role role, @NonNull Context context) {
- return Collections.emptyList();
+ @Nullable
+ default List<String> getDefaultHoldersAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return null;
}
/**
* @see Role#getFallbackHolder(Context)
*/
@Nullable
- default String getFallbackHolder(@NonNull Role role, @NonNull Context context) {
+ default String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
return null;
}
@@ -72,8 +76,8 @@ public interface RoleBehavior {
* @see Role#isPackageQualified(String, Context)
*/
@Nullable
- default Boolean isPackageQualified(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
+ default Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
return null;
}
@@ -87,15 +91,16 @@ public interface RoleBehavior {
}
/**
- * @see Role#grant(String, boolean, boolean, boolean, Context)
+ * @see Role#grantAsUser(String, boolean, boolean, UserHandle, Context)
*/
- default void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {}
+ default void grantAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {}
/**
- * @see Role#revoke(String, boolean, boolean, Context)
+ * @see Role#revokeAsUser(String, boolean, boolean, UserHandle, Context)
*/
- default void revoke(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {}
+ default void revokeAsUser(@NonNull Role role, @NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {}
/**
* @see Role#onHolderSelectedAsUser(String, UserHandle, Context)
@@ -108,4 +113,34 @@ public interface RoleBehavior {
*/
default void onHolderChangedAsUser(@NonNull Role role, @NonNull UserHandle user,
@NonNull Context context) {}
+
+ /**
+ * Check whether this role should be visible to user.
+ *
+ * @param role the role to check for
+ * @param user the user to check for
+ * @param context the `Context` to retrieve system services
+ *
+ * @return whether this role should be visible to user
+ */
+ default boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return true;
+ }
+
+ /**
+ * Check whether a qualifying application should be visible to user.
+ *
+ * @param role the role to check for
+ * @param applicationInfo the {@link ApplicationInfo} for the application
+ * @param user the user for the application
+ * @param context the {@code Context} to retrieve system services
+ *
+ * @return whether the qualifying application should be visible to user
+ */
+ default boolean isApplicationVisibleAsUser(@NonNull Role role,
+ @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return true;
+ }
}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java b/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java
index 23299419e..bd530d09d 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java
@@ -21,8 +21,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
+import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Build;
+import android.permission.flags.Flags;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -31,7 +33,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
import com.android.role.controller.behavior.BrowserRoleBehavior;
+import com.android.role.controller.util.ResourceUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -88,6 +92,7 @@ public class RoleParser {
private static final String ATTRIBUTE_LABEL = "label";
private static final String ATTRIBUTE_MAX_SDK_VERSION = "maxSdkVersion";
private static final String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion";
+ private static final String ATTRIBUTE_ONLY_GRANT_WHEN_ADDED = "onlyGrantWhenAdded";
private static final String ATTRIBUTE_OVERRIDE_USER_WHEN_GRANTING = "overrideUserWhenGranting";
private static final String ATTRIBUTE_QUERY_FLAGS = "queryFlags";
private static final String ATTRIBUTE_REQUEST_TITLE = "requestTitle";
@@ -149,7 +154,7 @@ public class RoleParser {
*/
@NonNull
public ArrayMap<String, Role> parse() {
- try (XmlResourceParser parser = sGetRolesXml.apply(mContext)) {
+ try (XmlResourceParser parser = getRolesXml()) {
Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> xml = parseXml(parser);
if (xml == null) {
return new ArrayMap<>();
@@ -164,6 +169,20 @@ public class RoleParser {
}
}
+ /**
+ * Retrieves the roles.xml resource from a context
+ */
+ private XmlResourceParser getRolesXml() {
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ Resources resources = ResourceUtils.getPermissionControllerResources(mContext);
+ int resourceId = resources.getIdentifier("roles", "xml",
+ ResourceUtils.RESOURCE_PACKAGE_NAME_PERMISSION_CONTROLLER);
+ return resources.getXml(resourceId);
+ } else {
+ return sGetRolesXml.apply(mContext);
+ }
+ }
+
@Nullable
private Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> parseXml(
@NonNull XmlResourceParser parser) throws IOException, XmlPullParserException {
@@ -252,6 +271,9 @@ public class RoleParser {
return null;
}
+ int minSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MIN_SDK_VERSION,
+ Build.VERSION_CODES.BASE);
+
List<Permission> permissions = new ArrayList<>();
int type;
@@ -269,6 +291,8 @@ public class RoleParser {
if (permission == null) {
continue;
}
+ int mergedMinSdkVersion = Math.max(permission.getMinSdkVersion(), minSdkVersion);
+ permission = permission.withMinSdkVersion(mergedMinSdkVersion);
validateNoDuplicateElement(permission, permissions, "permission");
permissions.add(permission);
} else {
@@ -373,6 +397,9 @@ public class RoleParser {
return null;
}
+ boolean onlyGrantWhenAdded = getAttributeBooleanValue(parser,
+ ATTRIBUTE_ONLY_GRANT_WHEN_ADDED, false);
+
boolean overrideUserWhenGranting = getAttributeBooleanValue(parser,
ATTRIBUTE_OVERRIDE_USER_WHEN_GRANTING, false);
@@ -500,10 +527,11 @@ public class RoleParser {
}
return new Role(name, allowBypassingQualification, behavior, defaultHoldersResourceName,
descriptionResource, exclusive, fallBackToDefaultHolder, labelResource,
- maxSdkVersion, minSdkVersion, overrideUserWhenGranting, requestDescriptionResource,
- requestTitleResource, requestable, searchKeywordsResource, shortLabelResource,
- showNone, statik, systemOnly, visible, requiredComponents, permissions,
- appOpPermissions, appOps, preferredActivities, uiBehaviorName);
+ maxSdkVersion, minSdkVersion, onlyGrantWhenAdded, overrideUserWhenGranting,
+ requestDescriptionResource, requestTitleResource, requestable,
+ searchKeywordsResource, shortLabelResource, showNone, statik, systemOnly, visible,
+ requiredComponents, permissions, appOpPermissions, appOps, preferredActivities,
+ uiBehaviorName);
}
@NonNull
@@ -738,13 +766,24 @@ public class RoleParser {
if (permissionSetName == null) {
continue;
}
- if (!permissionSets.containsKey(permissionSetName)) {
+ PermissionSet permissionSet = permissionSets.get(permissionSetName);
+ if (permissionSet == null) {
throwOrLogMessage("Unknown permission set:" + permissionSetName);
continue;
}
- PermissionSet permissionSet = permissionSets.get(permissionSetName);
- // We do allow intersection between permission sets.
- permissions.addAll(permissionSet.getPermissions());
+ int minSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MIN_SDK_VERSION,
+ Build.VERSION_CODES.BASE);
+ List<Permission> permissionsInSet = permissionSet.getPermissions();
+ int permissionsInSetSize = permissionsInSet.size();
+ for (int permissionsInSetIndex = 0;
+ permissionsInSetIndex < permissionsInSetSize; permissionsInSetIndex++) {
+ Permission permission = permissionsInSet.get(permissionsInSetIndex);
+ int mergedMinSdkVersion =
+ Math.max(permission.getMinSdkVersion(), minSdkVersion);
+ permission = permission.withMinSdkVersion(mergedMinSdkVersion);
+ // We do allow intersection between permission sets.
+ permissions.add(permission);
+ }
break;
}
case TAG_PERMISSION: {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/VisibilityMixin.java b/PermissionController/role-controller/java/com/android/role/controller/model/VisibilityMixin.java
index 90cda72ca..fdfb45143 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/VisibilityMixin.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/VisibilityMixin.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.Context;
import android.content.res.Resources;
@@ -23,8 +23,7 @@ import android.util.Log;
import androidx.annotation.NonNull;
-import com.android.role.controller.model.Role;
-import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.ResourceUtils;
/**
* Mixin for {@link RoleBehavior#isVisibleAsUser(Role, UserHandle, Context)} that returns whether
@@ -37,11 +36,26 @@ public class VisibilityMixin {
private VisibilityMixin() {}
/**
- * @see Role#isVisibleAsUser(UserHandle, Context)
+ * Get the boolean resource value that represents whether a role is visible to the user.
+ *
+ * @param resourceName the name of the resource
+ * @param isPermissionControllerResource if {@code true}, and if the current SDK level is at
+ * least V, get the resource from a PermissionController context for the given user.
+ * Otherwise, get the resource the provided context.
+ * @param user the user to get the PermissionController context for
+ * @param context the `Context` to retrieve the resource (and system services)
+ *
+ * @return whether this role should be visible to user
*/
- public static boolean isVisible(@NonNull String resourceName, @NonNull Context context) {
- Resources resources = context.getResources();
- int resourceId = resources.getIdentifier(resourceName, "bool", "android");
+ public static boolean isVisible(@NonNull String resourceName,
+ boolean isPermissionControllerResource, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Resources resources = isPermissionControllerResource
+ ? ResourceUtils.getPermissionControllerResources(context) : context.getResources();
+ String packageName = isPermissionControllerResource
+ ? ResourceUtils.RESOURCE_PACKAGE_NAME_PERMISSION_CONTROLLER : "android";
+
+ int resourceId = resources.getIdentifier(resourceName, "bool", packageName);
if (resourceId == 0) {
Log.w(LOG_TAG, "Cannot find resource for visibility: " + resourceName);
return true;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java
index c1c7da46a..bc7562c11 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.service;
+package com.android.role.controller.service;
import android.app.role.RoleControllerService;
import android.app.role.RoleManager;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Process;
import android.os.UserHandle;
@@ -28,11 +29,12 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
-import com.android.permissioncontroller.permission.utils.CollectionUtils;
-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.role.controller.util.CollectionUtils;
+import com.android.role.controller.util.LegacyRoleFallbackEnabledUtils;
+import com.android.role.controller.util.PackageUtils;
+import com.android.role.controller.util.UserUtils;
import java.util.ArrayList;
import java.util.List;
@@ -47,24 +49,40 @@ public class RoleControllerServiceImpl extends RoleControllerService {
private static final boolean DEBUG = false;
- private RoleManager mRoleManager;
+
+ private UserHandle mUser;
+ private Context mContext;
+ private RoleManager mUserRoleManager;
+
+ public RoleControllerServiceImpl() {}
+
+ public RoleControllerServiceImpl(@NonNull UserHandle user, @NonNull Context context) {
+ init(user, context);
+ }
@Override
public void onCreate() {
super.onCreate();
- mRoleManager = getSystemService(RoleManager.class);
+ init(Process.myUserHandle(), this);
+ }
+
+ private void init(@NonNull UserHandle user, @NonNull Context context) {
+ mUser = user;
+ mContext = context;
+ Context userContext = UserUtils.getUserContext(context, user);
+ mUserRoleManager = userContext.getSystemService(RoleManager.class);
}
@Override
@WorkerThread
public boolean onGrantDefaultRoles() {
if (DEBUG) {
- Log.i(LOG_TAG, "Granting default roles, user: " + UserHandle.myUserId());
+ Log.i(LOG_TAG, "Granting default roles, user: " + mUser.myUserId());
}
// Gather the available roles for current user.
- ArrayMap<String, Role> roleMap = Roles.get(this);
+ ArrayMap<String, Role> roleMap = Roles.get(mContext);
List<Role> roles = new ArrayList<>();
List<String> roleNames = new ArrayList<>();
ArraySet<String> addedRoleNames = new ArraySet<>();
@@ -72,13 +90,13 @@ public class RoleControllerServiceImpl extends RoleControllerService {
for (int i = 0; i < roleMapSize; i++) {
Role role = roleMap.valueAt(i);
- if (!role.isAvailable(this)) {
+ if (!role.isAvailableAsUser(mUser, mContext)) {
continue;
}
roles.add(role);
String roleName = role.getName();
roleNames.add(roleName);
- if (!mRoleManager.isRoleAvailable(roleName)) {
+ if (!mUserRoleManager.isRoleAvailable(roleName)) {
addedRoleNames.add(roleName);
}
}
@@ -86,14 +104,14 @@ public class RoleControllerServiceImpl extends RoleControllerService {
// TODO: Clean up holders of roles that will be removed.
// Set the available role names in RoleManager.
- mRoleManager.setRoleNamesFromController(roleNames);
+ mUserRoleManager.setRoleNamesFromController(roleNames);
int addedRoleNamesSize = addedRoleNames.size();
for (int i = 0; i < addedRoleNamesSize; i++) {
String roleName = addedRoleNames.valueAt(i);
Role role = roleMap.get(roleName);
- role.onRoleAdded(this);
+ role.onRoleAddedAsUser(mUser, mContext);
}
// Go through the holders of all roles.
@@ -105,18 +123,20 @@ public class RoleControllerServiceImpl extends RoleControllerService {
// For each of the current holders, check if it is still qualified, redo grant if so, or
// remove it otherwise.
- List<String> currentPackageNames = mRoleManager.getRoleHolders(roleName);
+ List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName);
int currentPackageNamesSize = currentPackageNames.size();
for (int currentPackageNamesIndex = 0;
currentPackageNamesIndex < currentPackageNamesSize;
currentPackageNamesIndex++) {
String packageName = currentPackageNames.get(currentPackageNamesIndex);
- if (role.isPackageQualified(packageName, this)) {
- // We should not override user set or fixed permissions because we are only
- // redoing the grant here. Otherwise, user won't be able to revoke permissions
- // granted by role.
- addRoleHolderInternal(role, packageName, false, false, true);
+ if (role.isPackageQualifiedAsUser(packageName, mUser, mContext)) {
+ if (!role.shouldOnlyGrantWhenAdded()) {
+ // We should not override user set or fixed permissions because we are only
+ // redoing the grant here. Otherwise, user won't be able to revoke
+ // permissions granted by role.
+ addRoleHolderInternal(role, packageName, false, false, true);
+ }
} else {
Log.i(LOG_TAG, "Removing package that no longer qualifies for the role,"
+ " package: " + packageName + ", role: " + roleName);
@@ -126,17 +146,17 @@ public class RoleControllerServiceImpl extends RoleControllerService {
// If there is no holder for a role now, or the role is static, we need to add default
// or fallback holders, if any.
- currentPackageNames = mRoleManager.getRoleHolders(roleName);
+ currentPackageNames = mUserRoleManager.getRoleHolders(roleName);
currentPackageNamesSize = currentPackageNames.size();
boolean isStaticRole = role.isStatic();
if (currentPackageNamesSize == 0 || isStaticRole) {
List<String> packageNamesToAdd = null;
if (addedRoleNames.contains(roleName) || isStaticRole) {
- packageNamesToAdd = role.getDefaultHolders(this);
+ packageNamesToAdd = role.getDefaultHoldersAsUser(mUser, mContext);
}
if (packageNamesToAdd == null || packageNamesToAdd.isEmpty()) {
- packageNamesToAdd = CollectionUtils.singletonOrEmpty(role.getFallbackHolder(
- this));
+ packageNamesToAdd = CollectionUtils.singletonOrEmpty(
+ role.getFallbackHolderAsUser(mUser, mContext));
}
int packageNamesToAddSize = packageNamesToAdd.size();
@@ -149,7 +169,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {
// static roles.
continue;
}
- if (!role.isPackageQualified(packageName, this)) {
+ if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) {
Log.e(LOG_TAG, "Default/fallback role holder package doesn't qualify for"
+ " the role, package: " + packageName + ", role: " + roleName);
continue;
@@ -165,7 +185,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {
}
// Ensure that an exclusive role has at most one holder.
- currentPackageNames = mRoleManager.getRoleHolders(roleName);
+ currentPackageNames = mUserRoleManager.getRoleHolders(roleName);
currentPackageNamesSize = currentPackageNames.size();
if (role.isExclusive() && currentPackageNamesSize > 1) {
Log.w(LOG_TAG, "Multiple packages holding an exclusive role, role: "
@@ -194,17 +214,17 @@ public class RoleControllerServiceImpl extends RoleControllerService {
return false;
}
- Role role = Roles.get(this).get(roleName);
+ Role role = Roles.get(mContext).get(roleName);
if (role == null) {
Log.e(LOG_TAG, "Unknown role: " + roleName);
return false;
}
- if (!role.isAvailable(this)) {
+ if (!role.isAvailableAsUser(mUser, mContext)) {
Log.e(LOG_TAG, "Role is unavailable: " + roleName);
return false;
}
- if (!role.isPackageQualified(packageName, this)) {
+ if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) {
Log.e(LOG_TAG, "Package does not qualify for the role, package: " + packageName
+ ", role: " + roleName);
return false;
@@ -212,7 +232,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {
boolean added = false;
if (role.isExclusive()) {
- List<String> currentPackageNames = mRoleManager.getRoleHolders(roleName);
+ List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName);
int currentPackageNamesSize = currentPackageNames.size();
for (int i = 0; i < currentPackageNamesSize; i++) {
String currentPackageName = currentPackageNames.get(i);
@@ -239,8 +259,8 @@ public class RoleControllerServiceImpl extends RoleControllerService {
return false;
}
- role.onHolderAddedAsUser(packageName, Process.myUserHandle(), this);
- role.onHolderChangedAsUser(Process.myUserHandle(), this);
+ role.onHolderAddedAsUser(packageName, mUser, mContext);
+ role.onHolderChangedAsUser(mUser, mContext);
return true;
}
@@ -253,12 +273,12 @@ public class RoleControllerServiceImpl extends RoleControllerService {
return false;
}
- Role role = Roles.get(this).get(roleName);
+ Role role = Roles.get(mContext).get(roleName);
if (role == null) {
Log.e(LOG_TAG, "Unknown role: " + roleName);
return false;
}
- if (!role.isAvailable(this)) {
+ if (!role.isAvailableAsUser(mUser, mContext)) {
Log.e(LOG_TAG, "Role is unavailable: " + roleName);
return false;
}
@@ -275,7 +295,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {
return false;
}
- role.onHolderChangedAsUser(Process.myUserHandle(), this);
+ role.onHolderChangedAsUser(mUser, mContext);
return true;
}
@@ -287,12 +307,12 @@ public class RoleControllerServiceImpl extends RoleControllerService {
return false;
}
- Role role = Roles.get(this).get(roleName);
+ Role role = Roles.get(mContext).get(roleName);
if (role == null) {
Log.e(LOG_TAG, "Unknown role: " + roleName);
return false;
}
- if (!role.isAvailable(this)) {
+ if (!role.isAvailableAsUser(mUser, mContext)) {
Log.e(LOG_TAG, "Role is unavailable: " + roleName);
return false;
}
@@ -309,7 +329,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {
return false;
}
- role.onHolderChangedAsUser(Process.myUserHandle(), this);
+ role.onHolderChangedAsUser(mUser, mContext);
return true;
}
@@ -323,11 +343,11 @@ public class RoleControllerServiceImpl extends RoleControllerService {
@WorkerThread
private boolean addRoleHolderInternal(@NonNull Role role, @NonNull String packageName,
boolean dontKillApp, boolean overrideUser, boolean added) {
- role.grant(packageName, dontKillApp, overrideUser, this);
+ role.grantAsUser(packageName, dontKillApp, overrideUser, mUser, mContext);
String roleName = role.getName();
if (!added) {
- added = mRoleManager.addRoleHolderFromController(roleName, packageName);
+ added = mUserRoleManager.addRoleHolderFromController(roleName, packageName);
}
if (!added) {
Log.e(LOG_TAG, "Failed to add role holder in RoleManager, package: " + packageName
@@ -339,17 +359,18 @@ public class RoleControllerServiceImpl extends RoleControllerService {
@WorkerThread
private boolean removeRoleHolderInternal(@NonNull Role role, @NonNull String packageName,
boolean dontKillApp) {
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, this);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ mUser, mContext);
if (applicationInfo == null) {
Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName);
}
if (applicationInfo != null) {
- role.revoke(packageName, dontKillApp, false, this);
+ role.revokeAsUser(packageName, dontKillApp, false, mUser, mContext);
}
String roleName = role.getName();
- boolean removed = mRoleManager.removeRoleHolderFromController(roleName, packageName);
+ boolean removed = mUserRoleManager.removeRoleHolderFromController(roleName, packageName);
if (!removed) {
Log.e(LOG_TAG, "Failed to remove role holder in RoleManager," + " package: "
+ packageName + ", role: " + roleName);
@@ -360,7 +381,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {
@WorkerThread
private boolean clearRoleHoldersInternal(@NonNull Role role, boolean dontKillApp) {
String roleName = role.getName();
- List<String> packageNames = mRoleManager.getRoleHolders(roleName);
+ List<String> packageNames = mUserRoleManager.getRoleHolders(roleName);
boolean cleared = true;
int packageNamesSize = packageNames.size();
@@ -381,17 +402,17 @@ public class RoleControllerServiceImpl extends RoleControllerService {
@WorkerThread
private boolean addFallbackRoleHolderMaybe(@NonNull Role role) {
String roleName = role.getName();
- List<String> currentPackageNames = mRoleManager.getRoleHolders(roleName);
+ List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName);
if (!currentPackageNames.isEmpty()) {
return true;
}
- String fallbackPackageName = role.getFallbackHolder(this);
+ String fallbackPackageName = role.getFallbackHolderAsUser(mUser, mContext);
if (fallbackPackageName == null) {
return true;
}
- if (!role.isPackageQualified(fallbackPackageName, this)) {
+ if (!role.isPackageQualifiedAsUser(fallbackPackageName, mUser, mContext)) {
Log.e(LOG_TAG, "Fallback role holder package doesn't qualify for the role, package: "
+ fallbackPackageName + ", role: " + roleName);
return false;
@@ -418,19 +439,20 @@ public class RoleControllerServiceImpl extends RoleControllerService {
@Override
public boolean onIsApplicationVisibleForRole(@NonNull String roleName,
@NonNull String packageName) {
- Role role = Roles.get(this).get(roleName);
+ Role role = Roles.get(mContext).get(roleName);
if (role == null) {
return false;
}
- if (!role.isAvailable(this)) {
+ if (!role.isAvailableAsUser(mUser, mContext)) {
return false;
}
- if (!role.isPackageQualified(packageName, this)) {
+ if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) {
return false;
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, this);
- if (applicationInfo == null || !RoleUiBehaviorUtils.isApplicationVisibleAsUser(role,
- applicationInfo, Process.myUserHandle(), this)) {
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ mUser, mContext);
+ if (applicationInfo == null || !role.isApplicationVisibleAsUser(applicationInfo, mUser,
+ mContext)) {
return false;
}
return true;
@@ -438,17 +460,24 @@ public class RoleControllerServiceImpl extends RoleControllerService {
@Override
public boolean onIsRoleVisible(@NonNull String roleName) {
- Role role = Roles.get(this).get(roleName);
+ Role role = Roles.get(mContext).get(roleName);
if (role == null) {
return false;
}
- if (!role.isAvailable(this)) {
+ if (!role.isAvailableAsUser(mUser, mContext)) {
return false;
}
- return RoleUiBehaviorUtils.isVisibleAsUser(role, Process.myUserHandle(), this);
+ return role.isVisibleAsUser(mUser, mContext);
}
+ @Override
+ @NonNull
+ public List<String> onGetLegacyFallbackDisabledRoles() {
+ return LegacyRoleFallbackEnabledUtils.getFallbackDisabledRoles(mUser, mContext);
+ }
+
+
private static boolean checkFlags(int flags, int allowedFlags) {
if ((flags & allowedFlags) != flags) {
Log.e(LOG_TAG, "flags is invalid, flags: 0x" + Integer.toHexString(flags)
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java
new file mode 100644
index 000000000..5be10a26a
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 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.role.controller.util;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LegacyRoleFallbackEnabledUtils {
+ /**
+ * Name of generic shared preferences file.
+ */
+ private static final String PREFERENCES_FILE = "preferences";
+
+ /**
+ * Key in the generic shared preferences that stores if the user manually selected the "none"
+ * role holder for a role.
+ */
+ private static final String IS_NONE_ROLE_HOLDER_SELECTED_KEY = "is_none_role_holder_selected:";
+
+ /**
+ * Get a device protected storage based shared preferences. Avoid storing sensitive data in it.
+ *
+ * @param context the context to get the shared preferences
+ * @return a device protected storage based shared preferences
+ */
+ @NonNull
+ @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static SharedPreferences getSharedPreferences(@NonNull UserHandle user,
+ @NonNull Context context) {
+ String packageName = context.getPackageManager().getPermissionControllerPackageName();
+ try {
+ context = context.createPackageContextAsUser(packageName, 0, user);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ if (!context.isDeviceProtectedStorage()) {
+ context = context.createDeviceProtectedStorageContext();
+ }
+ return context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Get all role names with fallback disabled, which means their "none" are set to true.
+ *
+ * @return A list of role names with fallback disabled.
+ */
+ public static List<String> getFallbackDisabledRoles(@NonNull UserHandle user,
+ @NonNull Context context) {
+ List<String> fallbackDisabledRoles = new ArrayList<>();
+ SharedPreferences sharedPreferences = getSharedPreferences(user, context);
+ for (String key : sharedPreferences.getAll().keySet()) {
+ if (key.startsWith(IS_NONE_ROLE_HOLDER_SELECTED_KEY)
+ && sharedPreferences.getBoolean(key, false)) {
+ String roleName = key.substring(IS_NONE_ROLE_HOLDER_SELECTED_KEY.length());
+ fallbackDisabledRoles.add(roleName);
+ }
+ }
+ return fallbackDisabledRoles;
+ }
+
+ /**
+ * Check whether the role has the fallback holder enabled.
+ *
+ * @return whether the "none" role holder is not selected
+ */
+ public static boolean isRoleFallbackEnabledAsUser(@NonNull String roleName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return !getSharedPreferences(user, context)
+ .getBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + roleName, false);
+ }
+
+ /**
+ * Set whether the role has fallback holder enabled.
+ */
+ public static void setRoleFallbackEnabledAsUser(@NonNull String roleName,
+ boolean fallbackEnabled, @NonNull UserHandle user, @NonNull Context context) {
+ String key = IS_NONE_ROLE_HOLDER_SELECTED_KEY + roleName;
+ if (fallbackEnabled) {
+ getSharedPreferences(user, context).edit().remove(key).apply();
+ } else {
+ getSharedPreferences(user, context).edit().putBoolean(key, true).apply();
+ }
+ }
+}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java
index 3b11d7d92..365c3b491 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.util.Log;
@@ -44,41 +45,45 @@ public final class NotificationUtils {
/**
* Grants the NotificationListener access.
*
- * @param context the {@code Context} to retrieve system services
* @param packageName the package name implements the NotificationListener
+ * @param user the user of the component
+ * @param context the {@code Context} to retrieve system services
*/
- public static void grantNotificationAccessForPackage(@NonNull Context context,
- @NonNull String packageName) {
- setNotificationGrantStateForPackage(context, packageName, true);
+ public static void grantNotificationAccessForPackageAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ setNotificationGrantStateForPackageAsUser(packageName, true, user, context);
}
/**
* Revokes the NotificationListener access.
*
- * @param context the {@code Context} to retrieve system services
* @param packageName the package name implements the NotificationListener
+ * @param user the user of the component
+ * @param context the {@code Context} to retrieve system services
*/
- public static void revokeNotificationAccessForPackage(@NonNull Context context,
- @NonNull String packageName) {
- setNotificationGrantStateForPackage(context, packageName, false);
+ public static void revokeNotificationAccessForPackageAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ setNotificationGrantStateForPackageAsUser(packageName, false, user, context);
}
- private static void setNotificationGrantStateForPackage(@NonNull Context context,
- @NonNull String packageName, boolean granted) {
+ private static void setNotificationGrantStateForPackageAsUser(@NonNull String packageName,
+ boolean granted, @NonNull UserHandle user, @NonNull Context context) {
List<ComponentName> notificationListenersForPackage =
- getNotificationListenersForPackage(packageName, context);
- NotificationManager notificationManager =
- context.getSystemService(NotificationManager.class);
+ getNotificationListenersForPackageAsUser(packageName, user, context);
+ Context userContext = UserUtils.getUserContext(context, user);
+ NotificationManager userNotificationManager =
+ userContext.getSystemService(NotificationManager.class);
for (ComponentName componentName : notificationListenersForPackage) {
- notificationManager.setNotificationListenerAccessGranted(
+ userNotificationManager.setNotificationListenerAccessGranted(
componentName, granted, false);
}
}
- private static List<ComponentName> getNotificationListenersForPackage(
- @NonNull String packageName, @NonNull Context context) {
- List<ResolveInfo> allListeners = context.getPackageManager().queryIntentServices(
+ private static List<ComponentName> getNotificationListenersForPackageAsUser(
+ @NonNull String packageName, @NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ List<ResolveInfo> allListeners = userContext.getPackageManager().queryIntentServices(
new Intent(NotificationListenerService.SERVICE_INTERFACE).setPackage(packageName),
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
ArrayList<ComponentName> pkgListeners = new ArrayList<>();
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java
index 4b127ad10..cbffd451a 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java
@@ -36,19 +36,21 @@ public final class PackageUtils {
* Retrieve the {@link PackageInfo} of an application.
*
* @param packageName the package name of the application
- * @param extraFlags the extra flags to pass to {@link PackageManager#getPackageInfo(String,
- * int)}
- * @param context the {@code Context} to retrieve system services
- *
+ * @param extraFlags the extra flags to pass to {@link PackageManager#getPackageInfo(String,
+ * int)}
+ * @param user the user of the application
+ * @param context the {@code Context} to retrieve system services
* @return the {@link PackageInfo} of the application, or {@code null} if not found
*/
@Nullable
- public static PackageInfo getPackageInfo(@NonNull String packageName, int extraFlags,
- @NonNull Context context) {
- PackageManager packageManager = context.getPackageManager();
+ public static PackageInfo getPackageInfoAsUser(@NonNull String packageName, int extraFlags,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
try {
- return packageManager.getPackageInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | extraFlags);
+ return userPackageManager.getPackageInfo(packageName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | extraFlags);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
@@ -58,12 +60,15 @@ public final class PackageUtils {
* Retrieve if a package is a system package.
*
* @param packageName the name of the package
+ * @param user the user of the package
* @param context the {@code Context} to retrieve system services
*
* @return whether the package is a system package
*/
- public static boolean isSystemPackage(@NonNull String packageName, @NonNull Context context) {
- return getPackageInfo(packageName, PackageManager.MATCH_SYSTEM_ONLY, context) != null;
+ public static boolean isSystemPackageAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return getPackageInfoAsUser(packageName, PackageManager.MATCH_SYSTEM_ONLY, user, context)
+ != null;
}
/**
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/ResourceUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/ResourceUtils.java
new file mode 100644
index 000000000..f8f12108a
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/ResourceUtils.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 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.role.controller.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.permission.flags.Flags;
+
+import androidx.annotation.NonNull;
+
+import com.android.modules.utils.build.SdkLevel;
+
+public class ResourceUtils {
+
+ private ResourceUtils() {}
+
+ public static String RESOURCE_PACKAGE_NAME_PERMISSION_CONTROLLER =
+ "com.android.permissioncontroller";
+
+ /**
+ * Get a {@link Resources} object to be used to access PermissionController resources.
+ */
+ @NonNull
+ public static Resources getPermissionControllerResources(@NonNull Context context) {
+ return getPermissionControllerContext(context).getResources();
+ }
+
+ @NonNull
+ private static Context getPermissionControllerContext(@NonNull Context context) {
+ if (!SdkLevel.isAtLeastV() || !Flags.systemServerRoleControllerEnabled()) {
+ // We don't have the getPermissionControllerPackageName() API below V,
+ // but role controller always runs in PermissionController below V.
+ return context;
+ }
+ String packageName = context.getPackageManager().getPermissionControllerPackageName();
+ try {
+ return context.createPackageContext(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException("Cannot create PermissionController context", e);
+ }
+ }
+}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java b/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java
index 8a6fd579c..ec63528d1 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java
@@ -18,8 +18,8 @@ package com.android.role.controller.util;
import android.app.role.RoleManager;
import android.content.Context;
-import android.content.SharedPreferences;
import android.os.UserHandle;
+import android.permission.flags.Flags;
import androidx.annotation.NonNull;
@@ -31,16 +31,7 @@ import com.android.role.controller.model.Role;
*/
public class RoleManagerCompat {
- /**
- * Key in the generic shared preferences that stores if the user manually selected the "none"
- * role holder for a role.
- */
- private static final String IS_NONE_ROLE_HOLDER_SELECTED_KEY = "is_none_role_holder_selected:";
- /**
- * Name of generic shared preferences file.
- */
- private static final String PREFERENCES_FILE = "preferences";
private RoleManagerCompat() {}
@@ -56,47 +47,34 @@ public class RoleManagerCompat {
}
/**
- * Get a device protected storage based shared preferences. Avoid storing sensitive data in it.
- *
- * @param context the context to get the shared preferences
- * @return a device protected storage based shared preferences
- */
- @NonNull
- private static SharedPreferences getDeviceProtectedSharedPreferences(@NonNull Context context) {
- if (!context.isDeviceProtectedStorage()) {
- context = context.createDeviceProtectedStorageContext();
- }
- return context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
- }
-
- /**
* Check whether the role has the fallback holder enabled.
*
* @return whether the "none" role holder is not selected
*/
public static boolean isRoleFallbackEnabledAsUser(@NonNull Role role, @NonNull UserHandle user,
@NonNull Context context) {
- Context userContext = UserUtils.getUserContext(context, user);
- boolean isNoneHolderSelected = getDeviceProtectedSharedPreferences(userContext)
- .getBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName(), false);
- return !isNoneHolderSelected;
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ RoleManager userRoleManager = userContext.getSystemService(RoleManager.class);
+ return userRoleManager.isRoleFallbackEnabled(role.getName());
+ } else {
+ return LegacyRoleFallbackEnabledUtils.isRoleFallbackEnabledAsUser(role.getName(), user,
+ context);
+ }
}
/**
* Set whether the role has fallback holder enabled.
- *
*/
public static void setRoleFallbackEnabledAsUser(@NonNull Role role,
boolean fallbackEnabled, @NonNull UserHandle user, @NonNull Context context) {
- Context userContext = UserUtils.getUserContext(context, user);
- if (fallbackEnabled) {
- getDeviceProtectedSharedPreferences(userContext).edit()
- .remove(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName())
- .apply();
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ RoleManager userRoleManager = userContext.getSystemService(RoleManager.class);
+ userRoleManager.setRoleFallbackEnabled(role.getName(), fallbackEnabled);
} else {
- getDeviceProtectedSharedPreferences(userContext).edit()
- .putBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName(), true)
- .apply();
+ LegacyRoleFallbackEnabledUtils.setRoleFallbackEnabledAsUser(role.getName(),
+ fallbackEnabled, user, context);
}
}
}
diff --git a/PermissionController/role-controller/lint-baseline.xml b/PermissionController/role-controller/lint-baseline.xml
index e7c119f3b..894dc1834 100644
--- a/PermissionController/role-controller/lint-baseline.xml
+++ b/PermissionController/role-controller/lint-baseline.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
message="Call requires API level 31 (current min is 30): `android.app.NotificationManager#setNotificationListenerAccessGranted`"
- errorLine1=" notificationManager.setNotificationListenerAccessGranted("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ errorLine1=" userNotificationManager.setNotificationListenerAccessGranted("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/modules/Permission/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java"
- line="74"
- column="33"/>
+ line="78"
+ column="37"/>
</issue>
</issues> \ No newline at end of file
diff --git a/PermissionController/src/com/android/permissioncontroller/Constants.java b/PermissionController/src/com/android/permissioncontroller/Constants.java
index 58b62dc54..a063fb607 100644
--- a/PermissionController/src/com/android/permissioncontroller/Constants.java
+++ b/PermissionController/src/com/android/permissioncontroller/Constants.java
@@ -320,6 +320,17 @@ public class Constants {
*/
public static final String UNUSED_APPS_SAFETY_CENTER_SEE_UNUSED_APPS_ID = "see_unused_apps";
+ /**
+ * Fallback Settings package name
+ */
+ public static final String SETTINGS_PACKAGE_NAME_FALLBACK = "com.android.settings";
+
+ /**
+ * Extra launcher icon for notification
+ */
+ public static final String NOTIFICATION_EXTRA_USE_LAUNCHER_ICON =
+ "com.android.car.notification.EXTRA_USE_LAUNCHER_ICON";
+
// TODO(b/231624295) add to API
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO =
diff --git a/PermissionController/src/com/android/permissioncontroller/DumpableLog.kt b/PermissionController/src/com/android/permissioncontroller/DumpableLog.kt
index bbce5bf5c..56682d018 100644
--- a/PermissionController/src/com/android/permissioncontroller/DumpableLog.kt
+++ b/PermissionController/src/com/android/permissioncontroller/DumpableLog.kt
@@ -20,9 +20,7 @@ import android.util.Log
import com.android.permissioncontroller.Constants.LOGS_TO_DUMP_FILE
import java.io.File
-/**
- * Like {@link Log} but stores the logs in a file which can later be dumped via {@link #dump}
- */
+/** Like {@link Log} but stores the logs in a file which can later be dumped via {@link #dump} */
object DumpableLog {
private const val MAX_FILE_SIZE = 64 * 1024
@@ -33,41 +31,31 @@ object DumpableLog {
file.createNewFile()
}
- /**
- * Equivalent to {@link Log.v}
- */
+ /** Equivalent to {@link Log.v} */
fun v(tag: String, message: String, exception: Throwable? = null) {
Log.v(tag, message, exception)
addLogToDump("v", tag, message, exception)
}
- /**
- * Equivalent to {@link Log.d}
- */
+ /** Equivalent to {@link Log.d} */
fun d(tag: String, message: String, exception: Throwable? = null) {
Log.d(tag, message, exception)
addLogToDump("d", tag, message, exception)
}
- /**
- * Equivalent to {@link Log.i}
- */
+ /** Equivalent to {@link Log.i} */
fun i(tag: String, message: String, exception: Throwable? = null) {
Log.i(tag, message, exception)
addLogToDump("i", tag, message, exception)
}
- /**
- * Equivalent to {@link Log.w}
- */
+ /** Equivalent to {@link Log.w} */
fun w(tag: String, message: String, exception: Throwable? = null) {
Log.w(tag, message, exception)
addLogToDump("w", tag, message, exception)
}
- /**
- * Equivalent to {@link Log.e}
- */
+ /** Equivalent to {@link Log.e} */
fun e(tag: String, message: String, exception: Throwable? = null) {
Log.e(tag, message, exception)
addLogToDump("e", tag, message, exception)
@@ -83,17 +71,17 @@ object DumpableLog {
dump.subList(dump.size / 2, dump.size).forEach { file.appendText(it + "\n") }
}
- file.appendText("${System.currentTimeMillis()} $tag:$level $message " +
- "${exception?.let { it.message + Log.getStackTraceString(it) } ?: ""}\n")
+ file.appendText(
+ "${System.currentTimeMillis()} $tag:$level $message " +
+ "${exception?.let { it.message + Log.getStackTraceString(it) } ?: ""}\n"
+ )
}
}
- /**
- * @return the previously logged entries
- */
+ /** @return the previously logged entries */
suspend fun get(): List<String> {
synchronized(lock) {
return file.readLines()
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java b/PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java
index 68495ce1e..50da28149 100644
--- a/PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java
+++ b/PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java
@@ -21,6 +21,7 @@ import android.content.ComponentName;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.Process;
import android.util.ArrayMap;
import android.view.accessibility.AccessibilityManager;
@@ -32,7 +33,6 @@ import com.android.permissioncontroller.permission.utils.Utils;
import com.android.permissioncontroller.privacysources.SafetyCenterAccessibilityListener;
import com.android.permissioncontroller.role.model.RoleParserInitializer;
import com.android.permissioncontroller.role.ui.SpecialAppAccessListActivity;
-import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.Roles;
@@ -71,7 +71,8 @@ public final class PermissionControllerApplication extends Application {
for (int i = 0; i < rolesSize; i++) {
Role role = roles.valueAt(i);
- if (!role.isAvailable(this) || !RoleUiBehaviorUtils.isVisible(role, this)) {
+ if (!role.isAvailableAsUser(Process.myUserHandle(), this)
+ || !role.isVisibleAsUser(Process.myUserHandle(), this)) {
continue;
}
if (!role.isExclusive()) {
diff --git a/PermissionController/src/com/android/permissioncontroller/auto/AutoSettingsFrameFragment.java b/PermissionController/src/com/android/permissioncontroller/auto/AutoSettingsFrameFragment.java
index 3b0e89b04..08e1b3560 100644
--- a/PermissionController/src/com/android/permissioncontroller/auto/AutoSettingsFrameFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/auto/AutoSettingsFrameFragment.java
@@ -27,6 +27,9 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.car.ui.FocusArea;
+import com.android.car.ui.R;
+import com.android.car.ui.baselayout.Insets;
import com.android.car.ui.preference.PreferenceFragment;
import com.android.car.ui.toolbar.MenuItem;
import com.android.car.ui.toolbar.ToolbarController;
@@ -56,6 +59,20 @@ public abstract class AutoSettingsFrameFragment extends PreferenceFragment {
return rootView;
}
+ @Override
+ public void onCarUiInsetsChanged(Insets insets) {
+ // don't allow scrolling behind the toolbar to be consistent with the rest of Settings
+ // reference UI. Scrolling behind toolbar also leads to flakier tests due to UI being
+ // visible but clicks are intercepted and dropped by the toolbar.
+ FocusArea focusArea = getView().findViewById(R.id.car_ui_focus_area);
+ focusArea.setHighlightPadding(
+ /* left= */ 0, /* top= */ 0, /* right= */ 0, /* bottom= */ 0);
+ focusArea.setBoundsOffset(/* left= */ 0, /* top= */ 0, /* right= */ 0, /* bottom= */ 0);
+ getView().setPadding(
+ insets.getLeft(), insets.getTop(), insets.getRight(), insets.getBottom());
+ getCarUiRecyclerView().setPadding(
+ /* left= */ 0, /* top= */ 0, /* right= */ 0, /* bottom= */ 0);
+ }
/** Sets the header text of this fragment. */
public void setHeaderLabel(CharSequence label) {
diff --git a/PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt b/PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt
index 0562afc0f..719ef33b5 100644
--- a/PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt
@@ -24,16 +24,13 @@ import android.app.PendingIntent
import android.app.Service
import android.car.Car
import android.car.drivingstate.CarUxRestrictionsManager
-import android.content.ComponentName
import android.content.Context
import android.content.Intent
-import android.content.pm.PackageManager
import android.os.Bundle
import android.os.IBinder
import android.os.Process
import android.os.UserHandle
import android.permission.PermissionManager
-import android.provider.Settings
import android.text.BidiFormatter
import androidx.annotation.VisibleForTesting
import com.android.permissioncontroller.Constants
@@ -55,9 +52,7 @@ import java.util.Random
*/
class DrivingDecisionReminderService : Service() {
- /**
- * Information needed to show a reminder about a permission decisions.
- */
+ /** Information needed to show a reminder about a permission decisions. */
data class PermissionReminder(
val packageName: String,
val permissionGroup: String,
@@ -72,7 +67,6 @@ class DrivingDecisionReminderService : Service() {
companion object {
private const val LOG_TAG = "DrivingDecisionReminderService"
- private const val SETTINGS_PACKAGE_NAME_FALLBACK = "com.android.settings"
const val EXTRA_PACKAGE_NAME = "package_name"
const val EXTRA_PERMISSION_GROUP = "permission_group"
@@ -109,14 +103,14 @@ class DrivingDecisionReminderService : Service() {
packageName: String,
permGroupName: String
) {
- Car.createCar(
- context,
- /* handler= */ null,
- Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT) { car: Car, ready: Boolean ->
+ Car.createCar(context, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT) {
+ car: Car,
+ ready: Boolean ->
// just give up if we can't connect to the car
if (ready) {
- val restrictionsManager = car.getCarManager(
- Car.CAR_UX_RESTRICTION_SERVICE) as CarUxRestrictionsManager?
+ val restrictionsManager =
+ car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE)
+ as CarUxRestrictionsManager?
if (restrictionsManager != null) {
val currentCarUxRestrictions = restrictionsManager.currentCarUxRestrictions
if (currentCarUxRestrictions != null) {
@@ -126,15 +120,21 @@ class DrivingDecisionReminderService : Service() {
context,
packageName,
permGroupName,
- Process.myUserHandle()))
+ Process.myUserHandle()
+ )
+ )
}
} else {
- DumpableLog.e(LOG_TAG,
- "Reminder service not created because CarUxRestrictions is null")
+ DumpableLog.e(
+ LOG_TAG,
+ "Reminder service not created because CarUxRestrictions is null"
+ )
}
} else {
- DumpableLog.e(LOG_TAG,
- "Reminder service not created because CarUxRestrictionsManager is null")
+ DumpableLog.e(
+ LOG_TAG,
+ "Reminder service not created because CarUxRestrictionsManager is null"
+ )
}
}
car.disconnect()
@@ -166,28 +166,32 @@ class DrivingDecisionReminderService : Service() {
}
private fun scheduleNotificationForUnrestrictedState() {
- Car.createCar(this, null,
- Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT
- ) { createdCar: Car?, ready: Boolean ->
+ Car.createCar(this, null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT) {
+ createdCar: Car?,
+ ready: Boolean ->
car = createdCar
if (ready) {
onCarReady()
} else {
- DumpableLog.w(LOG_TAG,
- "Car service disconnected, no notification will be scheduled")
+ DumpableLog.w(
+ LOG_TAG,
+ "Car service disconnected, no notification will be scheduled"
+ )
stopSelf()
}
}
}
private fun onCarReady() {
- carUxRestrictionsManager = car?.getCarManager(
- Car.CAR_UX_RESTRICTION_SERVICE) as CarUxRestrictionsManager
+ carUxRestrictionsManager =
+ car?.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE) as CarUxRestrictionsManager
DumpableLog.d(LOG_TAG, "Registering UX restriction listener")
carUxRestrictionsManager?.registerListener { restrictions ->
if (!restrictions.isRequiresDistractionOptimization) {
- DumpableLog.d(LOG_TAG,
- "UX restrictions no longer required - showing reminder notification")
+ DumpableLog.d(
+ LOG_TAG,
+ "UX restrictions no longer required - showing reminder notification"
+ )
showRecentGrantDecisionsPostDriveNotification()
stopSelf()
}
@@ -195,10 +199,12 @@ class DrivingDecisionReminderService : Service() {
}
private fun parseStartIntent(intent: Intent?): PermissionReminder? {
- if (intent == null ||
- !intent.hasExtra(EXTRA_PACKAGE_NAME) ||
- !intent.hasExtra(EXTRA_PERMISSION_GROUP) ||
- !intent.hasExtra(EXTRA_USER)) {
+ if (
+ intent == null ||
+ !intent.hasExtra(EXTRA_PACKAGE_NAME) ||
+ !intent.hasExtra(EXTRA_PERMISSION_GROUP) ||
+ !intent.hasExtra(EXTRA_USER)
+ ) {
DumpableLog.e(LOG_TAG, "Missing extras from intent $intent")
return null
}
@@ -212,21 +218,25 @@ class DrivingDecisionReminderService : Service() {
fun showRecentGrantDecisionsPostDriveNotification() {
val notificationManager = getSystemService(NotificationManager::class.java)!!
- val permissionReminderChannel = NotificationChannel(
- Constants.PERMISSION_REMINDER_CHANNEL_ID, getString(R.string.permission_reminders),
- NotificationManager.IMPORTANCE_HIGH)
+ val permissionReminderChannel =
+ NotificationChannel(
+ Constants.PERMISSION_REMINDER_CHANNEL_ID,
+ getString(R.string.permission_reminders),
+ NotificationManager.IMPORTANCE_HIGH
+ )
notificationManager.createNotificationChannel(permissionReminderChannel)
- notificationManager.notify(DrivingDecisionReminderService::class.java.simpleName,
+ notificationManager.notify(
+ DrivingDecisionReminderService::class.java.simpleName,
Constants.PERMISSION_DECISION_REMINDER_NOTIFICATION_ID,
- createNotification(createNotificationTitle(), createNotificationContent()))
+ createNotification(createNotificationTitle(), createNotificationContent())
+ )
logNotificationPresented()
}
private fun createNotificationTitle(): String {
- return applicationContext
- .getString(R.string.post_drive_permission_decision_reminder_title)
+ return applicationContext.getString(R.string.post_drive_permission_decision_reminder_title)
}
@VisibleForTesting
@@ -234,76 +244,100 @@ class DrivingDecisionReminderService : Service() {
val packageLabels: MutableList<String> = mutableListOf()
val permissionGroupNames: MutableList<String> = mutableListOf()
for (permissionReminder in permissionReminders) {
- val packageLabel = getLabelForPackage(permissionReminder.packageName,
- permissionReminder.user)
- val permissionGroupLabel = getPermGroupLabel(applicationContext,
- permissionReminder.permissionGroup).toString()
+ val packageLabel =
+ getLabelForPackage(permissionReminder.packageName, permissionReminder.user)
+ val permissionGroupLabel =
+ getPermGroupLabel(applicationContext, permissionReminder.permissionGroup).toString()
packageLabels.add(packageLabel)
permissionGroupNames.add(permissionGroupLabel)
}
val packageLabelsDistinct = packageLabels.distinct()
val permissionGroupNamesDistinct = permissionGroupNames.distinct()
return if (packageLabelsDistinct.size > 1) {
- StringUtils.getIcuPluralsString(applicationContext,
+ StringUtils.getIcuPluralsString(
+ applicationContext,
R.string.post_drive_permission_decision_reminder_summary_multi_apps,
- (packageLabels.size - 1), packageLabelsDistinct[0])
+ (packageLabels.size - 1),
+ packageLabelsDistinct[0]
+ )
} else if (permissionGroupNamesDistinct.size == 2) {
getString(
R.string.post_drive_permission_decision_reminder_summary_1_app_2_permissions,
- packageLabelsDistinct[0], permissionGroupNamesDistinct[0],
- permissionGroupNamesDistinct[1])
+ packageLabelsDistinct[0],
+ permissionGroupNamesDistinct[0],
+ permissionGroupNamesDistinct[1]
+ )
} else if (permissionGroupNamesDistinct.size > 2) {
getString(
R.string.post_drive_permission_decision_reminder_summary_1_app_multi_permission,
- permissionGroupNamesDistinct.size, packageLabelsDistinct[0])
+ permissionGroupNamesDistinct.size,
+ packageLabelsDistinct[0]
+ )
} else {
getString(
R.string.post_drive_permission_decision_reminder_summary_1_app_1_permission,
- packageLabelsDistinct[0], permissionGroupNamesDistinct[0])
+ packageLabelsDistinct[0],
+ permissionGroupNamesDistinct[0]
+ )
}
}
@VisibleForTesting
fun getLabelForPackage(packageName: String, user: UserHandle): String {
- return BidiFormatter.getInstance().unicodeWrap(
- getPackageLabel(application, packageName, user))
+ return BidiFormatter.getInstance()
+ .unicodeWrap(getPackageLabel(application, packageName, user))
}
private fun createNotification(title: String, body: String): Notification {
- val clickIntent = Intent(PermissionManager.ACTION_REVIEW_PERMISSION_DECISIONS).apply {
- putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- putExtra(AutoReviewPermissionDecisionsFragment.EXTRA_SOURCE,
- AutoReviewPermissionDecisionsFragment.EXTRA_SOURCE_NOTIFICATION)
- flags = Intent.FLAG_ACTIVITY_NEW_TASK
- }
- val pendingIntent = PendingIntent.getActivity(this, 0, clickIntent,
- PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_UPDATE_CURRENT or
- PendingIntent.FLAG_IMMUTABLE)
+ val clickIntent =
+ Intent(PermissionManager.ACTION_REVIEW_PERMISSION_DECISIONS).apply {
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ putExtra(
+ AutoReviewPermissionDecisionsFragment.EXTRA_SOURCE,
+ AutoReviewPermissionDecisionsFragment.EXTRA_SOURCE_NOTIFICATION
+ )
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ }
+ val pendingIntent =
+ PendingIntent.getActivity(
+ this,
+ 0,
+ clickIntent,
+ PendingIntent.FLAG_ONE_SHOT or
+ PendingIntent.FLAG_UPDATE_CURRENT or
+ PendingIntent.FLAG_IMMUTABLE
+ )
- val settingsDrawable = KotlinUtils.getBadgedPackageIcon(
- application,
- getSettingsPackageName(applicationContext.packageManager),
- permissionReminders.first().user)
- val settingsIcon = if (settingsDrawable != null) {
- KotlinUtils.convertToBitmap(settingsDrawable)
- } else {
- null
- }
+ val settingsIcon =
+ KotlinUtils.getSettingsIcon(
+ application,
+ permissionReminders.first().user,
+ applicationContext.packageManager
+ )
- val b = Notification.Builder(this, Constants.PERMISSION_REMINDER_CHANNEL_ID)
- .setContentTitle(title)
- .setContentText(body)
- .setSmallIcon(R.drawable.ic_settings_24dp)
- .setLargeIcon(settingsIcon)
- .setColor(getColor(android.R.color.system_notification_accent_color))
- .setAutoCancel(true)
- .setContentIntent(pendingIntent)
- .addExtras(Bundle().apply {
- putBoolean("com.android.car.notification.EXTRA_USE_LAUNCHER_ICON", false)
- })
- // Auto doesn't show icons for actions
- .addAction(Notification.Action.Builder(/* icon= */ null,
- getString(R.string.go_to_settings), pendingIntent).build())
+ val b =
+ Notification.Builder(this, Constants.PERMISSION_REMINDER_CHANNEL_ID)
+ .setContentTitle(title)
+ .setContentText(body)
+ .setSmallIcon(R.drawable.ic_settings_24dp)
+ .setLargeIcon(settingsIcon)
+ .setColor(getColor(android.R.color.system_notification_accent_color))
+ .setAutoCancel(true)
+ .setContentIntent(pendingIntent)
+ .addExtras(
+ Bundle().apply {
+ putBoolean(Constants.NOTIFICATION_EXTRA_USE_LAUNCHER_ICON, false)
+ }
+ )
+ // Auto doesn't show icons for actions
+ .addAction(
+ Notification.Action.Builder(
+ /* icon= */ null,
+ getString(R.string.go_to_settings),
+ pendingIntent
+ )
+ .build()
+ )
Utils.getSettingsLabelForNotifications(applicationContext.packageManager)?.let { label ->
val extras = Bundle()
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, label.toString())
@@ -312,15 +346,11 @@ class DrivingDecisionReminderService : Service() {
return b.build()
}
- private fun getSettingsPackageName(pm: PackageManager): String {
- val settingsIntent = Intent(Settings.ACTION_SETTINGS)
- val settingsComponent: ComponentName? = settingsIntent.resolveActivity(pm)
- return settingsComponent?.packageName ?: SETTINGS_PACKAGE_NAME_FALLBACK
- }
-
private fun logNotificationPresented() {
PermissionControllerStatsLog.write(
PermissionControllerStatsLog.PERMISSION_REMINDER_NOTIFICATION_INTERACTED,
- sessionId, PERMISSION_REMINDER_NOTIFICATION_INTERACTED__RESULT__NOTIFICATION_PRESENTED)
+ sessionId,
+ PERMISSION_REMINDER_NOTIFICATION_INTERACTED__RESULT__NOTIFICATION_PRESENTED
+ )
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt b/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
index 1f6b5272a..4d52abe32 100644
--- a/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
+++ b/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
@@ -80,6 +80,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.preference.PreferenceManager
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.DeviceUtils
import com.android.permissioncontroller.DumpableLog
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.R
@@ -99,6 +100,7 @@ import com.android.permissioncontroller.permission.data.get
import com.android.permissioncontroller.permission.data.getUnusedPackages
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.service.revokeAppPermissions
+import com.android.permissioncontroller.permission.utils.IPC
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.StringUtils
import com.android.permissioncontroller.permission.utils.Utils
@@ -113,26 +115,31 @@ import kotlinx.coroutines.launch
private const val LOG_TAG = "HibernationPolicy"
const val DEBUG_OVERRIDE_THRESHOLDS = false
-// TODO eugenesusla: temporarily enabled for extra logs during dogfooding
-const val DEBUG_HIBERNATION_POLICY = true || DEBUG_OVERRIDE_THRESHOLDS
+const val DEBUG_HIBERNATION_POLICY = false
private var SKIP_NEXT_RUN = false
private val DEFAULT_UNUSED_THRESHOLD_MS = TimeUnit.DAYS.toMillis(90)
-fun getUnusedThresholdMs() = when {
- DEBUG_OVERRIDE_THRESHOLDS -> TimeUnit.SECONDS.toMillis(1)
- else -> DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
- Utils.PROPERTY_HIBERNATION_UNUSED_THRESHOLD_MILLIS,
- DEFAULT_UNUSED_THRESHOLD_MS)
-}
+fun getUnusedThresholdMs() =
+ when {
+ DEBUG_OVERRIDE_THRESHOLDS -> TimeUnit.SECONDS.toMillis(1)
+ else ->
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PERMISSIONS,
+ Utils.PROPERTY_HIBERNATION_UNUSED_THRESHOLD_MILLIS,
+ DEFAULT_UNUSED_THRESHOLD_MS
+ )
+ }
private val DEFAULT_CHECK_FREQUENCY_MS = TimeUnit.DAYS.toMillis(15)
-private fun getCheckFrequencyMs() = DeviceConfig.getLong(
- DeviceConfig.NAMESPACE_PERMISSIONS,
+private fun getCheckFrequencyMs() =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PERMISSIONS,
Utils.PROPERTY_HIBERNATION_CHECK_FREQUENCY_MILLIS,
- DEFAULT_CHECK_FREQUENCY_MS)
+ DEFAULT_CHECK_FREQUENCY_MS
+ )
// Intentionally kept value of the key same as before because we want to continue reading value of
// this shared preference stored by previous versions of PermissionController
@@ -149,8 +156,11 @@ val ONE_DAY_MS = TimeUnit.DAYS.toMillis(1)
fun isHibernationEnabled(): Boolean {
return SdkLevel.isAtLeastS() &&
- DeviceConfig.getBoolean(NAMESPACE_APP_HIBERNATION, Utils.PROPERTY_APP_HIBERNATION_ENABLED,
- true /* defaultValue */)
+ DeviceConfig.getBoolean(
+ NAMESPACE_APP_HIBERNATION,
+ Utils.PROPERTY_APP_HIBERNATION_ENABLED,
+ true /* defaultValue */
+ )
}
/**
@@ -158,30 +168,33 @@ fun isHibernationEnabled(): Boolean {
* [isHibernationEnabled] is false.
*/
fun hibernationTargetsPreSApps(): Boolean {
- return DeviceConfig.getBoolean(NAMESPACE_APP_HIBERNATION,
+ return DeviceConfig.getBoolean(
+ NAMESPACE_APP_HIBERNATION,
Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS,
- false /* defaultValue */)
+ false /* defaultValue */
+ )
}
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
fun isSystemExemptFromHibernationEnabled(): Boolean {
- return SdkLevel.isAtLeastU() && DeviceConfig.getBoolean(NAMESPACE_APP_HIBERNATION,
+ return SdkLevel.isAtLeastU() &&
+ DeviceConfig.getBoolean(
+ NAMESPACE_APP_HIBERNATION,
Utils.PROPERTY_SYSTEM_EXEMPT_HIBERNATION_ENABLED,
- true /* defaultValue */)
+ true /* defaultValue */
+ )
}
-/**
- * Remove the unused apps notification.
- */
+/** Remove the unused apps notification. */
fun cancelUnusedAppsNotification(context: Context) {
- context.getSystemService(NotificationManager::class.java)!!.cancel(
- HibernationJobService::class.java.simpleName,
- Constants.UNUSED_APPS_NOTIFICATION_ID)
+ context
+ .getSystemService(NotificationManager::class.java)!!
+ .cancel(HibernationJobService::class.java.simpleName, Constants.UNUSED_APPS_NOTIFICATION_ID)
}
/**
- * Checks if we need to show the safety center card and sends the appropriate source data. If
- * the user has not reviewed the latest auto-revoked apps, we show the card. Otherwise, we ensure
+ * Checks if we need to show the safety center card and sends the appropriate source data. If the
+ * user has not reviewed the latest auto-revoked apps, we show the card. Otherwise, we ensure
* nothing is shown.
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@@ -193,36 +206,40 @@ fun rescanAndPushDataToSafetyCenter(
val safetyCenterManager: SafetyCenterManager =
context.getSystemService(SafetyCenterManager::class.java)!!
if (getUnusedAppsReviewNeeded(context)) {
- val seeUnusedAppsAction = Action.Builder(
- Constants.UNUSED_APPS_SAFETY_CENTER_SEE_UNUSED_APPS_ID,
- context.getString(R.string.unused_apps_safety_center_action_title),
- makeUnusedAppsIntent(context, sessionId))
- .build()
-
- val issue = SafetySourceIssue.Builder(
- Constants.UNUSED_APPS_SAFETY_CENTER_ISSUE_ID,
- context.getString(R.string.unused_apps_safety_center_card_title),
- context.getString(R.string.unused_apps_safety_center_card_content),
- SafetySourceData.SEVERITY_LEVEL_INFORMATION,
- Constants.UNUSED_APPS_SAFETY_CENTER_ISSUE_ID)
- .addAction(seeUnusedAppsAction)
- .setOnDismissPendingIntent(makeDismissIntent(context, sessionId))
- .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
- .build()
-
- val safetySourceData = SafetySourceData.Builder()
- .addIssue(issue)
- .build()
+ val seeUnusedAppsAction =
+ Action.Builder(
+ Constants.UNUSED_APPS_SAFETY_CENTER_SEE_UNUSED_APPS_ID,
+ context.getString(R.string.unused_apps_safety_center_action_title),
+ makeUnusedAppsIntent(context, sessionId)
+ )
+ .build()
+
+ val issue =
+ SafetySourceIssue.Builder(
+ Constants.UNUSED_APPS_SAFETY_CENTER_ISSUE_ID,
+ context.getString(R.string.unused_apps_safety_center_card_title),
+ context.getString(R.string.unused_apps_safety_center_card_content),
+ SafetySourceData.SEVERITY_LEVEL_INFORMATION,
+ Constants.UNUSED_APPS_SAFETY_CENTER_ISSUE_ID
+ )
+ .addAction(seeUnusedAppsAction)
+ .setOnDismissPendingIntent(makeDismissIntent(context, sessionId))
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .build()
+
+ val safetySourceData = SafetySourceData.Builder().addIssue(issue).build()
safetyCenterManager.setSafetySourceData(
Constants.UNUSED_APPS_SAFETY_CENTER_SOURCE_ID,
safetySourceData,
- safetyEvent)
+ safetyEvent
+ )
} else {
safetyCenterManager.setSafetySourceData(
Constants.UNUSED_APPS_SAFETY_CENTER_SOURCE_ID,
/* safetySourceData= */ null,
- safetyEvent)
+ safetyEvent
+ )
}
}
@@ -231,8 +248,10 @@ fun rescanAndPushDataToSafetyCenter(
*/
fun setUnusedAppsReviewNeeded(context: Context, needsReview: Boolean) {
val sharedPreferences = context.sharedPreferences
- if (sharedPreferences.contains(PREF_KEY_UNUSED_APPS_REVIEW) &&
- sharedPreferences.getBoolean(PREF_KEY_UNUSED_APPS_REVIEW, false) == needsReview) {
+ if (
+ sharedPreferences.contains(PREF_KEY_UNUSED_APPS_REVIEW) &&
+ sharedPreferences.getBoolean(PREF_KEY_UNUSED_APPS_REVIEW, false) == needsReview
+ ) {
return
}
sharedPreferences.edit().putBoolean(PREF_KEY_UNUSED_APPS_REVIEW, needsReview).apply()
@@ -245,10 +264,10 @@ private fun getUnusedAppsReviewNeeded(context: Context): Boolean {
/**
* Receiver of the following broadcasts:
* <ul>
- * <li> {@link Intent.ACTION_BOOT_COMPLETED}
- * <li> {@link #ACTION_SET_UP_HIBERNATION}
- * <li> {@link Intent.ACTION_TIME_CHANGED}
- * <li> {@link Intent.ACTION_TIMEZONE_CHANGED}
+ * <li> {@link Intent.ACTION_BOOT_COMPLETED}
+ * <li> {@link #ACTION_SET_UP_HIBERNATION}
+ * <li> {@link Intent.ACTION_TIME_CHANGED}
+ * <li> {@link Intent.ACTION_TIMEZONE_CHANGED}
* </ul>
*/
class HibernationBroadcastReceiver : BroadcastReceiver() {
@@ -257,9 +276,12 @@ class HibernationBroadcastReceiver : BroadcastReceiver() {
val action = intent.action
if (action == Intent.ACTION_BOOT_COMPLETED || action == ACTION_SET_UP_HIBERNATION) {
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG, "scheduleHibernationJob " +
- "with frequency ${getCheckFrequencyMs()}ms " +
- "and threshold ${getUnusedThresholdMs()}ms")
+ DumpableLog.i(
+ LOG_TAG,
+ "scheduleHibernationJob " +
+ "with frequency ${getCheckFrequencyMs()}ms " +
+ "and threshold ${getUnusedThresholdMs()}ms"
+ )
}
initStartTimeOfUnusedAppTracking(context.sharedPreferences)
@@ -268,32 +290,40 @@ class HibernationBroadcastReceiver : BroadcastReceiver() {
// primary user
if (isProfile(context)) {
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG,
- "user ${Process.myUserHandle().identifier} is a profile." +
- " Not running hibernation job.")
+ DumpableLog.i(
+ LOG_TAG,
+ "user ${Process.myUserHandle().identifier} is a profile." +
+ " Not running hibernation job."
+ )
}
return
} else if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG,
- "user ${Process.myUserHandle().identifier} is a profile" +
- "owner. Running hibernation job.")
+ DumpableLog.i(
+ LOG_TAG,
+ "user ${Process.myUserHandle().identifier} is a profile" +
+ "owner. Running hibernation job."
+ )
}
if (isNewJobScheduleRequired(context)) {
// periodic jobs normally run immediately, which is unnecessarily premature
SKIP_NEXT_RUN = true
- val jobInfo = JobInfo.Builder(
- Constants.HIBERNATION_JOB_ID,
- ComponentName(context, HibernationJobService::class.java))
- .setPeriodic(getCheckFrequencyMs())
- // persist this job across boots
- .setPersisted(true)
- .build()
- val status =
- context.getSystemService(JobScheduler::class.java)!!.schedule(jobInfo)
+ val jobInfo =
+ JobInfo.Builder(
+ Constants.HIBERNATION_JOB_ID,
+ ComponentName(context, HibernationJobService::class.java)
+ )
+ .setPeriodic(getCheckFrequencyMs())
+ // persist this job across boots
+ .setPersisted(true)
+ .build()
+ val status = context.getSystemService(JobScheduler::class.java)!!.schedule(jobInfo)
if (status != JobScheduler.RESULT_SUCCESS) {
- DumpableLog.e(LOG_TAG, "Could not schedule " +
- "${HibernationJobService::class.java.simpleName}: $status")
+ DumpableLog.e(
+ LOG_TAG,
+ "Could not schedule " +
+ "${HibernationJobService::class.java.simpleName}: $status"
+ )
}
}
}
@@ -318,8 +348,10 @@ class HibernationBroadcastReceiver : BroadcastReceiver() {
private fun isNewJobScheduleRequired(context: Context): Boolean {
// check if the job is already scheduled or needs a change
var scheduleNewJob = false
- val existingJob: JobInfo? = context.getSystemService(JobScheduler::class.java)!!
- .getPendingJob(Constants.HIBERNATION_JOB_ID)
+ val existingJob: JobInfo? =
+ context
+ .getSystemService(JobScheduler::class.java)!!
+ .getPendingJob(Constants.HIBERNATION_JOB_ID)
if (existingJob == null) {
if (DEBUG_HIBERNATION_POLICY) {
DumpableLog.i(LOG_TAG, "No existing job, scheduling a new one")
@@ -350,19 +382,24 @@ private suspend fun getAppsToHibernate(
val startTimeOfUnusedAppTracking = getStartTimeOfUnusedAppTracking(context.sharedPreferences)
val allPackagesByUser = AllPackageInfosLiveData.getInitializedValue(forceUpdate = true)
- val allPackagesByUserByUid = allPackagesByUser.mapValues { (_, pkgs) ->
- pkgs.groupBy { pkg -> pkg.uid }
- }
+ val allPackagesByUserByUid =
+ allPackagesByUser.mapValues { (_, pkgs) -> pkgs.groupBy { pkg -> pkg.uid } }
val unusedApps = allPackagesByUser.toMutableMap()
- val userStats = UsageStatsLiveData[getUnusedThresholdMs(),
- if (DEBUG_OVERRIDE_THRESHOLDS) INTERVAL_DAILY else INTERVAL_MONTHLY].getInitializedValue()
+ val userStats =
+ UsageStatsLiveData[
+ getUnusedThresholdMs(),
+ if (DEBUG_OVERRIDE_THRESHOLDS) INTERVAL_DAILY else INTERVAL_MONTHLY]
+ .getInitializedValue()
if (DEBUG_HIBERNATION_POLICY) {
for ((user, stats) in userStats) {
- DumpableLog.i(LOG_TAG, "Usage stats for user ${user.identifier}: " +
- stats.map { stat ->
- stat.packageName to Date(stat.lastTimePackageUsed())
- }.toMap())
+ DumpableLog.i(
+ LOG_TAG,
+ "Usage stats for user ${user.identifier}: " +
+ stats
+ .map { stat -> stat.packageName to Date(stat.lastTimePackageUsed()) }
+ .toMap()
+ )
}
}
for (user in unusedApps.keys.toList()) {
@@ -377,42 +414,52 @@ private suspend fun getAppsToHibernate(
for ((user, stats) in userStats) {
var unusedUserApps = unusedApps[user] ?: continue
- unusedUserApps = unusedUserApps.filter { packageInfo ->
- val pkgName = packageInfo.packageName
-
- val uidPackages = allPackagesByUserByUid[user]!![packageInfo.uid]
- ?.map { info -> info.packageName } ?: emptyList()
- if (pkgName !in uidPackages) {
- Log.wtf(LOG_TAG, "Package $pkgName not among packages for " +
- "its uid ${packageInfo.uid}: $uidPackages")
- }
- var lastTimePkgUsed: Long = stats.lastTimePackageUsed(uidPackages)
+ unusedUserApps =
+ unusedUserApps.filter { packageInfo ->
+ val pkgName = packageInfo.packageName
- // Limit by install time
- lastTimePkgUsed = Math.max(lastTimePkgUsed, packageInfo.firstInstallTime)
-
- // Limit by first boot time
- lastTimePkgUsed = Math.max(lastTimePkgUsed, startTimeOfUnusedAppTracking)
-
- // Handle cross-profile apps
- if (context.isPackageCrossProfile(pkgName)) {
- for ((otherUser, otherStats) in userStats) {
- if (otherUser == user) {
- continue
+ val uidPackages =
+ allPackagesByUserByUid[user]!![packageInfo.uid]?.map { info ->
+ info.packageName
+ }
+ ?: emptyList()
+ if (pkgName !in uidPackages) {
+ Log.wtf(
+ LOG_TAG,
+ "Package $pkgName not among packages for " +
+ "its uid ${packageInfo.uid}: $uidPackages"
+ )
+ }
+ var lastTimePkgUsed: Long = stats.lastTimePackageUsed(uidPackages)
+
+ // Limit by install time
+ lastTimePkgUsed = Math.max(lastTimePkgUsed, packageInfo.firstInstallTime)
+
+ // Limit by first boot time
+ lastTimePkgUsed = Math.max(lastTimePkgUsed, startTimeOfUnusedAppTracking)
+
+ // Handle cross-profile apps
+ if (context.isPackageCrossProfile(pkgName)) {
+ for ((otherUser, otherStats) in userStats) {
+ if (otherUser == user) {
+ continue
+ }
+ lastTimePkgUsed =
+ maxOf(lastTimePkgUsed, otherStats.lastTimePackageUsed(pkgName))
}
- lastTimePkgUsed =
- maxOf(lastTimePkgUsed, otherStats.lastTimePackageUsed(pkgName))
}
- }
- // Threshold check - whether app is unused
- now - lastTimePkgUsed > getUnusedThresholdMs()
- }
+ // Threshold check - whether app is unused
+ now - lastTimePkgUsed > getUnusedThresholdMs()
+ }
unusedApps[user] = unusedUserApps
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG, "Unused apps for user ${user.identifier}: " +
- "${unusedUserApps.map { it.packageName }}")
+ DumpableLog.i(
+ LOG_TAG,
+ "Unused apps for user ${user.identifier}: " +
+ "${unusedUserApps.map { it.packageName }}"
+ )
}
}
@@ -434,25 +481,29 @@ private suspend fun getAppsToHibernate(
}
val packageName = pkg.packageName
- val packageImportance = context
- .getSystemService(ActivityManager::class.java)!!
- .getPackageImportance(packageName)
+ val packageImportance =
+ context
+ .getSystemService(ActivityManager::class.java)!!
+ .getPackageImportance(packageName)
if (packageImportance <= IMPORTANCE_CANT_SAVE_STATE) {
// Process is running in a state where it should not be killed
- DumpableLog.i(LOG_TAG,
+ DumpableLog.i(
+ LOG_TAG,
"Skipping hibernation - $packageName running with importance " +
- "$packageImportance")
+ "$packageImportance"
+ )
return@forEachInParallel
}
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG, "unused app $packageName - last used on " +
- userStats[user]?.lastTimePackageUsed(packageName)?.let(::Date))
+ DumpableLog.i(
+ LOG_TAG,
+ "unused app $packageName - last used on " +
+ userStats[user]?.lastTimePackageUsed(packageName)?.let(::Date)
+ )
}
- synchronized(userAppsToHibernate) {
- userAppsToHibernate.add(pkg)
- }
+ synchronized(userAppsToHibernate) { userAppsToHibernate.add(pkg) }
}
appsToHibernate.put(user, userAppsToHibernate)
}
@@ -460,9 +511,9 @@ private suspend fun getAppsToHibernate(
}
/**
- * Gets the last time we consider the package used based off its usage stats. On pre-S devices
- * this looks at last time visible which tracks explicit usage. In S, we add component usage
- * which tracks various forms of implicit usage (e.g. service bindings).
+ * Gets the last time we consider the package used based off its usage stats. On pre-S devices this
+ * looks at last time visible which tracks explicit usage. In S, we add component usage which tracks
+ * various forms of implicit usage (e.g. service bindings).
*/
fun UsageStats.lastTimePackageUsed(): Long {
var lastTimePkgUsed = this.lastTimeVisible
@@ -486,9 +537,7 @@ private fun List<UsageStats>.lastTimePackageUsed(pkgName: String): Long {
return lastTimePackageUsed(listOf(pkgName))
}
-/**
- * Checks if the given package is exempt from hibernation in a way that's not user-overridable
- */
+/** Checks if the given package is exempt from hibernation in a way that's not user-overridable */
suspend fun isPackageHibernationExemptBySystem(
pkg: LightPackageInfo,
user: UserHandle,
@@ -499,23 +548,22 @@ suspend fun isPackageHibernationExemptBySystem(
}
return true
}
- if (!ExemptServicesLiveData[user]
- .getInitializedValue()[pkg.packageName]
- .isNullOrEmpty()) {
+ if (!ExemptServicesLiveData[user].getInitializedValue()[pkg.packageName].isNullOrEmpty()) {
return true
}
if (Utils.isUserDisabledOrWorkProfile(user)) {
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG,
- "Exempted ${pkg.packageName} - $user is disabled or a work profile")
+ DumpableLog.i(
+ LOG_TAG,
+ "Exempted ${pkg.packageName} - $user is disabled or a work profile"
+ )
}
return true
}
- if (pkg.uid == Process.SYSTEM_UID){
+ if (pkg.uid == Process.SYSTEM_UID) {
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG,
- "Exempted ${pkg.packageName} - Package shares system uid")
+ DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} - Package shares system uid")
}
return true
}
@@ -523,8 +571,8 @@ suspend fun isPackageHibernationExemptBySystem(
val context = PermissionControllerApplication.get()
if (context.getSystemService(DevicePolicyManager::class.java)!!.isDeviceManaged) {
// TODO(b/237065504): Use proper system API to check if the device is financed in U.
- val isFinancedDevice = Settings.Global.getInt(
- context.contentResolver, "device_owner_type", 0) == 1
+ val isFinancedDevice =
+ Settings.Global.getInt(context.contentResolver, "device_owner_type", 0) == 1
if (!isFinancedDevice) {
if (DEBUG_HIBERNATION_POLICY) {
DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} - device is managed")
@@ -533,12 +581,16 @@ suspend fun isPackageHibernationExemptBySystem(
}
}
- val carrierPrivilegedStatus = CarrierPrivilegedStatusLiveData[pkg.packageName]
- .getInitializedValue()
- if (carrierPrivilegedStatus != CARRIER_PRIVILEGE_STATUS_HAS_ACCESS &&
- carrierPrivilegedStatus != CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
- DumpableLog.w(LOG_TAG, "Error carrier privileged status for ${pkg.packageName}: " +
- carrierPrivilegedStatus)
+ val carrierPrivilegedStatus =
+ CarrierPrivilegedStatusLiveData[pkg.packageName].getInitializedValue()
+ if (
+ carrierPrivilegedStatus != CARRIER_PRIVILEGE_STATUS_HAS_ACCESS &&
+ carrierPrivilegedStatus != CARRIER_PRIVILEGE_STATUS_NO_ACCESS
+ ) {
+ DumpableLog.w(
+ LOG_TAG,
+ "Error carrier privileged status for ${pkg.packageName}: " + carrierPrivilegedStatus
+ )
}
if (carrierPrivilegedStatus == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
if (DEBUG_HIBERNATION_POLICY) {
@@ -547,19 +599,24 @@ suspend fun isPackageHibernationExemptBySystem(
return true
}
- if (PermissionControllerApplication.get()
+ if (
+ PermissionControllerApplication.get()
.packageManager
- .checkPermission(
- Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
- pkg.packageName) == PERMISSION_GRANTED) {
+ .checkPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pkg.packageName) ==
+ PERMISSION_GRANTED
+ ) {
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} " +
- "- holder of READ_PRIVILEGED_PHONE_STATE")
+ DumpableLog.i(
+ LOG_TAG,
+ "Exempted ${pkg.packageName} " + "- holder of READ_PRIVILEGED_PHONE_STATE"
+ )
}
return true
}
- val emergencyRoleHolders = context.getSystemService(android.app.role.RoleManager::class.java)!!
+ val emergencyRoleHolders =
+ context
+ .getSystemService(android.app.role.RoleManager::class.java)!!
.getRoleHolders(RoleManager.ROLE_EMERGENCY)
if (emergencyRoleHolders.contains(pkg.packageName)) {
if (DEBUG_HIBERNATION_POLICY) {
@@ -570,19 +627,19 @@ suspend fun isPackageHibernationExemptBySystem(
if (SdkLevel.isAtLeastS()) {
val hasInstallOrUpdatePermissions =
+ context.checkPermission(Manifest.permission.INSTALL_PACKAGES, -1 /* pid */, pkg.uid) ==
+ PERMISSION_GRANTED ||
context.checkPermission(
- Manifest.permission.INSTALL_PACKAGES, -1 /* pid */, pkg.uid) ==
- PERMISSION_GRANTED ||
- context.checkPermission(
- Manifest.permission.INSTALL_PACKAGE_UPDATES, -1 /* pid */, pkg.uid) ==
- PERMISSION_GRANTED
+ Manifest.permission.INSTALL_PACKAGE_UPDATES,
+ -1 /* pid */,
+ pkg.uid
+ ) == PERMISSION_GRANTED
val hasUpdatePackagesWithoutUserActionPermission =
- context.checkPermission(
- UPDATE_PACKAGES_WITHOUT_USER_ACTION, -1 /* pid */, pkg.uid) ==
- PERMISSION_GRANTED
+ context.checkPermission(UPDATE_PACKAGES_WITHOUT_USER_ACTION, -1 /* pid */, pkg.uid) ==
+ PERMISSION_GRANTED
val isInstallerOfRecord =
- InstallerPackagesLiveData[user].getInitializedValue().contains(pkg.packageName) &&
- hasUpdatePackagesWithoutUserActionPermission
+ InstallerPackagesLiveData[user].getInitializedValue().contains(pkg.packageName) &&
+ hasUpdatePackagesWithoutUserActionPermission
// Grant if app w/ privileged install/update permissions or app is an installer app that
// updates packages without user action.
if (hasInstallOrUpdatePermissions || isInstallerOfRecord) {
@@ -592,7 +649,9 @@ suspend fun isPackageHibernationExemptBySystem(
return true
}
- val roleHolders = context.getSystemService(android.app.role.RoleManager::class.java)!!
+ val roleHolders =
+ context
+ .getSystemService(android.app.role.RoleManager::class.java)!!
.getRoleHolders(RoleManager.ROLE_SYSTEM_WELLBEING)
if (roleHolders.contains(pkg.packageName)) {
if (DEBUG_HIBERNATION_POLICY) {
@@ -603,8 +662,10 @@ suspend fun isPackageHibernationExemptBySystem(
}
if (SdkLevel.isAtLeastT()) {
- val roleHolders = context.getSystemService(android.app.role.RoleManager::class.java)!!
- .getRoleHolders(RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT)
+ val roleHolders =
+ context
+ .getSystemService(android.app.role.RoleManager::class.java)!!
+ .getRoleHolders(RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT)
if (roleHolders.contains(pkg.packageName)) {
if (DEBUG_HIBERNATION_POLICY) {
DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} - device policy manager app")
@@ -613,9 +674,12 @@ suspend fun isPackageHibernationExemptBySystem(
}
}
- if (isSystemExemptFromHibernationEnabled() && AppOpLiveData[pkg.packageName,
- AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION,
- pkg.uid].getInitializedValue() == AppOpsManager.MODE_ALLOWED) {
+ if (
+ isSystemExemptFromHibernationEnabled() &&
+ AppOpLiveData[
+ pkg.packageName, AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION, pkg.uid]
+ .getInitializedValue() == AppOpsManager.MODE_ALLOWED
+ ) {
if (DEBUG_HIBERNATION_POLICY) {
DumpableLog.i(
LOG_TAG,
@@ -640,8 +704,8 @@ suspend fun isPackageHibernationExemptByUser(
val packageUid = pkg.uid
val allowlistAppOpMode =
- AppOpLiveData[packageName,
- AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, packageUid]
+ AppOpLiveData[
+ packageName, AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, packageUid]
.getInitializedValue()
if (allowlistAppOpMode == AppOpsManager.MODE_DEFAULT) {
// Initial state - allowlist not explicitly overridden by either user or installer
@@ -657,11 +721,11 @@ suspend fun isPackageHibernationExemptByUser(
// Q- packages exempt by default, except R- on Auto since Auto-Revoke was skipped in R
val maxTargetSdkVersionForExemptApps =
- if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- android.os.Build.VERSION_CODES.R
- } else {
- android.os.Build.VERSION_CODES.Q
- }
+ if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ android.os.Build.VERSION_CODES.R
+ } else {
+ android.os.Build.VERSION_CODES.Q
+ }
return pkg.targetSdkVersion <= maxTargetSdkVersionForExemptApps
}
@@ -670,18 +734,18 @@ suspend fun isPackageHibernationExemptByUser(
}
private fun Context.isPackageCrossProfile(pkg: String): Boolean {
- return packageManager.checkPermission(
- Manifest.permission.INTERACT_ACROSS_PROFILES, pkg) == PERMISSION_GRANTED ||
- packageManager.checkPermission(
- Manifest.permission.INTERACT_ACROSS_USERS, pkg) == PERMISSION_GRANTED ||
- packageManager.checkPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, pkg) == PERMISSION_GRANTED
+ return packageManager.checkPermission(Manifest.permission.INTERACT_ACROSS_PROFILES, pkg) ==
+ PERMISSION_GRANTED ||
+ packageManager.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg) ==
+ PERMISSION_GRANTED ||
+ packageManager.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, pkg) ==
+ PERMISSION_GRANTED
}
val Context.sharedPreferences: SharedPreferences
get() {
- return PreferenceManager.getDefaultSharedPreferences(this)
-}
+ return PreferenceManager.getDefaultSharedPreferences(this)
+ }
internal class SystemTime {
var actualSystemTime: Long = SNAPSHOT_UNINITIALIZED
@@ -691,15 +755,15 @@ internal class SystemTime {
private fun getSystemTime(sharedPreferences: SharedPreferences): SystemTime {
val systemTime = SystemTime()
- val systemTimeSnapshot = sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT,
- SNAPSHOT_UNINITIALIZED)
+ val systemTimeSnapshot =
+ sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
if (systemTimeSnapshot == SNAPSHOT_UNINITIALIZED) {
DumpableLog.e(LOG_TAG, "PREF_KEY_BOOT_TIME_SNAPSHOT is not initialized")
return systemTime
}
- val realtimeSnapshot = sharedPreferences.getLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT,
- SNAPSHOT_UNINITIALIZED)
+ val realtimeSnapshot =
+ sharedPreferences.getLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
if (realtimeSnapshot == SNAPSHOT_UNINITIALIZED) {
DumpableLog.e(LOG_TAG, "PREF_KEY_ELAPSED_REALTIME_SNAPSHOT is not initialized")
return systemTime
@@ -712,14 +776,19 @@ private fun getSystemTime(sharedPreferences: SharedPreferences): SystemTime {
}
fun getStartTimeOfUnusedAppTracking(sharedPreferences: SharedPreferences): Long {
- val startTimeOfUnusedAppTracking = sharedPreferences.getLong(
- PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING, SNAPSHOT_UNINITIALIZED)
+ val startTimeOfUnusedAppTracking =
+ sharedPreferences.getLong(
+ PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
+ SNAPSHOT_UNINITIALIZED
+ )
// If the preference is not initialized then use the current system time.
if (startTimeOfUnusedAppTracking == SNAPSHOT_UNINITIALIZED) {
val actualSystemTime = System.currentTimeMillis()
- sharedPreferences.edit()
- .putLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING, actualSystemTime).apply()
+ sharedPreferences
+ .edit()
+ .putLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING, actualSystemTime)
+ .apply()
return actualSystemTime
}
@@ -728,20 +797,28 @@ fun getStartTimeOfUnusedAppTracking(sharedPreferences: SharedPreferences): Long
if (diffSystemTime > ONE_DAY_MS) {
adjustStartTimeOfUnusedAppTracking(sharedPreferences)
}
- return sharedPreferences.getLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
- SNAPSHOT_UNINITIALIZED)
+ return sharedPreferences.getLong(
+ PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
+ SNAPSHOT_UNINITIALIZED
+ )
}
private fun initStartTimeOfUnusedAppTracking(sharedPreferences: SharedPreferences) {
val systemTimeSnapshot = System.currentTimeMillis()
- if (sharedPreferences
- .getLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING, SNAPSHOT_UNINITIALIZED)
- == SNAPSHOT_UNINITIALIZED) {
- sharedPreferences.edit()
- .putLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING, systemTimeSnapshot).apply()
+ if (
+ sharedPreferences.getLong(
+ PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
+ SNAPSHOT_UNINITIALIZED
+ ) == SNAPSHOT_UNINITIALIZED
+ ) {
+ sharedPreferences
+ .edit()
+ .putLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING, systemTimeSnapshot)
+ .apply()
}
val realtimeSnapshot = SystemClock.elapsedRealtime()
- sharedPreferences.edit()
+ sharedPreferences
+ .edit()
.putLong(PREF_KEY_BOOT_TIME_SNAPSHOT, systemTimeSnapshot)
.putLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT, realtimeSnapshot)
.apply()
@@ -750,49 +827,52 @@ private fun initStartTimeOfUnusedAppTracking(sharedPreferences: SharedPreference
private fun adjustStartTimeOfUnusedAppTracking(sharedPreferences: SharedPreferences) {
val systemTime = getSystemTime(sharedPreferences)
val startTimeOfUnusedAppTracking =
- sharedPreferences.getLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
- SNAPSHOT_UNINITIALIZED)
+ sharedPreferences.getLong(
+ PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
+ SNAPSHOT_UNINITIALIZED
+ )
if (startTimeOfUnusedAppTracking == SNAPSHOT_UNINITIALIZED) {
DumpableLog.e(LOG_TAG, "PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING is not initialized")
return
}
val adjustedStartTimeOfUnusedAppTracking =
startTimeOfUnusedAppTracking + systemTime.diffSystemTime
- sharedPreferences.edit()
+ sharedPreferences
+ .edit()
.putLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING, adjustedStartTimeOfUnusedAppTracking)
.putLong(PREF_KEY_BOOT_TIME_SNAPSHOT, systemTime.actualSystemTime)
.putLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT, systemTime.actualRealtime)
.apply()
}
-/**
- * Make intent to go to unused apps page.
- */
+/** Make intent to go to unused apps page. */
private fun makeUnusedAppsIntent(context: Context, sessionId: Long): PendingIntent {
- val clickIntent = Intent(Intent.ACTION_MANAGE_UNUSED_APPS).apply {
- putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- flags = FLAG_ACTIVITY_NEW_TASK
- }
- val pendingIntent = PendingIntent.getActivity(context, 0, clickIntent,
- FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
+ val clickIntent =
+ Intent(Intent.ACTION_MANAGE_UNUSED_APPS).apply {
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ flags = FLAG_ACTIVITY_NEW_TASK
+ }
+ val pendingIntent =
+ PendingIntent.getActivity(context, 0, clickIntent, FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
return pendingIntent
}
-/**
- * Make intent for when safety center card is dismissed.
- */
+/** Make intent for when safety center card is dismissed. */
private fun makeDismissIntent(context: Context, sessionId: Long): PendingIntent {
- val dismissIntent = Intent(context, DismissHandler::class.java).apply {
- putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- flags = FLAG_RECEIVER_FOREGROUND
- }
- return PendingIntent.getBroadcast(context, /* requestCode= */ 0, dismissIntent,
- FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
+ val dismissIntent =
+ Intent(context, DismissHandler::class.java).apply {
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ flags = FLAG_RECEIVER_FOREGROUND
+ }
+ return PendingIntent.getBroadcast(
+ context,
+ /* requestCode= */ 0,
+ dismissIntent,
+ FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
+ )
}
-/**
- * Broadcast receiver class for when safety center card is dismissed.
- */
+/** Broadcast receiver class for when safety center card is dismissed. */
class DismissHandler : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
setUnusedAppsReviewNeeded(context!!, false)
@@ -800,8 +880,8 @@ class DismissHandler : BroadcastReceiver() {
}
/**
- * A job to check for apps unused in the last [getUnusedThresholdMs]ms every
- * [getCheckFrequencyMs]ms and hibernate the app / revoke their runtime permissions.
+ * A job to check for apps unused in the last [getUnusedThresholdMs]ms every [getCheckFrequencyMs]ms
+ * and hibernate the app / revoke their runtime permissions.
*/
class HibernationJobService : JobService() {
var job: Job? = null
@@ -822,58 +902,79 @@ class HibernationJobService : JobService() {
}
jobStartTime = System.currentTimeMillis()
- job = GlobalScope.launch(Main) {
- try {
- var sessionId = Constants.INVALID_SESSION_ID
- while (sessionId == Constants.INVALID_SESSION_ID) {
- sessionId = Random().nextLong()
- }
+ job =
+ GlobalScope.launch(Main) {
+ try {
+ var sessionId = Constants.INVALID_SESSION_ID
+ while (sessionId == Constants.INVALID_SESSION_ID) {
+ sessionId = Random().nextLong()
+ }
- val appsToHibernate = getAppsToHibernate(this@HibernationJobService)
- var hibernatedApps: Set<Pair<String, UserHandle>> = emptySet()
- if (isHibernationEnabled()) {
- val hibernationController =
- HibernationController(this@HibernationJobService, getUnusedThresholdMs(),
- hibernationTargetsPreSApps())
- hibernatedApps = hibernationController.hibernateApps(appsToHibernate)
- }
- val revokedApps = revokeAppPermissions(
- appsToHibernate, this@HibernationJobService, sessionId)
- val unusedApps: Set<Pair<String, UserHandle>> = hibernatedApps + revokedApps
- if (unusedApps.isNotEmpty()) {
- showUnusedAppsNotification(unusedApps.size, sessionId)
- if (SdkLevel.isAtLeastT() &&
- revokedApps.isNotEmpty() &&
- getSystemService(SafetyCenterManager::class.java)!!.isSafetyCenterEnabled) {
- setUnusedAppsReviewNeeded(this@HibernationJobService, true)
- rescanAndPushDataToSafetyCenter(
- this@HibernationJobService,
+ val appsToHibernate = getAppsToHibernate(this@HibernationJobService)
+ var hibernatedApps: Set<Pair<String, UserHandle>> = emptySet()
+ if (isHibernationEnabled()) {
+ val hibernationController =
+ HibernationController(
+ this@HibernationJobService,
+ getUnusedThresholdMs(),
+ hibernationTargetsPreSApps()
+ )
+ hibernatedApps = hibernationController.hibernateApps(appsToHibernate)
+ }
+ val revokedApps =
+ revokeAppPermissions(appsToHibernate, this@HibernationJobService, sessionId)
+ val unusedApps: Set<Pair<String, UserHandle>> = hibernatedApps + revokedApps
+ if (unusedApps.isNotEmpty()) {
+ showUnusedAppsNotification(
+ unusedApps.size,
sessionId,
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
- .build())
+ Process.myUserHandle()
+ )
+ if (
+ SdkLevel.isAtLeastT() &&
+ revokedApps.isNotEmpty() &&
+ getSystemService(SafetyCenterManager::class.java)!!
+ .isSafetyCenterEnabled
+ ) {
+ setUnusedAppsReviewNeeded(this@HibernationJobService, true)
+ rescanAndPushDataToSafetyCenter(
+ this@HibernationJobService,
+ sessionId,
+ SafetyEvent.Builder(
+ SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
+ )
+ .build()
+ )
+ }
}
+ } catch (e: Exception) {
+ DumpableLog.e(LOG_TAG, "Failed to auto-revoke permissions", e)
}
- } catch (e: Exception) {
- DumpableLog.e(LOG_TAG, "Failed to auto-revoke permissions", e)
+ jobFinished(params, false)
}
- jobFinished(params, false)
- }
return true
}
- private suspend fun showUnusedAppsNotification(numUnused: Int, sessionId: Long) {
+ private fun showUnusedAppsNotification(numUnused: Int, sessionId: Long, user: UserHandle) {
val notificationManager = getSystemService(NotificationManager::class.java)!!
- val permissionReminderChannel = NotificationChannel(
- Constants.PERMISSION_REMINDER_CHANNEL_ID, getString(R.string.permission_reminders),
- NotificationManager.IMPORTANCE_LOW)
+ val permissionReminderChannel =
+ NotificationChannel(
+ Constants.PERMISSION_REMINDER_CHANNEL_ID,
+ getString(R.string.permission_reminders),
+ NotificationManager.IMPORTANCE_LOW
+ )
notificationManager.createNotificationChannel(permissionReminderChannel)
var notifTitle: String
var notifContent: String
if (isHibernationEnabled()) {
- notifTitle = StringUtils.getIcuPluralsString(this,
- R.string.unused_apps_notification_title, numUnused)
+ notifTitle =
+ StringUtils.getIcuPluralsString(
+ this,
+ R.string.unused_apps_notification_title,
+ numUnused
+ )
notifContent = getString(R.string.unused_apps_notification_content)
} else {
notifTitle = getString(R.string.auto_revoke_permission_notification_title)
@@ -881,16 +982,25 @@ class HibernationJobService : JobService() {
}
// Notification won't appear on TV, because notifications are considered distruptive on TV
- val b = Notification.Builder(this, Constants.PERMISSION_REMINDER_CHANNEL_ID)
- .setContentTitle(notifTitle)
- .setContentText(notifContent)
- .setStyle(Notification.BigTextStyle().bigText(notifContent))
- .setColor(getColor(android.R.color.system_notification_accent_color))
- .setAutoCancel(true)
- .setContentIntent(makeUnusedAppsIntent(this, sessionId))
+ val b =
+ Notification.Builder(this, Constants.PERMISSION_REMINDER_CHANNEL_ID)
+ .setContentTitle(notifTitle)
+ .setContentText(notifContent)
+ .setStyle(Notification.BigTextStyle().bigText(notifContent))
+ .setColor(getColor(android.R.color.system_notification_accent_color))
+ .setAutoCancel(true)
+ .setContentIntent(makeUnusedAppsIntent(this, sessionId))
val extras = Bundle()
- if (SdkLevel.isAtLeastT() &&
- getSystemService(SafetyCenterManager::class.java)!!.isSafetyCenterEnabled) {
+ if (DeviceUtils.isAuto(this)) {
+ val settingsIcon =
+ KotlinUtils.getSettingsIcon(application, user, applicationContext.packageManager)
+ extras.putBoolean(Constants.NOTIFICATION_EXTRA_USE_LAUNCHER_ICON, false)
+ b.setLargeIcon(settingsIcon)
+ }
+ if (
+ SdkLevel.isAtLeastT() &&
+ getSystemService(SafetyCenterManager::class.java)!!.isSafetyCenterEnabled
+ ) {
val notificationResources = KotlinUtils.getSafetyCenterNotificationResources(this)
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, notificationResources.appLabel)
@@ -902,15 +1012,19 @@ class HibernationJobService : JobService() {
Utils.getSettingsLabelForNotifications(applicationContext.packageManager)?.let {
settingsLabel ->
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, settingsLabel.toString())
- b.setSmallIcon(R.drawable.ic_settings_24dp)
- .addExtras(extras)
+ b.setSmallIcon(R.drawable.ic_settings_24dp).addExtras(extras)
}
}
- notificationManager.notify(HibernationJobService::class.java.simpleName,
- Constants.UNUSED_APPS_NOTIFICATION_ID, b.build())
- // Preload the unused packages
- getUnusedPackages().getInitializedValue()
+ notificationManager.notify(
+ HibernationJobService::class.java.simpleName,
+ Constants.UNUSED_APPS_NOTIFICATION_ID,
+ b.build()
+ )
+ GlobalScope.launch(IPC) {
+ // Preload the unused packages
+ getUnusedPackages().getInitializedValue(staleOk = true)
+ }
}
override fun onStopJob(params: JobParameters?): Boolean {
@@ -926,47 +1040,39 @@ class HibernationJobService : JobService() {
*/
class ExemptServicesLiveData(private val user: UserHandle) :
SmartUpdateMediatorLiveData<Map<String, List<String>>>() {
- private val serviceLiveDatas: List<SmartUpdateMediatorLiveData<Set<String>>> = listOf(
- ServiceLiveData[InputMethod.SERVICE_INTERFACE,
- Manifest.permission.BIND_INPUT_METHOD,
- user],
+ private val serviceLiveDatas: List<SmartUpdateMediatorLiveData<Set<String>>> =
+ listOf(
ServiceLiveData[
- NotificationListenerService.SERVICE_INTERFACE,
- Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE,
- user],
+ InputMethod.SERVICE_INTERFACE, Manifest.permission.BIND_INPUT_METHOD, user],
ServiceLiveData[
- AccessibilityService.SERVICE_INTERFACE,
- Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
- user],
+ NotificationListenerService.SERVICE_INTERFACE,
+ Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE,
+ user],
ServiceLiveData[
- WallpaperService.SERVICE_INTERFACE,
- Manifest.permission.BIND_WALLPAPER,
- user],
+ AccessibilityService.SERVICE_INTERFACE,
+ Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
+ user],
ServiceLiveData[
- VoiceInteractionService.SERVICE_INTERFACE,
- Manifest.permission.BIND_VOICE_INTERACTION,
- user],
+ WallpaperService.SERVICE_INTERFACE, Manifest.permission.BIND_WALLPAPER, user],
ServiceLiveData[
- PrintService.SERVICE_INTERFACE,
- Manifest.permission.BIND_PRINT_SERVICE,
- user],
+ VoiceInteractionService.SERVICE_INTERFACE,
+ Manifest.permission.BIND_VOICE_INTERACTION,
+ user],
ServiceLiveData[
- DreamService.SERVICE_INTERFACE,
- Manifest.permission.BIND_DREAM_SERVICE,
- user],
+ PrintService.SERVICE_INTERFACE, Manifest.permission.BIND_PRINT_SERVICE, user],
ServiceLiveData[
- AutofillService.SERVICE_INTERFACE,
- Manifest.permission.BIND_AUTOFILL_SERVICE,
- user],
+ DreamService.SERVICE_INTERFACE, Manifest.permission.BIND_DREAM_SERVICE, user],
ServiceLiveData[
- DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE,
- Manifest.permission.BIND_DEVICE_ADMIN,
- user],
+ AutofillService.SERVICE_INTERFACE, Manifest.permission.BIND_AUTOFILL_SERVICE, user],
+ ServiceLiveData[
+ DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE,
+ Manifest.permission.BIND_DEVICE_ADMIN,
+ user],
BroadcastReceiverLiveData[
- DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
- Manifest.permission.BIND_DEVICE_ADMIN,
- user]
- )
+ DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+ Manifest.permission.BIND_DEVICE_ADMIN,
+ user]
+ )
init {
serviceLiveDatas.forEach { addSource(it) { update() } }
@@ -978,8 +1084,9 @@ class ExemptServicesLiveData(private val user: UserHandle) :
serviceLiveDatas.forEach { serviceLD ->
serviceLD.value!!.forEach { packageName ->
- pksToServices.getOrPut(packageName, { mutableListOf() })
- .add((serviceLD as? HasIntentAction)?.intentAction ?: "???")
+ pksToServices
+ .getOrPut(packageName, { mutableListOf() })
+ .add((serviceLD as? HasIntentAction)?.intentAction ?: "???")
}
}
@@ -999,23 +1106,26 @@ class ExemptServicesLiveData(private val user: UserHandle) :
}
}
-/**
- * Live data for whether the hibernation feature is enabled or not.
- */
-object HibernationEnabledLiveData :
- MutableLiveData<Boolean>() {
+/** Live data for whether the hibernation feature is enabled or not. */
+object HibernationEnabledLiveData : MutableLiveData<Boolean>() {
init {
- postValue(SdkLevel.isAtLeastS() &&
- DeviceConfig.getBoolean(NAMESPACE_APP_HIBERNATION,
- Utils.PROPERTY_APP_HIBERNATION_ENABLED, true /* defaultValue */))
+ postValue(
+ SdkLevel.isAtLeastS() &&
+ DeviceConfig.getBoolean(
+ NAMESPACE_APP_HIBERNATION,
+ Utils.PROPERTY_APP_HIBERNATION_ENABLED,
+ true /* defaultValue */
+ )
+ )
DeviceConfig.addOnPropertiesChangedListener(
NAMESPACE_APP_HIBERNATION,
PermissionControllerApplication.get().mainExecutor,
{ properties ->
for (key in properties.keyset) {
if (key == Utils.PROPERTY_APP_HIBERNATION_ENABLED) {
- value = SdkLevel.isAtLeastS() &&
- properties.getBoolean(key, true /* defaultValue */)
+ value =
+ SdkLevel.isAtLeastS() &&
+ properties.getBoolean(key, true /* defaultValue */)
break
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING
index 16ee9b47d..69a8f74be 100644
--- a/PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/hibernation/TEST_MAPPING
@@ -5,6 +5,9 @@
"options": [
{
"include-filter": "android.hibernation.cts.AppHibernationIntegrationTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/hibernation/v31/HibernationController.kt b/PermissionController/src/com/android/permissioncontroller/hibernation/v31/HibernationController.kt
index f4dfe233a..e81c7a207 100644
--- a/PermissionController/src/com/android/permissioncontroller/hibernation/v31/HibernationController.kt
+++ b/PermissionController/src/com/android/permissioncontroller/hibernation/v31/HibernationController.kt
@@ -25,11 +25,10 @@ import android.os.Build
import android.os.UserHandle
import androidx.annotation.RequiresApi
import com.android.permissioncontroller.DumpableLog
+import com.android.permissioncontroller.permission.data.HibernatedPackagesLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
-/**
- * Hibernation controller that handles modifying hibernation state.
- */
+/** Hibernation controller that handles modifying hibernation state. */
@RequiresApi(Build.VERSION_CODES.S)
class HibernationController(
private val context: Context,
@@ -61,8 +60,7 @@ class HibernationController(
if (hibernationManager.isHibernatingForUser(pkg.packageName)) {
continue
}
- if (!targetsPreS &&
- pkg.targetSdkVersion < Build.VERSION_CODES.S) {
+ if (!targetsPreS && pkg.targetSdkVersion < Build.VERSION_CODES.S) {
// Only apps targeting S or above can be truly hibernated.
continue
}
@@ -80,8 +78,10 @@ class HibernationController(
context.getSystemService(APP_HIBERNATION_SERVICE) as AppHibernationManager
val globallyHibernatedApps = mutableSetOf<String>()
for ((pkgName, _) in hibernatedApps) {
- if (globallyHibernatedApps.contains(pkgName) ||
- hibernationManager.isHibernatingGlobally(pkgName)) {
+ if (
+ globallyHibernatedApps.contains(pkgName) ||
+ hibernationManager.isHibernatingGlobally(pkgName)
+ ) {
continue
}
@@ -94,10 +94,15 @@ class HibernationController(
hibernationManager.setHibernatingGlobally(pkgName, true)
globallyHibernatedApps.add(pkgName)
}
+ if (hibernatedApps.isNotEmpty()) {
+ HibernatedPackagesLiveData.update()
+ }
if (DEBUG_HIBERNATION) {
- DumpableLog.i(LOG_TAG,
+ DumpableLog.i(
+ LOG_TAG,
"Done hibernating apps $hibernatedApps \n " +
- "Globally hibernating apps $globallyHibernatedApps")
+ "Globally hibernating apps $globallyHibernatedApps"
+ )
}
return hibernatedApps
diff --git a/PermissionController/src/com/android/permissioncontroller/hibernation/v31/InstallerPackagesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/hibernation/v31/InstallerPackagesLiveData.kt
index f1a19294a..ebe57ec36 100644
--- a/PermissionController/src/com/android/permissioncontroller/hibernation/v31/InstallerPackagesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/hibernation/v31/InstallerPackagesLiveData.kt
@@ -27,17 +27,13 @@ import com.android.permissioncontroller.permission.data.DataRepositoryForPackage
import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
import kotlinx.coroutines.Job
-/**
- * Packages that are the installer of record for some package on the device.
- */
+/** Packages that are the installer of record for some package on the device. */
@RequiresApi(Build.VERSION_CODES.S)
-class InstallerPackagesLiveData(private val user: UserHandle)
- : SmartAsyncMediatorLiveData<Set<String>>() {
+class InstallerPackagesLiveData(private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<Set<String>>() {
init {
- addSource(AllPackageInfosLiveData) {
- update()
- }
+ addSource(AllPackageInfosLiveData) { update() }
}
override suspend fun loadDataAndPostValue(job: Job) {
diff --git a/PermissionController/src/com/android/permissioncontroller/incident/ConfirmationActivity.java b/PermissionController/src/com/android/permissioncontroller/incident/ConfirmationActivity.java
index 0a8196524..c4a02eda4 100644
--- a/PermissionController/src/com/android/permissioncontroller/incident/ConfirmationActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/incident/ConfirmationActivity.java
@@ -16,7 +16,6 @@
package com.android.permissioncontroller.incident;
-import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -38,15 +37,20 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.activity.ComponentActivity;
+
import com.android.modules.utils.build.SdkLevel;
+import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.incident.wear.ConfirmationActivityWearViewHandler;
import java.util.ArrayList;
/**
* Confirmation dialog for approving an incident or bug report for sharing off the device.
*/
-public class ConfirmationActivity extends Activity implements OnClickListener, OnDismissListener {
+public class ConfirmationActivity extends ComponentActivity implements OnClickListener,
+ OnDismissListener {
private static final String TAG = "ConfirmationActivity";
/**
@@ -107,7 +111,16 @@ public class ConfirmationActivity extends Activity implements OnClickListener, O
// since we can't get proper approval. (Zero-length images or reasons means that
// we will proceed with the imageless consent dialog).
final IncidentManager incidentManager = getSystemService(IncidentManager.class);
- incidentManager.denyReport(getIntent().getData());
+ incidentManager.denyReport(uri);
+
+ if (DeviceUtils.isWear(this)) {
+ ConfirmationActivityWearViewHandler viewHandler =
+ new ConfirmationActivityWearViewHandler(this, incidentManager);
+ setContentView(viewHandler.createView());
+ viewHandler.updateViewModel(true, getString(R.string.incident_report_dialog_title),
+ getString(R.string.incident_report_error_dialog_text, appLabel), uri);
+ return;
+ }
// Show a message to the user saying... nevermind.
new AlertDialog.Builder(this)
@@ -125,6 +138,22 @@ public class ConfirmationActivity extends Activity implements OnClickListener, O
}
+ final String message = getString(R.string.incident_report_dialog_text,
+ appLabel,
+ formatting.getDate(pending.getTimestamp()),
+ formatting.getTime(pending.getTimestamp()),
+ appLabel);
+
+ if (DeviceUtils.isWear(this)) {
+ ConfirmationActivityWearViewHandler viewHandler =
+ new ConfirmationActivityWearViewHandler(this,
+ getSystemService(IncidentManager.class));
+ setContentView(viewHandler.createView());
+ viewHandler.updateViewModel(false, getString(R.string.incident_report_dialog_title),
+ message, uri);
+ return;
+ }
+
final View content = getLayoutInflater().inflate(R.layout.incident_confirmation,
null);
@@ -162,11 +191,6 @@ public class ConfirmationActivity extends Activity implements OnClickListener, O
reasonTextView.setText(spannable);
}
- final String message = getString(R.string.incident_report_dialog_text,
- appLabel,
- formatting.getDate(pending.getTimestamp()),
- formatting.getTime(pending.getTimestamp()),
- appLabel);
((TextView) content.findViewById(R.id.message)).setText(message);
final ArrayList<Drawable> images = details.getImages();
diff --git a/PermissionController/src/com/android/permissioncontroller/incident/PendingList.java b/PermissionController/src/com/android/permissioncontroller/incident/PendingList.java
index dead300d7..7efb89849 100644
--- a/PermissionController/src/com/android/permissioncontroller/incident/PendingList.java
+++ b/PermissionController/src/com/android/permissioncontroller/incident/PendingList.java
@@ -40,7 +40,7 @@ import java.util.Set;
/**
* Represents the current list of pending records.
*/
-class PendingList {
+public class PendingList {
private static final String TAG = "PermissionController.incident";
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/incident/wear/ConfirmationActivityWearViewHandler.java b/PermissionController/src/com/android/permissioncontroller/incident/wear/ConfirmationActivityWearViewHandler.java
new file mode 100644
index 000000000..272a87960
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/incident/wear/ConfirmationActivityWearViewHandler.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 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.incident.wear;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.IncidentManager;
+import android.view.View;
+
+import com.android.permissioncontroller.incident.PendingList;
+
+import kotlin.Unit;
+
+/**
+ * Wear-specific view handler for the confirmation activity.
+ */
+public class ConfirmationActivityWearViewHandler {
+
+ private final Activity mActivity;
+ private final IncidentManager mIncidentManager;
+ private WearConfirmationActivityViewModel mViewModel;
+
+ public ConfirmationActivityWearViewHandler(Activity activity, IncidentManager incidentManager) {
+ mActivity = activity;
+ mIncidentManager = incidentManager;
+ }
+
+ /**
+ * Creates and returns the view hierarchy that is managed by this view
+ * handler. This must be called before {@link #updateViewModel}.
+ */
+ public View createView() {
+ WearConfirmationActivityViewModelFactory factory =
+ new WearConfirmationActivityViewModelFactory();
+ mViewModel = factory.create(
+ WearConfirmationActivityViewModel.class);
+
+ return WearConfirmationScreenKt.createView(mActivity, mViewModel);
+ }
+
+ /**
+ * Updates the wear confirmation activity view model to reflect the specified state.
+ */
+ public void updateViewModel(boolean isDenyView, String dialogTitle, String message, Uri uri) {
+ mViewModel.getShowDialogLiveData().setValue(true);
+ mViewModel.getShowDenyReportLiveData().setValue(isDenyView);
+ WearConfirmationActivityViewModel.ContentArgs args =
+ new WearConfirmationActivityViewModel.ContentArgs(
+ dialogTitle,
+ message,
+ () -> {
+ mIncidentManager.denyReport(uri);
+ mActivity.finish();
+ return Unit.INSTANCE;
+ },
+ () -> {
+ mIncidentManager.approveReport(uri);
+ PendingList.getInstance().updateState(mActivity, 0);
+ mActivity.finish();
+ return Unit.INSTANCE;
+ },
+ () -> {
+ mIncidentManager.denyReport(uri);
+ PendingList.getInstance().updateState(mActivity, 0);
+ mActivity.finish();
+ return Unit.INSTANCE;
+ }
+ );
+ mViewModel.getContentArgsLiveData().setValue(args);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationActivityViewModel.kt b/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationActivityViewModel.kt
new file mode 100644
index 000000000..aecb6222b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationActivityViewModel.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.incident.wear
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+
+class WearConfirmationActivityViewModel : ViewModel() {
+ /** A livedata which stores whether the incident/bug report dialog is visible. */
+ val showDialogLiveData = MutableLiveData<Boolean>()
+
+ /** A livedata which stores to whether to show the screen for deny report */
+ val showDenyReportLiveData = MutableLiveData<Boolean>()
+
+ /** A livedata which stores arguments for a confirmation section. */
+ var contentArgsLiveData = MutableLiveData<ContentArgs>()
+
+ data class ContentArgs(
+ // stores the incident/bug report title
+ val title: String,
+ // stores the incident/bug report message body
+ val message: String,
+ // this is a button shows only in a denied incident/bug report dialog
+ val onDenyClick: () -> Unit,
+ val onOkClick: () -> Unit,
+ val onCancelClick: () -> Unit,
+ )
+
+ init {
+ showDialogLiveData.value = false
+ showDenyReportLiveData.value = false
+ contentArgsLiveData.value = null
+ }
+}
+
+/** Factory for a WearConfirmationActivityViewModel */
+class WearConfirmationActivityViewModelFactory : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return WearConfirmationActivityViewModel() as T
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt b/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt
new file mode 100644
index 000000000..8e58d48d9
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 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.incident.wear
+
+import android.app.Activity
+import android.view.View
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import androidx.wear.compose.foundation.lazy.ScalingLazyListState
+import androidx.wear.compose.material.CircularProgressIndicator
+import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.SingleButtonAlertDialog
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
+
+@Composable
+fun WearConfirmationScreen(viewModel: WearConfirmationActivityViewModel) {
+ // Wear screen doesn't show incident/bug report's optional reasons and images.
+ val showDialog = viewModel.showDialogLiveData.observeAsState(false)
+ val showDenyReport = viewModel.showDenyReportLiveData.observeAsState(false)
+ val contentArgs = viewModel.contentArgsLiveData.observeAsState(null)
+ var isLoading by rememberSaveable { mutableStateOf(true) }
+
+ Box(modifier = Modifier.fillMaxSize()) {
+ if (isLoading) {
+ CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
+ } else {
+ if (showDenyReport.value) {
+ contentArgs.value?.let {
+ SingleButtonAlertDialog(
+ showDialog = showDialog.value,
+ title = it.title,
+ message = it.message,
+ onButtonClick = it.onDenyClick,
+ scalingLazyListState = ScalingLazyListState(0)
+ )
+ }
+ return
+ }
+ contentArgs.value?.let {
+ AlertDialog(
+ showDialog = showDialog.value,
+ title = it.title,
+ message = it.message,
+ onOKButtonClick = it.onOkClick,
+ onCancelButtonClick = it.onCancelClick,
+ scalingLazyListState = ScalingLazyListState(0)
+ )
+ }
+ }
+ }
+
+ if (isLoading && showDialog.value) {
+ isLoading = false
+ }
+}
+
+fun createView(activity: Activity, viewModel: WearConfirmationActivityViewModel): View {
+ return ComposeView(activity).apply {
+ setContent { WearPermissionTheme { WearConfirmationScreen(viewModel) } }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING
index b65eb6710..38d46fe76 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING
@@ -22,7 +22,7 @@
"include-filter": "android.permission.cts.PlatformPermissionGroupMappingTest"
},
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
},
@@ -30,7 +30,7 @@
"name": "CtsHibernationTestCases",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
@@ -58,19 +58,77 @@
"include-filter": "android.permission.cts.PlatformPermissionGroupMappingTest"
},
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
},
{
"name": "CtsHibernationTestCases[com.google.android.permission.apex]",
"options": [
- // TODO(b/238677038): This test currently fails on R base image
{
- "exclude-filter": "android.hibernation.cts.AutoRevokeTest#testUnusedApp_uninstallApp"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsHibernationTestCases"
+ },
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.BackgroundPermissionsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.LocationAccessCheckTest"
+ },
+ {
+ "include-filter": "android.permission.cts.NotificationListenerCheckTest"
},
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "include-filter": "android.permission.cts.OneTimePermissionTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PermissionControllerTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PlatformPermissionGroupMappingTest"
+ }
+ ]
+ }
+ ],
+ "mainline-postsubmit": [
+ {
+ "name": "CtsPermissionTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.BackgroundPermissionsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.LocationAccessCheckTest"
+ },
+ {
+ "include-filter": "android.permission.cts.NotificationListenerCheckTest"
+ },
+ {
+ "include-filter": "android.permission.cts.OneTimePermissionTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PermissionControllerTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PlatformPermissionGroupMappingTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsHibernationTestCases[com.google.android.permission.apex]",
+ "options": [
+ // TODO(b/238677038): This test currently fails on R base image
+ {
+ "exclude-filter": "android.hibernation.cts.AutoRevokeTest#testUnusedApp_uninstallApp"
}
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java b/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java
deleted file mode 100644
index 637eb5fc4..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2023 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.permission.compat;
-
-import android.text.Layout;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.method.LinkMovementMethod;
-import android.text.method.Touch;
-import android.view.MotionEvent;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-
-/**
- * Fixes the issue that links can be triggered for touches outside of line bounds for
- * {@link LinkMovementMethod}.
- * <p>
- * This is based on the fix in ag/22301465.
- */
-public class LinkMovementMethodCompat extends LinkMovementMethod {
- @Override
- public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer,
- @NonNull MotionEvent event) {
- int action = event.getAction();
-
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
- int x = (int) event.getX();
- int y = (int) event.getY();
-
- x -= widget.getTotalPaddingLeft();
- y -= widget.getTotalPaddingTop();
-
- x += widget.getScrollX();
- y += widget.getScrollY();
-
- Layout layout = widget.getLayout();
- boolean isOutOfLineBounds;
- if (y < 0 || y > layout.getHeight()) {
- isOutOfLineBounds = true;
- } else {
- int line = layout.getLineForVertical(y);
- isOutOfLineBounds = x < layout.getLineLeft(line) || x > layout.getLineRight(line);
- }
-
- if (isOutOfLineBounds) {
- Selection.removeSelection(buffer);
-
- // return LinkMovementMethod.super.onTouchEvent(widget, buffer, event);
- return Touch.onTouchEvent(widget, buffer, event);
- }
- }
-
- return super.onTouchEvent(widget, buffer, event);
- }
-
- /**
- * @return a {@link LinkMovementMethodCompat} instance
- */
- @NonNull
- public static LinkMovementMethodCompat getInstance() {
- if (sInstance == null) {
- sInstance = new LinkMovementMethodCompat();
- }
-
- return sInstance;
- }
-
- private static LinkMovementMethodCompat sInstance;
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/AllPackageInfosLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/AllPackageInfosLiveData.kt
index c2655ecff..b3a28eefe 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/AllPackageInfosLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/AllPackageInfosLiveData.kt
@@ -20,9 +20,7 @@ import android.os.UserHandle
import com.android.permissioncontroller.permission.data.AllPackageInfosLiveData.addSource
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
-/**
- * A LiveData which tracks the PackageInfos of all of the packages in the system, for all users.
- */
+/** A LiveData which tracks the PackageInfos of all of the packages in the system, for all users. */
object AllPackageInfosLiveData :
SmartUpdateMediatorLiveData<Map<UserHandle, List<LightPackageInfo>>>() {
@@ -30,9 +28,7 @@ object AllPackageInfosLiveData :
private val userPackageInfos = mutableMapOf<UserHandle, List<LightPackageInfo>>()
init {
- addSource(UsersLiveData) {
- update()
- }
+ addSource(UsersLiveData) { update() }
}
override fun onUpdate() {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/AppOpLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/AppOpLiveData.kt
index 5a0abeaa1..1e44f16bd 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/AppOpLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/AppOpLiveData.kt
@@ -27,12 +27,12 @@ import com.android.permissioncontroller.PermissionControllerApplication
* @param packageName The name of the package
* @param op The name of the appop
* @param uid The uid of the package
- *
* @see AppOpsManager
*/
// TODO eugenesusla: observe appops
// TODO eugenesusla: use for external storage
-class AppOpLiveData private constructor(
+class AppOpLiveData
+private constructor(
private val app: Application,
private val packageName: String,
private val op: String,
@@ -52,13 +52,18 @@ class AppOpLiveData private constructor(
/**
* Repository for AppOpLiveData.
- * <p> Key value is a triple of string package name, string appop, and
- * package uid, value is its corresponding LiveData.
+ *
+ * <p> Key value is a triple of string package name, string appop, and package uid, value is its
+ * corresponding LiveData.
*/
companion object : DataRepository<Triple<String, String, Int>, AppOpLiveData>() {
override fun newValue(key: Triple<String, String, Int>): AppOpLiveData {
- return AppOpLiveData(PermissionControllerApplication.get(),
- key.first, key.second, key.third)
+ return AppOpLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second,
+ key.third
+ )
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt
index b9d2d237a..b17098a13 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt
@@ -32,17 +32,17 @@ import com.android.permissioncontroller.permission.model.livedatatypes.LightPack
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermGroupInfo
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermInfo
import com.android.permissioncontroller.permission.model.livedatatypes.PermState
-import com.android.permissioncontroller.permission.utils.PermissionMapping.isPlatformPermissionGroup
import com.android.permissioncontroller.permission.utils.LocationUtils
+import com.android.permissioncontroller.permission.utils.PermissionMapping.isPlatformPermissionGroup
import com.android.permissioncontroller.permission.utils.Utils
import kotlinx.coroutines.Job
/**
* A LiveData representing UI properties of an App Permission Group:
* <ul>
- * <li>shouldShow</li>
- * <li>isSystem</li>
- * <li>isGranted</li>
+ * <li>shouldShow</li>
+ * <li>isSystem</li>
+ * <li>isGranted</li>
* </ul>
*
* @param app The current application
@@ -50,7 +50,8 @@ import kotlinx.coroutines.Job
* @param permGroupName The name of the permission group whose permissions are observed
* @param user The user of the package
*/
-class AppPermGroupUiInfoLiveData private constructor(
+class AppPermGroupUiInfoLiveData
+private constructor(
private val app: Application,
private val packageName: String,
private val permGroupName: String,
@@ -62,23 +63,22 @@ class AppPermGroupUiInfoLiveData private constructor(
private val permGroupLiveData = PermGroupLiveData[permGroupName]
private val permissionStateLiveData = PermStateLiveData[packageName, permGroupName, user]
private val isStorage = permGroupName == STORAGE
+ private val isHealth = Utils.isHealthPermissionGroup(permGroupName)
init {
- isSpecialLocation = LocationUtils.isLocationGroupAndProvider(app,
- permGroupName, packageName) ||
- LocationUtils.isLocationGroupAndControllerExtraPackage(app, permGroupName, packageName)
+ isSpecialLocation =
+ LocationUtils.isLocationGroupAndProvider(app, permGroupName, packageName) ||
+ LocationUtils.isLocationGroupAndControllerExtraPackage(
+ app,
+ permGroupName,
+ packageName
+ )
- addSource(packageInfoLiveData) {
- update()
- }
+ addSource(packageInfoLiveData) { update() }
- addSource(permGroupLiveData) {
- update()
- }
+ addSource(permGroupLiveData) { update() }
- addSource(permissionStateLiveData) {
- update()
- }
+ addSource(permissionStateLiveData) { update() }
}
override suspend fun loadDataAndPostValue(job: Job) {
@@ -90,27 +90,36 @@ class AppPermGroupUiInfoLiveData private constructor(
val permissionState = permissionStateLiveData.value
if (packageInfo == null || permissionGroup == null || permissionState == null) {
- if (packageInfoLiveData.isInitialized && permGroupLiveData.isInitialized &&
- permissionStateLiveData.isInitialized) {
+ if (
+ packageInfoLiveData.isInitialized &&
+ permGroupLiveData.isInitialized &&
+ permissionStateLiveData.isInitialized
+ ) {
invalidateSingle(Triple(packageName, permGroupName, user))
postValue(null)
}
return
}
- postValue(getAppPermGroupUiInfo(packageInfo, permissionGroup.groupInfo,
- permissionGroup.permissionInfos, permissionState))
+ postValue(
+ getAppPermGroupUiInfo(
+ packageInfo,
+ permissionGroup.groupInfo,
+ permissionGroup.permissionInfos,
+ permissionState
+ )
+ )
}
/**
- * Determines if the UI should show a given package, if that package is a system app, and
- * if it has granted permissions in this LiveData's permission group.
+ * Determines if the UI should show a given package, if that package is a system app, and if it
+ * has granted permissions in this LiveData's permission group.
*
* @param packageInfo The PackageInfo of the package we wish to examine
* @param groupInfo The groupInfo of the permission group we wish to examine
* @param allPermInfos All of the PermissionInfos in the permission group
- * @param permissionState The flags and grant state for all permissions in the permission
- * group that this package requests
+ * @param permissionState The flags and grant state for all permissions in the permission group
+ * that this package requests
*/
private fun getAppPermGroupUiInfo(
packageInfo: LightPackageInfo,
@@ -125,9 +134,11 @@ class AppPermGroupUiInfoLiveData private constructor(
val requestedPermissionInfos =
allPermInfos.filter { permissionState.containsKey(it.key) }.values
- val shouldShow = packageInfo.enabled &&
- isGrantableAndNotLegacyPlatform(packageInfo, groupInfo, requestedPermissionInfos) &&
- (!isStorage || Utils.shouldShowStorage(packageInfo))
+ val shouldShow =
+ packageInfo.enabled &&
+ isGrantableAndNotLegacyPlatform(packageInfo, groupInfo, requestedPermissionInfos) &&
+ (!isStorage || Utils.shouldShowStorage(packageInfo)) &&
+ (!isHealth || Utils.shouldShowHealthPermission(packageInfo, groupInfo.name))
val isSystemApp = !isUserSensitive(permissionState)
@@ -145,19 +156,17 @@ class AppPermGroupUiInfoLiveData private constructor(
*
* @param packageInfo The PackageInfo of the package we are examining
* @param groupInfo The Permission Group Info of the permission group we are examining
- * @param permissionInfos The LightPermInfos corresponding to the permissions in the
- * permission group that this package requests
- *
+ * @param permissionInfos The LightPermInfos corresponding to the permissions in the permission
+ * group that this package requests
* @return True if the app permission group is grantable, and is not a legacy system permission,
- * false otherwise.
+ * false otherwise.
*/
private fun isGrantableAndNotLegacyPlatform(
packageInfo: LightPackageInfo,
groupInfo: LightPermGroupInfo,
permissionInfos: Collection<LightPermInfo>
): Boolean {
- if (groupInfo.packageName == Utils.OS_PKG &&
- !isPlatformPermissionGroup(groupInfo.name)) {
+ if (groupInfo.packageName == Utils.OS_PKG && !isPlatformPermissionGroup(groupInfo.name)) {
return false
}
@@ -165,8 +174,9 @@ class AppPermGroupUiInfoLiveData private constructor(
var hasPreRuntime = false
for (permissionInfo in permissionInfos) {
- if (permissionInfo.protectionFlags and
- PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY == 0) {
+ if (
+ permissionInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY == 0
+ ) {
hasPreRuntime = true
}
@@ -175,8 +185,9 @@ class AppPermGroupUiInfoLiveData private constructor(
}
}
- val isGrantingAllowed = (!packageInfo.isInstantApp || hasInstantPerm) &&
- (packageInfo.targetSdkVersion >= Build.VERSION_CODES.M || hasPreRuntime)
+ val isGrantingAllowed =
+ (!packageInfo.isInstantApp || hasInstantPerm) &&
+ (packageInfo.targetSdkVersion >= Build.VERSION_CODES.M || hasPreRuntime)
if (!isGrantingAllowed) {
return false
}
@@ -189,10 +200,9 @@ class AppPermGroupUiInfoLiveData private constructor(
* then it is considered a system app, and hidden in the UI by default.
*
* @param permissionState The permission flags and grant state corresponding to the permissions
- * in this group requested by a given app
- *
+ * in this group requested by a given app
* @return Whether or not this package requests a user sensitive permission in the given
- * permission group
+ * permission group
*/
private fun isUserSensitive(permissionState: Map<String, PermState>): Boolean {
if (!isPlatformPermissionGroup(permGroupName)) {
@@ -202,10 +212,12 @@ class AppPermGroupUiInfoLiveData private constructor(
for (permissionName in permissionState.keys) {
val flags = permissionState[permissionName]?.permFlags ?: return true
val granted = permissionState[permissionName]?.granted ?: return true
- if ((granted &&
+ if (
+ (granted &&
flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED != 0) ||
- (!granted &&
- flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED != 0)) {
+ (!granted &&
+ flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED != 0)
+ ) {
return true
}
}
@@ -216,32 +228,30 @@ class AppPermGroupUiInfoLiveData private constructor(
* Determines if the app permission group is user set
*
* @param permissionState The permission flags and grant state corresponding to the permissions
- * in this group requested by a given app
- *
+ * in this group requested by a given app
* @return Whether or not any of the permissions in this group have been set or fixed by the
- * user
+ * user
*/
private fun isUserSet(permissionState: Map<String, PermState>): Boolean {
- val flagMask = PackageManager.FLAG_PERMISSION_USER_SET or
- PackageManager.FLAG_PERMISSION_USER_FIXED
+ val flagMask =
+ PackageManager.FLAG_PERMISSION_USER_SET or PackageManager.FLAG_PERMISSION_USER_FIXED
return permissionState.any { (it.value.permFlags and flagMask) != 0 }
}
/**
- * Determines if this app permission group is granted, granted in foreground only, or denied.
- * It is granted if it either requests no background permissions, and has at least one requested
- * permission that is granted, or has granted at least one requested background permission.
- * It is granted in foreground only if it has at least one non-background permission granted,
- * and has denied all requested background permissions. It is denied if all requested
- * permissions are denied.
+ * Determines if this app permission group is granted, granted in foreground only, or denied. It
+ * is granted if it either requests no background permissions, and has at least one requested
+ * permission that is granted, or has granted at least one requested background permission. It
+ * is granted in foreground only if it has at least one non-background permission granted, and
+ * has denied all requested background permissions. It is denied if all requested permissions
+ * are denied.
*
* @param permissionState The permission flags and grant state corresponding to the permissions
- * in this group requested by a given app
- * @param allPermInfos All of the permissionInfos in the permission group of this app
- * permission group
- *
+ * in this group requested by a given app
+ * @param allPermInfos All of the permissionInfos in the permission group of this app permission
+ * group
* @return The int code corresponding to the app permission group state, either allowed, allowed
- * in foreground only, or denied.
+ * in foreground only, or denied.
*/
private fun getGrantedIncludingBackground(
permissionState: Map<String, PermState>,
@@ -260,36 +270,46 @@ class AppPermGroupUiInfoLiveData private constructor(
val permInfo = allPermInfos[permName] ?: continue
permInfo.backgroundPermission?.let { backgroundPerm ->
hasPermWithBackground = true
- if (permissionState[backgroundPerm]?.granted == true &&
+ if (
+ permissionState[backgroundPerm]?.granted == true &&
(permissionState[backgroundPerm]!!.permFlags and
- PackageManager.FLAG_PERMISSION_ONE_TIME == 0) &&
- specialLocationState != false) {
+ PackageManager.FLAG_PERMISSION_ONE_TIME == 0) &&
+ specialLocationState != false
+ ) {
return PermGrantState.PERMS_ALLOWED_ALWAYS
}
}
- isUserFixed = isUserFixed ||
+ isUserFixed =
+ isUserFixed ||
permState.permFlags and PackageManager.FLAG_PERMISSION_USER_FIXED != 0
}
// isOneTime indicates whether all granted permissions in permission states are one-time
// permissions
- val isOneTime = permissionState.any {
- it.value.permFlags and PackageManager.FLAG_PERMISSION_ONE_TIME != 0 } &&
+ val isOneTime =
+ permissionState.any {
+ it.value.permFlags and PackageManager.FLAG_PERMISSION_ONE_TIME != 0
+ } &&
!permissionState.any {
it.value.permFlags and PackageManager.FLAG_PERMISSION_ONE_TIME == 0 &&
- it.value.granted }
+ it.value.granted
+ }
val supportsRuntime = pkg.targetSdkVersion >= Build.VERSION_CODES.M
- val anyAllowed = specialLocationState ?: permissionState.any { (_, state) ->
- state.granted || (supportsRuntime &&
- (state.permFlags and PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0)
- }
+ val anyAllowed =
+ specialLocationState
+ ?: permissionState.any { (_, state) ->
+ state.granted ||
+ (supportsRuntime &&
+ (state.permFlags and PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) !=
+ 0)
+ }
val onlySelectedPhotosGranted =
permissionState.containsKey(READ_MEDIA_VISUAL_USER_SELECTED) &&
- permissionState.all { (permName, state) ->
- (permName == READ_MEDIA_VISUAL_USER_SELECTED && state.granted) ||
- (permName != READ_MEDIA_VISUAL_USER_SELECTED && !state.granted)
- }
+ permissionState.all { (permName, state) ->
+ (permName == READ_MEDIA_VISUAL_USER_SELECTED && state.granted) ||
+ (permName != READ_MEDIA_VISUAL_USER_SELECTED && !state.granted)
+ }
if (anyAllowed && (hasPermWithBackground || shouldShowAsForegroundGroup())) {
return if (isOneTime) {
PermGrantState.PERMS_ASK
@@ -323,32 +343,38 @@ class AppPermGroupUiInfoLiveData private constructor(
}
// The permission of the extra location controller package is determined by the
// status of the controller package itself.
- if (LocationUtils.isLocationGroupAndControllerExtraPackage(userContext,
- permGroupName, packageName)) {
+ if (
+ LocationUtils.isLocationGroupAndControllerExtraPackage(
+ userContext,
+ permGroupName,
+ packageName
+ )
+ ) {
return LocationUtils.isExtraLocationControllerPackageEnabled(userContext)
}
return null
}
private fun isFullFilesAccessGranted(pkg: LightPackageInfo): Boolean {
- val packageState = if (!FullStoragePermissionAppsLiveData.isStale) {
- val fullStoragePackages = FullStoragePermissionAppsLiveData.value ?: return false
- fullStoragePackages.find {
- it.packageName == packageName && it.user == user
- } ?: return false
- } else {
- val appOpsManager = Utils.getUserContext(app, UserHandle.getUserHandleForUid(pkg.uid))
- .getSystemService(AppOpsManager::class.java)!!
- FullStoragePermissionAppsLiveData.getFullStorageStateForPackage(
- appOpsManager, pkg) ?: return false
- }
+ val packageState =
+ if (!FullStoragePermissionAppsLiveData.isStale) {
+ val fullStoragePackages = FullStoragePermissionAppsLiveData.value ?: return false
+ fullStoragePackages.find { it.packageName == packageName && it.user == user }
+ ?: return false
+ } else {
+ val appOpsManager =
+ Utils.getUserContext(app, UserHandle.getUserHandleForUid(pkg.uid))
+ .getSystemService(AppOpsManager::class.java)!!
+ FullStoragePermissionAppsLiveData.getFullStorageStateForPackage(appOpsManager, pkg)
+ ?: return false
+ }
return !packageState.isLegacy && packageState.isGranted
}
// TODO moltmann-team: Actually change mic/camera to be a foreground only permission
private fun shouldShowAsForegroundGroup(): Boolean {
return permGroupName.equals(Manifest.permission_group.CAMERA) ||
- permGroupName.equals(Manifest.permission_group.MICROPHONE)
+ permGroupName.equals(Manifest.permission_group.MICROPHONE)
}
override fun onLocationStateChange(enabled: Boolean) {
@@ -373,15 +399,19 @@ class AppPermGroupUiInfoLiveData private constructor(
/**
* Repository for AppPermGroupUiInfoLiveDatas.
- * <p> Key value is a triple of string package name, string permission group name, and UserHandle,
- * value is its corresponding LiveData.
+ *
+ * <p> Key value is a triple of string package name, string permission group name, and
+ * UserHandle, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<Triple<String, String, UserHandle>,
- AppPermGroupUiInfoLiveData>() {
- override fun newValue(key: Triple<String, String, UserHandle>):
- AppPermGroupUiInfoLiveData {
- return AppPermGroupUiInfoLiveData(PermissionControllerApplication.get(),
- key.first, key.second, key.third)
+ companion object :
+ DataRepositoryForPackage<Triple<String, String, UserHandle>, AppPermGroupUiInfoLiveData>() {
+ override fun newValue(key: Triple<String, String, UserHandle>): AppPermGroupUiInfoLiveData {
+ return AppPermGroupUiInfoLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second,
+ key.third
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveData.kt
index b55c736ad..fac901a04 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveData.kt
@@ -22,12 +22,12 @@ import android.content.res.Resources.ID_NULL
import android.os.UserHandle
import android.util.Log
import com.android.permissioncontroller.PermissionControllerApplication
+import java.io.FileNotFoundException
import kotlinx.coroutines.Job
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParser.END_DOCUMENT
import org.xmlpull.v1.XmlPullParser.END_TAG
import org.xmlpull.v1.XmlPullParser.START_TAG
-import java.io.FileNotFoundException
private const val MANIFEST_FILE_NAME = "AndroidManifest.xml"
private const val MANIFEST_TAG = "manifest"
@@ -43,7 +43,8 @@ private const val LABEL_ATTR = "label"
* <p>Obviously the resource is found in the package, hence needs to be loaded via a Resources
* object created for this package.
*/
-class AttributionLabelLiveData private constructor(
+class AttributionLabelLiveData
+private constructor(
private val app: Application,
private val attributionTag: String?,
private val packageName: String,
@@ -61,14 +62,15 @@ class AttributionLabelLiveData private constructor(
return
}
- val pkgContext = try {
- app.createPackageContextAsUser(packageName, 0, user)
- } catch (e: NameNotFoundException) {
- Log.e(LOG_TAG, "Cannot find $packageName for $user")
+ val pkgContext =
+ try {
+ app.createPackageContextAsUser(packageName, 0, user)
+ } catch (e: NameNotFoundException) {
+ Log.e(LOG_TAG, "Cannot find $packageName for $user")
- postValue(null)
- return
- }
+ postValue(null)
+ return
+ }
// TODO (moltmann): Read this from PackageInfo once available
var cookie = 0
@@ -76,11 +78,12 @@ class AttributionLabelLiveData private constructor(
// Some resources have multiple "AndroidManifest.xml" loaded and hence we need
// to find the right one
cookie++
- val parser = try {
- pkgContext.assets.openXmlResourceParser(cookie, MANIFEST_FILE_NAME)
- } catch (e: FileNotFoundException) {
- break
- }
+ val parser =
+ try {
+ pkgContext.assets.openXmlResourceParser(cookie, MANIFEST_FILE_NAME)
+ } catch (e: FileNotFoundException) {
+ break
+ }
try {
do {
@@ -109,8 +112,9 @@ class AttributionLabelLiveData private constructor(
}
if (parser.getAttributeValue(ANDROID_NS, TAG_ATTR) == attributionTag) {
- postValue(parser.getAttributeResourceValue(ANDROID_NS, LABEL_ATTR,
- ID_NULL))
+ postValue(
+ parser.getAttributeResourceValue(ANDROID_NS, LABEL_ATTR, ID_NULL)
+ )
return
} else {
parser.skipTag()
@@ -125,9 +129,7 @@ class AttributionLabelLiveData private constructor(
postValue(null)
}
- /**
- * Skip tag parser is currently pointing to (including all tags nested in it)
- */
+ /** Skip tag parser is currently pointing to (including all tags nested in it) */
private fun XmlPullParser.skipTag() {
var depth = 1
while (depth != 0) {
@@ -158,18 +160,25 @@ class AttributionLabelLiveData private constructor(
/**
* Repository for AttributionLiveData.
+ *
* <p> Key value is a pair of string attribution tag, string package name, user handle, value is
* its corresponding LiveData.
*/
- companion object : DataRepository<Triple<String?, String, UserHandle>,
- AttributionLabelLiveData>() {
+ companion object :
+ DataRepository<Triple<String?, String, UserHandle>, AttributionLabelLiveData>() {
override fun newValue(key: Triple<String?, String, UserHandle>): AttributionLabelLiveData {
- return AttributionLabelLiveData(PermissionControllerApplication.get(),
- key.first, key.second, key.third)
+ return AttributionLabelLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second,
+ key.third
+ )
}
- operator fun get(attributionTag: String?, packageName: String, user: UserHandle):
- AttributionLabelLiveData =
- get(Triple(attributionTag, packageName, user))
+ operator fun get(
+ attributionTag: String?,
+ packageName: String,
+ user: UserHandle
+ ): AttributionLabelLiveData = get(Triple(attributionTag, packageName, user))
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/AutoRevokedPackagesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/AutoRevokedPackagesLiveData.kt
index 70f857afb..2e6fab44d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/AutoRevokedPackagesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/AutoRevokedPackagesLiveData.kt
@@ -21,8 +21,8 @@ import android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED
import android.os.Build
import android.os.UserHandle
import android.util.Log
-import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
@@ -34,15 +34,13 @@ import kotlinx.coroutines.launch
*
* ```(packageName, user) -> [groupName]```
*/
-object AutoRevokedPackagesLiveData
- : SmartAsyncMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() {
+object AutoRevokedPackagesLiveData :
+ SmartAsyncMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() {
private val LOG_TAG = AutoRevokedPackagesLiveData::class.java.simpleName
init {
- addSource(AllPackageInfosLiveData) {
- update()
- }
+ addSource(AllPackageInfosLiveData) { update() }
}
private val permStateLiveDatas =
@@ -66,7 +64,8 @@ object AutoRevokedPackagesLiveData
for ((idx, requestedPerm) in pkg.requestedPermissions.withIndex()) {
val group =
PermissionMapping.getGroupOfPlatformPermission(requestedPerm) ?: continue
- val granted = (pkg.requestedPermissionsFlags[idx] and
+ val granted =
+ (pkg.requestedPermissionsFlags[idx] and
PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
if (pkg.targetSdkVersion < Build.VERSION_CODES.M || !granted) {
pkgGroups.add(Triple(pkg.packageName, group, user))
@@ -85,7 +84,6 @@ object AutoRevokedPackagesLiveData
private fun observePermStateLiveDatas(packageGroups: Set<Triple<String, String, UserHandle>>) {
GlobalScope.launch(Main.immediate) {
-
val (toAdd, toRemove) =
KotlinUtils.getMapAndListDifferences(packageGroups, permStateLiveDatas)
@@ -118,7 +116,8 @@ object AutoRevokedPackagesLiveData
} else if (permState != null) {
for ((_, state) in permState) {
if (state.permFlags and FLAG_PERMISSION_AUTO_REVOKED != 0) {
- packageAutoRevokedPermsList.getOrPut(packageUser) { mutableSetOf() }
+ packageAutoRevokedPermsList
+ .getOrPut(packageUser) { mutableSetOf() }
.add(packagePermGroup.second)
added = true
break
@@ -142,8 +141,7 @@ object AutoRevokedPackagesLiveData
}
private fun postCopyOfMap() {
- val autoRevokedCopy =
- mutableMapOf<Pair<String, UserHandle>, Set<String>>()
+ val autoRevokedCopy = mutableMapOf<Pair<String, UserHandle>, Set<String>>()
for ((userPackage, permGroups) in packageAutoRevokedPermsList) {
autoRevokedCopy[userPackage] = permGroups.toSet()
}
@@ -155,9 +153,7 @@ object AutoRevokedPackagesLiveData
private val autoRevokedPackagesSetLiveData =
object : SmartUpdateMediatorLiveData<Set<Pair<String, UserHandle>>>() {
init {
- addSource(AutoRevokedPackagesLiveData) {
- update()
- }
+ addSource(AutoRevokedPackagesLiveData) { update() }
}
override fun onUpdate() {
@@ -168,4 +164,4 @@ private val autoRevokedPackagesSetLiveData =
}
}
-val unusedAutoRevokePackagesLiveData = UnusedPackagesLiveData(autoRevokedPackagesSetLiveData) \ No newline at end of file
+val unusedAutoRevokePackagesLiveData = UnusedPackagesLiveData(autoRevokedPackagesSetLiveData)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/BroadcastReceiverLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/BroadcastReceiverLiveData.kt
index 0a296d977..e14a02115 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/BroadcastReceiverLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/BroadcastReceiverLiveData.kt
@@ -41,9 +41,10 @@ class BroadcastReceiverLiveData(
override val intentAction: String,
private val permission: String,
private val user: UserHandle
-) : SmartAsyncMediatorLiveData<Set<String>>(),
- PackageBroadcastReceiver.PackageBroadcastListener,
- HasIntentAction {
+) :
+ SmartAsyncMediatorLiveData<Set<String>>(),
+ PackageBroadcastReceiver.PackageBroadcastListener,
+ HasIntentAction {
private val name = intentAction.substringAfterLast(".")
@@ -51,9 +52,7 @@ class BroadcastReceiverLiveData(
init {
if (intentAction == DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED) {
- addSource(enabledDeviceAdminsLiveDataLiveData) {
- updateAsync()
- }
+ addSource(enabledDeviceAdminsLiveDataLiveData) { updateAsync() }
}
}
@@ -65,15 +64,20 @@ class BroadcastReceiverLiveData(
if (job.isCancelled) {
return
}
- if (intentAction == DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED &&
- !enabledDeviceAdminsLiveDataLiveData.isInitialized) {
+ if (
+ intentAction == DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED &&
+ !enabledDeviceAdminsLiveDataLiveData.isInitialized
+ ) {
return
}
- val packageNames = getUserContext(app, user).packageManager
+ val packageNames =
+ getUserContext(app, user)
+ .packageManager
.queryBroadcastReceivers(
- Intent(intentAction),
- PackageManager.GET_RECEIVERS or PackageManager.GET_META_DATA)
+ Intent(intentAction),
+ PackageManager.GET_RECEIVERS or PackageManager.GET_META_DATA
+ )
.mapNotNull { resolveInfo ->
if (resolveInfo?.activityInfo?.permission != permission) {
return@mapNotNull null
@@ -81,17 +85,22 @@ class BroadcastReceiverLiveData(
val packageName = resolveInfo.activityInfo?.packageName
if (!isReceiverEnabled(packageName)) {
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG,
- "Not exempting $packageName - not an active $name " +
- "for u${user.identifier}")
+ DumpableLog.i(
+ LOG_TAG,
+ "Not exempting $packageName - not an active $name " +
+ "for u${user.identifier}"
+ )
}
return@mapNotNull null
}
packageName
- }.toSet()
+ }
+ .toSet()
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG,
- "Detected ${intentAction.substringAfterLast(".")}s: $packageNames")
+ DumpableLog.i(
+ LOG_TAG,
+ "Detected ${intentAction.substringAfterLast(".")}s: $packageNames"
+ )
}
postValue(packageNames)
@@ -127,13 +136,17 @@ class BroadcastReceiverLiveData(
* <p> Key value is a (string intent action, required permission, user) triple, value is its
* corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<Triple<String, String, UserHandle>,
- BroadcastReceiverLiveData>() {
+ companion object :
+ DataRepositoryForPackage<Triple<String, String, UserHandle>, BroadcastReceiverLiveData>() {
private const val LOG_TAG = "BroadcastReceiverLiveData"
override fun newValue(key: Triple<String, String, UserHandle>): BroadcastReceiverLiveData {
- return BroadcastReceiverLiveData(PermissionControllerApplication.get(),
- key.first, key.second, key.third)
+ return BroadcastReceiverLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second,
+ key.third
+ )
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/CarrierPrivilegedStatusLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/CarrierPrivilegedStatusLiveData.kt
index fae7f223b..d84db741c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/CarrierPrivilegedStatusLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/CarrierPrivilegedStatusLiveData.kt
@@ -26,10 +26,9 @@ import com.android.permissioncontroller.PermissionControllerApplication
* @param app The current application
* @param packageName The name of the package
*/
-class CarrierPrivilegedStatusLiveData private constructor(
- private val app: Application,
- private val packageName: String
-) : SmartUpdateMediatorLiveData<Int>() {
+class CarrierPrivilegedStatusLiveData
+private constructor(private val app: Application, private val packageName: String) :
+ SmartUpdateMediatorLiveData<Int>() {
private val telephonyManager = app.getSystemService(TelephonyManager::class.java)!!
@@ -44,13 +43,13 @@ class CarrierPrivilegedStatusLiveData private constructor(
/**
* Repository for [CarrierPrivilegedStatusLiveData].
+ *
* <p> Key value is a package name, value is its corresponding LiveData of
* [android.telephony.Annotation.CarrierPrivilegeStatus]
*/
- companion object
- : DataRepository<String, CarrierPrivilegedStatusLiveData>() {
+ companion object : DataRepository<String, CarrierPrivilegedStatusLiveData>() {
override fun newValue(key: String): CarrierPrivilegedStatusLiveData {
return CarrierPrivilegedStatusLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt
index cb44c0a27..757472464 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt
@@ -24,7 +24,6 @@ import com.android.permissioncontroller.permission.utils.PermissionMapping
/**
* A class which tracks the names of all custom permission groups in the system, including
* non-grouped runtime permissions, the UNDEFINED group, and any group not defined by the system.
- *
*/
object CustomPermGroupNamesLiveData : SmartUpdateMediatorLiveData<List<String>>() {
@@ -32,9 +31,7 @@ object CustomPermGroupNamesLiveData : SmartUpdateMediatorLiveData<List<String>>(
private val packagesLiveData = AllPackageInfosLiveData
init {
- addSource(packagesLiveData) {
- update()
- }
+ addSource(packagesLiveData) { update() }
}
override fun onUpdate() {
@@ -49,15 +46,19 @@ object CustomPermGroupNamesLiveData : SmartUpdateMediatorLiveData<List<String>>(
packageInfo.permissions.let {
for (permission in it) {
// We care only about installed runtime permissions.
- if (permission.protection != PermissionInfo.PROTECTION_DANGEROUS ||
- permission.flags and PermissionInfo.FLAG_INSTALLED == 0) {
+ if (
+ permission.protection != PermissionInfo.PROTECTION_DANGEROUS ||
+ permission.flags and PermissionInfo.FLAG_INSTALLED == 0
+ ) {
continue
}
// If this permission is already in a group, no more work to do
- if (groupNames.contains(permission.group) ||
- platformGroupNames.contains(permission.group) ||
- groupNames.contains(permission.name)) {
+ if (
+ groupNames.contains(permission.group) ||
+ platformGroupNames.contains(permission.group) ||
+ groupNames.contains(permission.name)
+ ) {
continue
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/DataRepository.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/DataRepository.kt
index 5cb91f5c5..9a826deb1 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/DataRepository.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/DataRepository.kt
@@ -22,6 +22,8 @@ import android.content.res.Configuration
import androidx.annotation.GuardedBy
import androidx.annotation.MainThread
import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.utils.ContextCompat
+import com.android.permissioncontroller.permission.utils.KotlinUtils
import java.util.concurrent.TimeUnit
/**
@@ -39,18 +41,16 @@ abstract class DataRepository<K, V : DataRepository.InactiveTimekeeper> : Compon
private val TIME_THRESHOLD_ALL_NANOS: Long = 0
protected val lock = Any()
- @GuardedBy("lock")
- protected val data = mutableMapOf<K, V>()
+ @GuardedBy("lock") protected val data = mutableMapOf<K, V>()
- /**
- * Whether or not this data repository has been registered as a component callback yet
- */
+ /** Whether or not this data repository has been registered as a component callback yet */
private var registered = false
- /**
- * Whether or not this device is a low-RAM device.
- */
- private var isLowMemoryDevice = PermissionControllerApplication.get().getSystemService(
- ActivityManager::class.java)?.isLowRamDevice ?: false
+ /** Whether or not this device is a low-RAM device. */
+ private var isLowMemoryDevice =
+ PermissionControllerApplication.get()
+ .getSystemService(ActivityManager::class.java)
+ ?.isLowRamDevice
+ ?: false
init {
PermissionControllerApplication.get().registerComponentCallbacks(this)
@@ -60,7 +60,6 @@ abstract class DataRepository<K, V : DataRepository.InactiveTimekeeper> : Compon
* Get a value from this repository, creating it if needed
*
* @param key The key associated with the desired Value
- *
* @return The cached or newly created Value for the given Key
*/
operator fun get(key: K): V {
@@ -73,11 +72,9 @@ abstract class DataRepository<K, V : DataRepository.InactiveTimekeeper> : Compon
* Generate a new value type from the given data
*
* @param key Information about this value object, used to instantiate it
- *
* @return The generated Value
*/
- @MainThread
- protected abstract fun newValue(key: K): V
+ @MainThread protected abstract fun newValue(key: K): V
/**
* Remove LiveData objects with no observer based on the severity of the memory pressure. If
@@ -91,15 +88,18 @@ abstract class DataRepository<K, V : DataRepository.InactiveTimekeeper> : Compon
return
}
- trimInactiveData(threshold = when (level) {
- ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> TIME_THRESHOLD_LAX_NANOS
- ComponentCallbacks2.TRIM_MEMORY_MODERATE -> TIME_THRESHOLD_TIGHT_NANOS
- ComponentCallbacks2.TRIM_MEMORY_COMPLETE -> TIME_THRESHOLD_ALL_NANOS
- ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE -> TIME_THRESHOLD_LAX_NANOS
- ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW -> TIME_THRESHOLD_TIGHT_NANOS
- ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> TIME_THRESHOLD_ALL_NANOS
- else -> return
- })
+ trimInactiveData(
+ threshold =
+ when (level) {
+ ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> TIME_THRESHOLD_LAX_NANOS
+ ComponentCallbacks2.TRIM_MEMORY_MODERATE -> TIME_THRESHOLD_TIGHT_NANOS
+ ComponentCallbacks2.TRIM_MEMORY_COMPLETE -> TIME_THRESHOLD_ALL_NANOS
+ ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE -> TIME_THRESHOLD_LAX_NANOS
+ ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW -> TIME_THRESHOLD_TIGHT_NANOS
+ ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> TIME_THRESHOLD_ALL_NANOS
+ else -> return
+ }
+ )
}
override fun onLowMemory() {
@@ -111,9 +111,7 @@ abstract class DataRepository<K, V : DataRepository.InactiveTimekeeper> : Compon
}
fun invalidateSingle(key: K) {
- synchronized(lock) {
- data.remove(key)
- }
+ synchronized(lock) { data.remove(key) }
}
private fun trimInactiveData(threshold: Long) {
@@ -127,8 +125,8 @@ abstract class DataRepository<K, V : DataRepository.InactiveTimekeeper> : Compon
}
/**
- * Interface which describes an object which can track how long it has been inactive, and if
- * it has any observers.
+ * Interface which describes an object which can track how long it has been inactive, and if it
+ * has any observers.
*/
interface InactiveTimekeeper {
@@ -156,8 +154,8 @@ abstract class DataRepository<K, V : DataRepository.InactiveTimekeeper> : Compon
* invalidating all values tied to a package. Expects key to be a pair or triple, with the package
* name as the first value of the key.
*/
-abstract class DataRepositoryForPackage<K, V : DataRepository.InactiveTimekeeper>
- : DataRepository<K, V>() {
+abstract class DataRepositoryForPackage<K, V : DataRepository.InactiveTimekeeper> :
+ DataRepository<K, V>() {
/**
* Invalidates every value with the packageName in the key.
@@ -167,7 +165,11 @@ abstract class DataRepositoryForPackage<K, V : DataRepository.InactiveTimekeeper
fun invalidateAllForPackage(packageName: String) {
synchronized(lock) {
for (key in data.keys.toSet()) {
- if (key is Pair<*, *> || key is Triple<*, *, *> && key.first == packageName) {
+ if (
+ key is Pair<*, *> ||
+ key is Triple<*, *, *> ||
+ key is KotlinUtils.Quadruple<*, *, *, *> && key.first == packageName
+ ) {
data.remove(key)
}
}
@@ -176,8 +178,28 @@ abstract class DataRepositoryForPackage<K, V : DataRepository.InactiveTimekeeper
}
/**
- * A convenience to retrieve data from a repository with a composite key
+ * A DataRepository to cache LiveData for a device. The device can be a primary device with default
+ * deviceId in the key, or a remote device with virtual device Id in the key. It uses deviceId to
+ * initialize a new LiveData instance. Note: the virtual device Id should always be the last element
+ * in the composite key.
*/
+abstract class DataRepositoryForDevice<K, V : DataRepository.InactiveTimekeeper> :
+ DataRepositoryForPackage<K, V>() {
+
+ @MainThread protected abstract fun newValue(key: K, deviceId: Int): V
+
+ override fun newValue(key: K): V {
+ return newValue(key, ContextCompat.DEVICE_ID_DEFAULT)
+ }
+
+ fun getWithDeviceId(key: K, deviceId: Int): V {
+ synchronized(lock) {
+ return data.getOrPut(key) { newValue(key, deviceId) }
+ }
+ }
+}
+
+/** A convenience to retrieve data from a repository with a composite key */
operator fun <K1, K2, V : DataRepository.InactiveTimekeeper> DataRepository<Pair<K1, K2>, V>.get(
k1: K1,
k2: K2
@@ -185,14 +207,77 @@ operator fun <K1, K2, V : DataRepository.InactiveTimekeeper> DataRepository<Pair
return get(k1 to k2)
}
+/** A convenience to retrieve data from a repository with a composite key */
+operator fun <K1, K2, K3, V : DataRepository.InactiveTimekeeper> DataRepository<
+ Triple<K1, K2, K3>, V
+>
+ .get(k1: K1, k2: K2, k3: K3): V {
+ return get(Triple(k1, k2, k3))
+}
+
+/** A getter on DataRepositoryForDevice to retrieve a LiveData for a device. */
+operator fun <K1, K2, V : DataRepository.InactiveTimekeeper> DataRepositoryForDevice<
+ Triple<K1, K2, Int>, V
+>
+ .get(k1: K1, k2: K2, deviceId: Int): V {
+ return getWithDeviceId(Triple(k1, k2, deviceId), deviceId)
+}
+
/**
- * A convenience to retrieve data from a repository with a composite key
+ * A collection of getters on DataRepositoryForDevice to conveniently retrieve a LiveData for tbe
+ * primary device. The param can be in the format of Pair<K1, K2> or [K1, K2]
*/
-operator fun <K1, K2, K3, V : DataRepository.InactiveTimekeeper>
- DataRepository<Triple<K1, K2, K3>, V>.get(
- k1: K1,
- k2: K2,
- k3: K3
- ): V {
- return get(Triple(k1, k2, k3))
+operator fun <K1, K2, V : DataRepository.InactiveTimekeeper> DataRepositoryForDevice<
+ Triple<K1, K2, Int>, V
+>
+ .get(
+ k1: K1,
+ k2: K2,
+): V {
+ return getWithDeviceId(
+ Triple(k1, k2, ContextCompat.DEVICE_ID_DEFAULT),
+ ContextCompat.DEVICE_ID_DEFAULT
+ )
+}
+
+operator fun <K1, K2, V : DataRepository.InactiveTimekeeper> DataRepositoryForDevice<
+ Triple<K1, K2, Int>, V
+>
+ .get(key: Pair<K1, K2>): V {
+ return getWithDeviceId(
+ Triple(key.first, key.second, ContextCompat.DEVICE_ID_DEFAULT),
+ ContextCompat.DEVICE_ID_DEFAULT
+ )
+}
+
+/** A getter on DataRepositoryForDevice to retrieve a LiveData for a device. */
+operator fun <K1, K2, K3, V : DataRepository.InactiveTimekeeper> DataRepositoryForDevice<
+ KotlinUtils.Quadruple<K1, K2, K3, Int>, V
+>
+ .get(k1: K1, k2: K2, k3: K3, deviceId: Int): V {
+ return getWithDeviceId(KotlinUtils.Quadruple(k1, k2, k3, deviceId), deviceId)
+}
+
+/**
+ * A collection of getters on DataRepositoryForDevice to conveniently retrieve a LiveData for tbe
+ * primary device. The param can be in the format of Triple<K1, K2, K3> or [K1, K2, K3]
+ */
+operator fun <K1, K2, K3, V : DataRepository.InactiveTimekeeper> DataRepositoryForDevice<
+ KotlinUtils.Quadruple<K1, K2, K3, Int>, V
+>
+ .get(k1: K1, k2: K2, k3: K3): V {
+ return getWithDeviceId(
+ KotlinUtils.Quadruple(k1, k2, k3, ContextCompat.DEVICE_ID_DEFAULT),
+ ContextCompat.DEVICE_ID_DEFAULT
+ )
+}
+
+operator fun <K1, K2, K3, V : DataRepository.InactiveTimekeeper> DataRepositoryForDevice<
+ KotlinUtils.Quadruple<K1, K2, K3, Int>, V
+>
+ .get(key: Triple<K1, K2, K3>): V {
+ return getWithDeviceId(
+ KotlinUtils.Quadruple(key.first, key.second, key.third, ContextCompat.DEVICE_ID_DEFAULT),
+ ContextCompat.DEVICE_ID_DEFAULT
+ )
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/DisabledPrintServicesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/DisabledPrintServicesLiveData.kt
index 3abb20564..4d9c2574b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/DisabledPrintServicesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/DisabledPrintServicesLiveData.kt
@@ -30,28 +30,26 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param user The user the services should be determined for
*/
-class DisabledPrintServicesLiveData(
- private val app: Application,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<List<String>>() {
+class DisabledPrintServicesLiveData(private val app: Application, private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<List<String>>() {
override suspend fun loadDataAndPostValue(job: Job) {
if (job.isCancelled) {
return
}
- val packageNames = Settings.Secure.getString(
- Utils.getUserContext(app, user).contentResolver, SETTING)
+ val packageNames =
+ Settings.Secure.getString(Utils.getUserContext(app, user).contentResolver, SETTING)
?.split(":")
?.map { pkgOrComponent ->
if ('/' in pkgOrComponent) {
- ComponentName.unflattenFromString(pkgOrComponent)
- ?.packageName
- ?: pkgOrComponent
+ ComponentName.unflattenFromString(pkgOrComponent)?.packageName
+ ?: pkgOrComponent
} else {
pkgOrComponent
}
- } ?: emptyList()
+ }
+ ?: emptyList()
postValue(packageNames)
}
@@ -61,8 +59,7 @@ class DisabledPrintServicesLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- DisabledPrintServicesLiveData>() {
+ companion object : DataRepositoryForPackage<UserHandle, DisabledPrintServicesLiveData>() {
/* Settings.Secure.DISABLED_PRINT_SERVICES */
private const val SETTING = "disabled_print_services"
@@ -70,4 +67,4 @@ class DisabledPrintServicesLiveData(
return DisabledPrintServicesLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledAccessibilityServicesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledAccessibilityServicesLiveData.kt
index 2b1391a98..9717d949c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledAccessibilityServicesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledAccessibilityServicesLiveData.kt
@@ -21,8 +21,8 @@ import android.app.Application
import android.os.UserHandle
import android.view.accessibility.AccessibilityManager
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.componentInfo
import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.componentInfo
import kotlinx.coroutines.Job
/**
@@ -42,7 +42,8 @@ class EnabledAccessibilityServicesLiveData(
return
}
- val packageNames = Utils.getUserContext(app, user)
+ val packageNames =
+ Utils.getUserContext(app, user)
.getSystemService(AccessibilityManager::class.java)!!
.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
.map { info: AccessibilityServiceInfo ->
@@ -62,10 +63,10 @@ class EnabledAccessibilityServicesLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- EnabledAccessibilityServicesLiveData>() {
+ companion object :
+ DataRepositoryForPackage<UserHandle, EnabledAccessibilityServicesLiveData>() {
override fun newValue(key: UserHandle): EnabledAccessibilityServicesLiveData {
return EnabledAccessibilityServicesLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDeviceAdminsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDeviceAdminsLiveData.kt
index 60dcf59b0..eebcac06f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDeviceAdminsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDeviceAdminsLiveData.kt
@@ -29,17 +29,16 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param user The user the services should be determined for
*/
-class EnabledDeviceAdminsLiveData(
- private val app: Application,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<List<String>>() {
+class EnabledDeviceAdminsLiveData(private val app: Application, private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<List<String>>() {
override suspend fun loadDataAndPostValue(job: Job) {
if (job.isCancelled) {
return
}
- val packageNames = Utils.getUserContext(app, user)
+ val packageNames =
+ Utils.getUserContext(app, user)
.getSystemService(DevicePolicyManager::class.java)!!
.activeAdmins
?.map { component -> component.packageName }
@@ -53,10 +52,9 @@ class EnabledDeviceAdminsLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- EnabledDeviceAdminsLiveData>() {
+ companion object : DataRepositoryForPackage<UserHandle, EnabledDeviceAdminsLiveData>() {
override fun newValue(key: UserHandle): EnabledDeviceAdminsLiveData {
return EnabledDeviceAdminsLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDreamServicesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDreamServicesLiveData.kt
index 200384aab..9b8554e80 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDreamServicesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledDreamServicesLiveData.kt
@@ -30,28 +30,26 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param user The user the services should be determined for
*/
-class EnabledDreamServicesLiveData(
- private val app: Application,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<List<String>>() {
+class EnabledDreamServicesLiveData(private val app: Application, private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<List<String>>() {
override suspend fun loadDataAndPostValue(job: Job) {
if (job.isCancelled) {
return
}
- val packageNames = Settings.Secure.getString(
- Utils.getUserContext(app, user).contentResolver, SETTING)
+ val packageNames =
+ Settings.Secure.getString(Utils.getUserContext(app, user).contentResolver, SETTING)
?.split(",")
?.map { pkgOrComponent ->
if ('/' in pkgOrComponent) {
- ComponentName.unflattenFromString(pkgOrComponent)
- ?.packageName
- ?: pkgOrComponent
+ ComponentName.unflattenFromString(pkgOrComponent)?.packageName
+ ?: pkgOrComponent
} else {
pkgOrComponent
}
- } ?: emptyList()
+ }
+ ?: emptyList()
postValue(packageNames)
}
@@ -61,8 +59,7 @@ class EnabledDreamServicesLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- EnabledDreamServicesLiveData>() {
+ companion object : DataRepositoryForPackage<UserHandle, EnabledDreamServicesLiveData>() {
/* Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
private const val SETTING = "enabled_notification_listeners"
@@ -70,4 +67,4 @@ class EnabledDreamServicesLiveData(
return EnabledDreamServicesLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledInputMethodsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledInputMethodsLiveData.kt
index d0d2783ab..e48c432d8 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledInputMethodsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledInputMethodsLiveData.kt
@@ -30,22 +30,19 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param user The user the services should be determined for
*/
-class EnabledInputMethodsLiveData(
- private val app: Application,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<List<String>>() {
+class EnabledInputMethodsLiveData(private val app: Application, private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<List<String>>() {
override suspend fun loadDataAndPostValue(job: Job) {
if (job.isCancelled) {
return
}
- val packageNames = Utils.getUserContext(app, user)
+ val packageNames =
+ Utils.getUserContext(app, user)
.getSystemService(InputMethodManager::class.java)!!
.enabledInputMethodList
- .map { info: InputMethodInfo ->
- info.component.packageName
- }
+ .map { info: InputMethodInfo -> info.component.packageName }
postValue(packageNames)
}
@@ -55,10 +52,9 @@ class EnabledInputMethodsLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- EnabledInputMethodsLiveData>() {
+ companion object : DataRepositoryForPackage<UserHandle, EnabledInputMethodsLiveData>() {
override fun newValue(key: UserHandle): EnabledInputMethodsLiveData {
return EnabledInputMethodsLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledNotificationListenersLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledNotificationListenersLiveData.kt
index f5c5d4bf1..7dd1567e4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledNotificationListenersLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/EnabledNotificationListenersLiveData.kt
@@ -40,20 +40,22 @@ class EnabledNotificationListenersLiveData(
return
}
- val packageNames = Settings.Secure.getString(
- Utils.getUserContext(app, user).contentResolver,
- /* Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
- "enabled_notification_listeners")
+ val packageNames =
+ Settings.Secure.getString(
+ Utils.getUserContext(app, user).contentResolver,
+ /* Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
+ "enabled_notification_listeners"
+ )
?.split(":")
?.map { pkgOrComponent ->
if ('/' in pkgOrComponent) {
- ComponentName.unflattenFromString(pkgOrComponent)
- ?.packageName
- ?: pkgOrComponent
+ ComponentName.unflattenFromString(pkgOrComponent)?.packageName
+ ?: pkgOrComponent
} else {
pkgOrComponent
}
- } ?: emptyList()
+ }
+ ?: emptyList()
postValue(packageNames)
}
@@ -63,10 +65,10 @@ class EnabledNotificationListenersLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- EnabledNotificationListenersLiveData>() {
+ companion object :
+ DataRepositoryForPackage<UserHandle, EnabledNotificationListenersLiveData>() {
override fun newValue(key: UserHandle): EnabledNotificationListenersLiveData {
return EnabledNotificationListenersLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt
index 1471ed15f..513f5fc4e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt
@@ -39,11 +39,12 @@ object ForegroundPermNamesLiveData : SmartAsyncMediatorLiveData<Map<String, List
val systemGroups = PermissionMapping.getPlatformPermissionGroups()
val permMap = mutableMapOf<String, MutableList<String>>()
for (groupName in systemGroups) {
- val permInfos = try {
- Utils.getInstalledRuntimePermissionInfosForGroup(app.packageManager, groupName)
- } catch (e: PackageManager.NameNotFoundException) {
- continue
- }
+ val permInfos =
+ try {
+ Utils.getInstalledRuntimePermissionInfosForGroup(app.packageManager, groupName)
+ } catch (e: PackageManager.NameNotFoundException) {
+ continue
+ }
for (permInfo in permInfos) {
val backgroundPerm: String? = permInfo.backgroundPermission
if (backgroundPerm != null) {
@@ -54,4 +55,4 @@ object ForegroundPermNamesLiveData : SmartAsyncMediatorLiveData<Map<String, List
}
postValue(permMap)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/FullStoragePermissionAppsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/FullStoragePermissionAppsLiveData.kt
index 0b27dbff0..4a2d3b68a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/FullStoragePermissionAppsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/FullStoragePermissionAppsLiveData.kt
@@ -34,14 +34,13 @@ import kotlinx.coroutines.Job
/**
* A liveData which tracks all packages in the system which have full file permissions, as
* represented by the OPSTR_LEGACY_STORAGE app op, not just media-only storage permissions.
- *
*/
object FullStoragePermissionAppsLiveData :
SmartAsyncMediatorLiveData<List<FullStoragePermissionAppsLiveData.FullStoragePackageState>>() {
private val app: Application = PermissionControllerApplication.get()
- private val standardPermGroupsPackagesLiveData = PermGroupsPackagesLiveData.get(
- customGroups = false)
+ private val standardPermGroupsPackagesLiveData =
+ PermGroupsPackagesLiveData.get(customGroups = false)
data class FullStoragePackageState(
val packageName: String,
@@ -51,12 +50,8 @@ object FullStoragePermissionAppsLiveData :
)
init {
- addSource(standardPermGroupsPackagesLiveData) {
- updateAsync()
- }
- addSource(AllPackageInfosLiveData) {
- updateAsync()
- }
+ addSource(standardPermGroupsPackagesLiveData) { updateAsync() }
+ addSource(AllPackageInfosLiveData) { updateAsync() }
}
override suspend fun loadDataAndPostValue(job: Job) {
@@ -65,14 +60,16 @@ object FullStoragePermissionAppsLiveData :
val fullStoragePackages = mutableListOf<FullStoragePackageState>()
for ((user, packageInfoList) in AllPackageInfosLiveData.value ?: emptyMap()) {
- val userPackages = packageInfoList.filter {
- storagePackages.contains(it.packageName to user) ||
- it.requestedPermissions.contains(MANAGE_EXTERNAL_STORAGE)
- }
+ val userPackages =
+ packageInfoList.filter {
+ storagePackages.contains(it.packageName to user) ||
+ it.requestedPermissions.contains(MANAGE_EXTERNAL_STORAGE)
+ }
for (packageInfo in userPackages) {
- fullStoragePackages.add(getFullStorageStateForPackage(appOpsManager,
- packageInfo, user) ?: continue)
+ fullStoragePackages.add(
+ getFullStorageStateForPackage(appOpsManager, packageInfo, user) ?: continue
+ )
}
}
@@ -85,9 +82,8 @@ object FullStoragePermissionAppsLiveData :
* @param appOpsManager The App Ops manager to use, if applicable
* @param packageInfo The package whose state is to be determined
* @param userHandle A preexisting UserHandle object to use. Otherwise, one will be created
- *
* @return the FullStoragePackageState for the package, or null if the package does not request
- * full storage permissions
+ * full storage permissions
*/
fun getFullStorageStateForPackage(
appOpsManager: AppOpsManager,
@@ -97,31 +93,51 @@ object FullStoragePermissionAppsLiveData :
val sdk = packageInfo.targetSdkVersion
val user = userHandle ?: UserHandle.getUserHandleForUid(packageInfo.uid)
if (sdk < Build.VERSION_CODES.P) {
- return FullStoragePackageState(packageInfo.packageName, user,
- isLegacy = true, isGranted = true)
- } else if (sdk <= Build.VERSION_CODES.Q &&
- appOpsManager.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE, packageInfo.uid,
- packageInfo.packageName) == MODE_ALLOWED) {
- return FullStoragePackageState(packageInfo.packageName, user,
- isLegacy = true, isGranted = true)
+ return FullStoragePackageState(
+ packageInfo.packageName,
+ user,
+ isLegacy = true,
+ isGranted = true
+ )
+ } else if (
+ sdk <= Build.VERSION_CODES.Q &&
+ appOpsManager.unsafeCheckOpNoThrow(
+ OPSTR_LEGACY_STORAGE,
+ packageInfo.uid,
+ packageInfo.packageName
+ ) == MODE_ALLOWED
+ ) {
+ return FullStoragePackageState(
+ packageInfo.packageName,
+ user,
+ isLegacy = true,
+ isGranted = true
+ )
}
if (MANAGE_EXTERNAL_STORAGE in packageInfo.requestedPermissions) {
- val mode = appOpsManager.unsafeCheckOpNoThrow(OPSTR_MANAGE_EXTERNAL_STORAGE,
- packageInfo.uid, packageInfo.packageName)
- val granted = mode == MODE_ALLOWED || mode == MODE_FOREGROUND ||
- (mode == MODE_DEFAULT &&
- MANAGE_EXTERNAL_STORAGE in packageInfo.grantedPermissions)
- return FullStoragePackageState(packageInfo.packageName, user,
- isLegacy = false, isGranted = granted)
+ val mode =
+ appOpsManager.unsafeCheckOpNoThrow(
+ OPSTR_MANAGE_EXTERNAL_STORAGE,
+ packageInfo.uid,
+ packageInfo.packageName
+ )
+ val granted =
+ mode == MODE_ALLOWED ||
+ mode == MODE_FOREGROUND ||
+ (mode == MODE_DEFAULT &&
+ MANAGE_EXTERNAL_STORAGE in packageInfo.grantedPermissions)
+ return FullStoragePackageState(
+ packageInfo.packageName,
+ user,
+ isLegacy = false,
+ isGranted = granted
+ )
}
return null
}
- /**
- * Recalculate the LiveData
- * TODO ntmyren: Make livedata properly observe app ops
- */
+ /** Recalculate the LiveData TODO ntmyren: Make livedata properly observe app ops */
fun recalculate() {
updateAsync()
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/HasIntentAction.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/HasIntentAction.kt
index 91557e441..1c0325ec6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/HasIntentAction.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/HasIntentAction.kt
@@ -16,9 +16,7 @@
package com.android.permissioncontroller.permission.data
-/**
- * An interface for classes that have an [Intent] action
- */
+/** An interface for classes that have an [Intent] action */
interface HasIntentAction {
val intentAction: String
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt
index 887998a2e..9fdb8411a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt
@@ -25,17 +25,12 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.utils.Utils.getUserContext
import kotlinx.coroutines.Job
-/**
- * Tracks which packages have been hibernated.
- */
-object HibernatedPackagesLiveData
- : SmartAsyncMediatorLiveData<Set<Pair<String, UserHandle>>>() {
+/** Tracks which packages have been hibernated. */
+object HibernatedPackagesLiveData : SmartAsyncMediatorLiveData<Set<Pair<String, UserHandle>>>() {
private val LOG_TAG = HibernatedPackagesLiveData::class.java.simpleName
init {
- addSource(AllPackageInfosLiveData) {
- update()
- }
+ addSource(AllPackageInfosLiveData) { update() }
}
override suspend fun loadDataAndPostValue(job: Job) {
@@ -57,8 +52,10 @@ object HibernatedPackagesLiveData
hibernatingPackages.add(pkg.packageName to user)
}
} catch (e: Exception) {
- DumpableLog.e(LOG_TAG,
- "Failed to get hibernation state of package: ${pkg.packageName}")
+ DumpableLog.e(
+ LOG_TAG,
+ "Failed to get hibernation state of package: ${pkg.packageName}"
+ )
}
}
}
@@ -69,25 +66,23 @@ object HibernatedPackagesLiveData
}
}
-private val hibernatedOrRevokedPackagesLiveData = object
- : SmartUpdateMediatorLiveData<Set<Pair<String, UserHandle>>>() {
+private val hibernatedOrRevokedPackagesLiveData =
+ object : SmartUpdateMediatorLiveData<Set<Pair<String, UserHandle>>>() {
- init {
- addSource(AutoRevokedPackagesLiveData) {
- update()
- }
- addSource(HibernatedPackagesLiveData) {
- update()
+ init {
+ addSource(AutoRevokedPackagesLiveData) { update() }
+ addSource(HibernatedPackagesLiveData) { update() }
}
- }
- override fun onUpdate() {
- if (!AutoRevokedPackagesLiveData.isInitialized ||
- !HibernatedPackagesLiveData.isInitialized) {
- return
+ override fun onUpdate() {
+ if (
+ !AutoRevokedPackagesLiveData.isInitialized ||
+ !HibernatedPackagesLiveData.isInitialized
+ ) {
+ return
+ }
+ value = AutoRevokedPackagesLiveData.value!!.keys + HibernatedPackagesLiveData.value!!
}
- value = AutoRevokedPackagesLiveData.value!!.keys + HibernatedPackagesLiveData.value!!
}
-}
val unusedHibernatedOrRevokedPackagesLiveData =
- UnusedPackagesLiveData(hibernatedOrRevokedPackagesLiveData) \ No newline at end of file
+ UnusedPackagesLiveData(hibernatedOrRevokedPackagesLiveData)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt
index 606562641..75d965d02 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt
@@ -34,6 +34,7 @@ import com.android.permissioncontroller.hibernation.isPackageHibernationExemptBy
import com.android.permissioncontroller.hibernation.isPackageHibernationExemptByUser
import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData.Companion.NON_RUNTIME_NORMAL_PERMS
import com.android.permissioncontroller.permission.model.livedatatypes.HibernationSettingState
+import com.android.permissioncontroller.permission.service.AUTO_REVOKE_EXEMPT_PERMISSIONS
import kotlinx.coroutines.Job
/**
@@ -43,14 +44,14 @@ import kotlinx.coroutines.Job
* @param packageName The package name whose state we want
* @param user The user for whom we want the package
*/
-class HibernationSettingStateLiveData private constructor(
+class HibernationSettingStateLiveData
+private constructor(
private val app: Application,
private val packageName: String,
private val user: UserHandle
) : SmartAsyncMediatorLiveData<HibernationSettingState>(), AppOpsManager.OnOpChangedListener {
- private val packagePermsLiveData =
- PackagePermissionsLiveData[packageName, user]
+ private val packagePermsLiveData = PackagePermissionsLiveData[packageName, user]
private val packageLiveData = LightPackageInfoLiveData[packageName, user]
private val permStateLiveDatas = mutableMapOf<String, PermStateLiveData>()
private val exemptServicesLiveData = ExemptServicesLiveData[user]
@@ -64,26 +65,19 @@ class HibernationSettingStateLiveData private constructor(
private var gotPastIsSystemExempt: Boolean = false
init {
- addSource(packagePermsLiveData) {
- update()
- }
- addSource(packageLiveData) {
- update()
- }
- addSource(exemptServicesLiveData) {
- update()
- }
- addSource(HibernationEnabledLiveData) {
- update()
- }
- Handler(app.mainLooper).postDelayed({
- logState()
- }, DELAY_MS)
+ addSource(packagePermsLiveData) { update() }
+ addSource(packageLiveData) { update() }
+ addSource(exemptServicesLiveData) { update() }
+ addSource(HibernationEnabledLiveData) { update() }
+ Handler(app.mainLooper).postDelayed({ logState() }, DELAY_MS)
}
override suspend fun loadDataAndPostValue(job: Job) {
- if (!packageLiveData.isInitialized || !packagePermsLiveData.isInitialized ||
- !exemptServicesLiveData.isInitialized) {
+ if (
+ !packageLiveData.isInitialized ||
+ !packagePermsLiveData.isInitialized ||
+ !exemptServicesLiveData.isInitialized
+ ) {
return
}
@@ -103,21 +97,30 @@ class HibernationSettingStateLiveData private constructor(
val exemptBySystem = isPackageHibernationExemptBySystem(packageInfo, user)
val exemptByUser = isPackageHibernationExemptByUser(app, packageInfo)
- val eligibility = when {
- !exemptBySystem && !exemptByUser -> HIBERNATION_ELIGIBILITY_ELIGIBLE
- exemptBySystem -> HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
- else -> HIBERNATION_ELIGIBILITY_EXEMPT_BY_USER
- }
+ val eligibility =
+ when {
+ !exemptBySystem && !exemptByUser -> HIBERNATION_ELIGIBILITY_ELIGIBLE
+ exemptBySystem -> HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
+ else -> HIBERNATION_ELIGIBILITY_EXEMPT_BY_USER
+ }
gotPastIsUserExempt = true
val revocableGroups = mutableListOf<String>()
if (!isPackageHibernationExemptBySystem(packageInfo, user)) {
gotPastIsSystemExempt = true
permStateLiveDatas.forEach { (groupName, liveData) ->
- val default = liveData.value?.any { (_, permState) ->
- permState.permFlags and (FLAG_PERMISSION_GRANTED_BY_DEFAULT or
- FLAG_PERMISSION_GRANTED_BY_ROLE) != 0
- } ?: false
- if (!default) {
+ val default =
+ liveData.value?.any { (_, permState) ->
+ permState.permFlags and
+ (FLAG_PERMISSION_GRANTED_BY_DEFAULT or
+ FLAG_PERMISSION_GRANTED_BY_ROLE) != 0
+ }
+ ?: false
+ val allExempt =
+ liveData.value?.all { (permName, _) ->
+ permName in AUTO_REVOKE_EXEMPT_PERMISSIONS
+ }
+ ?: false
+ if (!default && !allExempt) {
revocableGroups.add(groupName)
}
}
@@ -148,29 +151,45 @@ class HibernationSettingStateLiveData private constructor(
if (!isStale) {
return
}
- Log.i(LOG_TAG, "overall state: isStale:$isStale, isInitialized:$isInitialized, " +
+ Log.i(
+ LOG_TAG,
+ "overall state: isStale:$isStale, isInitialized:$isInitialized, " +
"value:$value, got perm LiveDatas:$gotPermLiveDatas, " +
- "got isUserExempt$gotPastIsUserExempt, got isSystemExempt$gotPastIsSystemExempt")
- Log.i(LOG_TAG, "packagePermsLivedata isStale:${packagePermsLiveData.isStale}, " +
- "isInitialized:${packagePermsLiveData.isInitialized}")
- Log.i(LOG_TAG, "ExemptServicesLiveData isStale:${exemptServicesLiveData.isStale}, " +
- "isInitialized:${exemptServicesLiveData.isInitialized}")
+ "got isUserExempt$gotPastIsUserExempt, got isSystemExempt$gotPastIsSystemExempt"
+ )
+ Log.i(
+ LOG_TAG,
+ "packagePermsLivedata isStale:${packagePermsLiveData.isStale}, " +
+ "isInitialized:${packagePermsLiveData.isInitialized}"
+ )
+ Log.i(
+ LOG_TAG,
+ "ExemptServicesLiveData isStale:${exemptServicesLiveData.isStale}, " +
+ "isInitialized:${exemptServicesLiveData.isInitialized}"
+ )
Log.i(LOG_TAG, "HibernationEnabledLivedata value:${HibernationEnabledLiveData.value}")
for ((group, liveData) in permStateLiveDatas) {
- Log.i(LOG_TAG, "permStateLivedata $group isStale:${liveData.isStale}, " +
- "isInitialized:${liveData.isInitialized}")
+ Log.i(
+ LOG_TAG,
+ "permStateLivedata $group isStale:${liveData.isStale}, " +
+ "isInitialized:${liveData.isInitialized}"
+ )
}
}
/**
* Repository for HibernationSettingStateLiveDatas.
+ *
* <p> Key value is a pair of string package name and UserHandle, value is its corresponding
* LiveData.
*/
- companion object : DataRepositoryForPackage<Pair<String, UserHandle>,
- HibernationSettingStateLiveData>() {
+ companion object :
+ DataRepositoryForPackage<Pair<String, UserHandle>, HibernationSettingStateLiveData>() {
override fun newValue(key: Pair<String, UserHandle>): HibernationSettingStateLiveData {
- return HibernationSettingStateLiveData(PermissionControllerApplication.get(),
- key.first, key.second)
+ return HibernationSettingStateLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LauncherPackagesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LauncherPackagesLiveData.kt
index b512c7e4a..94bf230d7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/LauncherPackagesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LauncherPackagesLiveData.kt
@@ -18,39 +18,43 @@
package com.android.permissioncontroller.permission.data
import android.content.Intent
+import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE
import android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-import android.content.pm.PackageManager.FEATURE_LEANBACK
import com.android.permissioncontroller.PermissionControllerApplication
import kotlinx.coroutines.Job
-/**
- * A livedata which stores a list of package names of packages which have launcher icons.
- */
-object LauncherPackagesLiveData : SmartAsyncMediatorLiveData<Set<String>>(),
- PackageBroadcastReceiver.PackageBroadcastListener {
+/** A livedata which stores a list of package names of packages which have launcher icons. */
+object LauncherPackagesLiveData :
+ SmartAsyncMediatorLiveData<Set<String>>(), PackageBroadcastReceiver.PackageBroadcastListener {
- private val LAUNCHER_INTENT = Intent(Intent.ACTION_MAIN, null)
- .addCategory(Intent.CATEGORY_LAUNCHER)
+ private val LAUNCHER_INTENT =
+ Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER)
// On ATV some apps may have a leanback launcher icon but no regular launcher icon
- private val LEANBACK_LAUNCHER_INTENT = Intent(Intent.ACTION_MAIN, null)
- .addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER)
+ private val LEANBACK_LAUNCHER_INTENT =
+ Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER)
override suspend fun loadDataAndPostValue(job: Job) {
val launcherPkgs = mutableSetOf<String>()
loadPkgsFromIntent(launcherPkgs, LAUNCHER_INTENT)
- if (PermissionControllerApplication.get().packageManager
- .hasSystemFeature(FEATURE_LEANBACK)) {
+ if (
+ PermissionControllerApplication.get().packageManager.hasSystemFeature(FEATURE_LEANBACK)
+ ) {
loadPkgsFromIntent(launcherPkgs, LEANBACK_LAUNCHER_INTENT)
}
postValue(launcherPkgs)
}
private fun loadPkgsFromIntent(launcherPkgs: MutableSet<String>, intent: Intent) {
- for (info in PermissionControllerApplication.get().packageManager.queryIntentActivities(
- intent, MATCH_DIRECT_BOOT_AWARE or MATCH_DIRECT_BOOT_UNAWARE)) {
+ for (info in
+ PermissionControllerApplication.get()
+ .packageManager
+ .queryIntentActivities(
+ intent,
+ MATCH_DIRECT_BOOT_AWARE or MATCH_DIRECT_BOOT_UNAWARE
+ )) {
launcherPkgs.add(info.activityInfo.packageName)
}
}
@@ -69,4 +73,4 @@ object LauncherPackagesLiveData : SmartAsyncMediatorLiveData<Set<String>>(),
super.onInactive()
PackageBroadcastReceiver.removeAllCallback(this)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightAppPermGroupLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightAppPermGroupLiveData.kt
index 3621319a6..67b765097 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightAppPermGroupLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightAppPermGroupLiveData.kt
@@ -27,6 +27,7 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission
+import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.LocationUtils
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.Utils.OS_PKG
@@ -39,31 +40,35 @@ import com.android.permissioncontroller.permission.utils.Utils.OS_PKG
* @param permGroupName The name of the permission group
* @param user The user of the package
*/
-class LightAppPermGroupLiveData private constructor(
+class LightAppPermGroupLiveData
+private constructor(
private val app: Application,
private val packageName: String,
private val permGroupName: String,
- private val user: UserHandle
+ private val user: UserHandle,
+ private val deviceId: Int
) : SmartUpdateMediatorLiveData<LightAppPermGroup?>(), LocationUtils.LocationListener {
private val LOG_TAG = this::class.java.simpleName
private var isSpecialLocation = false
- private val permStateLiveData = PermStateLiveData[packageName, permGroupName, user]
+ private val permStateLiveData = PermStateLiveData[packageName, permGroupName, user, deviceId]
private val permGroupLiveData = PermGroupLiveData[permGroupName]
- private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
+ private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user, deviceId]
private val fgPermNamesLiveData = ForegroundPermNamesLiveData
init {
- isSpecialLocation = LocationUtils.isLocationGroupAndProvider(app,
- permGroupName, packageName) ||
- LocationUtils.isLocationGroupAndControllerExtraPackage(app, permGroupName, packageName)
+ isSpecialLocation =
+ LocationUtils.isLocationGroupAndProvider(app, permGroupName, packageName) ||
+ LocationUtils.isLocationGroupAndControllerExtraPackage(
+ app,
+ permGroupName,
+ packageName
+ )
- addSource(fgPermNamesLiveData) {
- update()
- }
+ addSource(fgPermNamesLiveData) { update() }
- val key = Triple(packageName, permGroupName, user)
+ val key = KotlinUtils.Quadruple(packageName, permGroupName, user, deviceId)
addSource(permStateLiveData) { permStates ->
if (permStates == null && permStateLiveData.isInitialized) {
@@ -100,8 +105,10 @@ class LightAppPermGroupLiveData private constructor(
val allForegroundPerms = fgPermNamesLiveData.value ?: return
// Do not allow toggling pre-M custom perm groups
- if (packageInfo.targetSdkVersion < Build.VERSION_CODES.M &&
- permGroup.groupInfo.packageName != OS_PKG) {
+ if (
+ packageInfo.targetSdkVersion < Build.VERSION_CODES.M &&
+ permGroup.groupInfo.packageName != OS_PKG
+ ) {
value = LightAppPermGroup(packageInfo, permGroup.groupInfo, emptyMap())
return
}
@@ -110,8 +117,8 @@ class LightAppPermGroupLiveData private constructor(
for ((permName, permState) in permStates) {
val permInfo = permGroup.permissionInfos[permName] ?: continue
val foregroundPerms = allForegroundPerms[permName]
- permissionMap[permName] = LightPermission(packageInfo, permInfo, permState,
- foregroundPerms)
+ permissionMap[permName] =
+ LightPermission(packageInfo, permInfo, permState, foregroundPerms)
}
// Determine if this app permission group is a special location package or provider
@@ -119,17 +126,24 @@ class LightAppPermGroupLiveData private constructor(
val userContext = Utils.getUserContext(app, user)
if (LocationUtils.isLocationGroupAndProvider(userContext, permGroupName, packageName)) {
specialLocationGrant = LocationUtils.isLocationEnabled(userContext)
- } else if (LocationUtils.isLocationGroupAndControllerExtraPackage(app, permGroupName,
- packageName)) {
+ } else if (
+ LocationUtils.isLocationGroupAndControllerExtraPackage(app, permGroupName, packageName)
+ ) {
// The permission of the extra location controller package is determined by the status
// of the controller package itself.
- specialLocationGrant = LocationUtils.isExtraLocationControllerPackageEnabled(
- userContext)
+ specialLocationGrant =
+ LocationUtils.isExtraLocationControllerPackageEnabled(userContext)
}
val hasInstallToRuntimeSplit = hasInstallToRuntimeSplit(packageInfo, permissionMap)
- value = LightAppPermGroup(packageInfo, permGroup.groupInfo, permissionMap,
- hasInstallToRuntimeSplit, specialLocationGrant)
+ value =
+ LightAppPermGroup(
+ packageInfo,
+ permGroup.groupInfo,
+ permissionMap,
+ hasInstallToRuntimeSplit,
+ specialLocationGrant
+ )
}
/**
@@ -147,12 +161,13 @@ class LightAppPermGroupLiveData private constructor(
for (spi in permissionManager.splitPermissions) {
val splitPerm = spi.splitPermission
- val pi = try {
- app.packageManager.getPermissionInfo(splitPerm, 0)
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(LOG_TAG, "No such permission: $splitPerm", e)
- continue
- }
+ val pi =
+ try {
+ app.packageManager.getPermissionInfo(splitPerm, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(LOG_TAG, "No such permission: $splitPerm", e)
+ continue
+ }
// Skip if split permission is not "install" permission.
if (pi.protection != PermissionInfo.PROTECTION_NORMAL) {
@@ -199,15 +214,25 @@ class LightAppPermGroupLiveData private constructor(
/**
* Repository for AppPermGroupLiveDatas.
+ *
* <p> Key value is a triple of string package name, string permission group name, and
* UserHandle, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<Triple<String, String, UserHandle>,
- LightAppPermGroupLiveData>() {
- override fun newValue(key: Triple<String, String, UserHandle>):
- LightAppPermGroupLiveData {
- return LightAppPermGroupLiveData(PermissionControllerApplication.get(),
- key.first, key.second, key.third)
+ companion object :
+ DataRepositoryForDevice<
+ KotlinUtils.Quadruple<String, String, UserHandle, Int>, LightAppPermGroupLiveData
+ >() {
+ override fun newValue(
+ key: KotlinUtils.Quadruple<String, String, UserHandle, Int>,
+ deviceId: Int
+ ): LightAppPermGroupLiveData {
+ return LightAppPermGroupLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second,
+ key.third,
+ deviceId
+ )
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt
index 27681cd90..ef0a36583 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt
@@ -18,6 +18,8 @@
package com.android.permissioncontroller.permission.data
import android.app.Application
+import android.content.Context
+import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.UserHandle
import android.os.UserManager
@@ -27,6 +29,8 @@ import androidx.lifecycle.Observer
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
+import com.android.permissioncontroller.permission.utils.ContextCompat
+import com.android.permissioncontroller.permission.utils.MultiDeviceUtils.isPermissionDeviceAware
import com.android.permissioncontroller.permission.utils.Utils
import kotlinx.coroutines.Job
@@ -37,11 +41,14 @@ import kotlinx.coroutines.Job
* @param packageName The name of the package this LiveData will watch for mode changes for
* @param user The user for whom the packageInfo will be defined
*/
-class LightPackageInfoLiveData private constructor(
+class LightPackageInfoLiveData
+private constructor(
private val app: Application,
private val packageName: String,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<LightPackageInfo?>(alwaysUpdateOnActive = false),
+ private val user: UserHandle,
+ private val deviceId: Int
+) :
+ SmartAsyncMediatorLiveData<LightPackageInfo?>(alwaysUpdateOnActive = false),
PackageBroadcastReceiver.PackageBroadcastListener,
PermissionListenerMultiplexer.PermissionChangeCallback {
@@ -49,13 +56,9 @@ class LightPackageInfoLiveData private constructor(
private val userPackagesLiveData = UserPackageInfosLiveData[user]
private var uid: Int? = null
- /**
- * The currently registered UID on which this LiveData is listening for permission changes.
- */
+ /** The currently registered UID on which this LiveData is listening for permission changes. */
private var registeredUid: Int? = null
- /**
- * Whether or not this package livedata is watching the UserPackageInfosLiveData
- */
+ /** Whether or not this package livedata is watching the UserPackageInfosLiveData */
private var watchingUserPackagesLiveData: Boolean = false
/**
@@ -73,8 +76,11 @@ class LightPackageInfoLiveData private constructor(
uid = packageInfo.uid
if (hasActiveObservers()) {
- PermissionListenerMultiplexer.addOrReplaceCallback(registeredUid,
- packageInfo.uid, this)
+ PermissionListenerMultiplexer.addOrReplaceCallback(
+ registeredUid,
+ packageInfo.uid,
+ this
+ )
registeredUid = uid
}
}
@@ -95,30 +101,51 @@ class LightPackageInfoLiveData private constructor(
if (job.isCancelled) {
return
}
- postValue(try {
- var flags = PackageManager.GET_PERMISSIONS
- if (SdkLevel.isAtLeastS()) {
- flags = flags or PackageManager.GET_ATTRIBUTIONS
- }
+ postValue(
+ try {
+ var flags = PackageManager.GET_PERMISSIONS
+ if (SdkLevel.isAtLeastS()) {
+ flags = flags or PackageManager.GET_ATTRIBUTIONS
+ }
+
+ val packageManager = Utils.getUserContext(app, user).packageManager
+ val pI = packageManager.getPackageInfo(packageName, flags)
- LightPackageInfo(Utils.getUserContext(app, user).packageManager
- .getPackageInfo(packageName, flags))
- } catch (e: Exception) {
- if (e is PackageManager.NameNotFoundException) {
- Log.w(LOG_TAG, "Package \"$packageName\" not found for user $user")
- } else {
- val profiles = app.getSystemService(UserManager::class.java)!!.userProfiles
- Log.e(LOG_TAG, "Failed to create context for user $user. " +
- "User exists : ${user in profiles }", e)
+ // PackageInfo#requestedPermissionsFlags is not device aware. Hence for device aware
+ // permissions if the deviceId is not the primary device we need to separately check
+ // permission for that device and update requestedPermissionsFlags.
+ if (SdkLevel.isAtLeastV() && deviceId != ContextCompat.DEVICE_ID_DEFAULT) {
+ val requestedPermissionsFlagsForDevice =
+ getPermissionsFlagsForDevice(
+ pI.requestedPermissions?.toList() ?: emptyList(),
+ pI.requestedPermissionsFlags?.toList() ?: emptyList(),
+ pI.applicationInfo!!.uid,
+ deviceId
+ )
+
+ LightPackageInfo(pI, deviceId, requestedPermissionsFlagsForDevice)
+ } else {
+ LightPackageInfo(pI)
+ }
+ } catch (e: Exception) {
+ if (e is PackageManager.NameNotFoundException) {
+ Log.w(LOG_TAG, "Package \"$packageName\" not found for user $user")
+ } else {
+ val profiles = app.getSystemService(UserManager::class.java)!!.userProfiles
+ Log.e(
+ LOG_TAG,
+ "Failed to create context for user $user. " +
+ "User exists : ${user in profiles }",
+ e
+ )
+ }
+ invalidateSingle(Triple(packageName, user, deviceId))
+ null
}
- invalidateSingle(packageName to user)
- null
- })
+ )
}
- /**
- * Callback from the PermissionListener. Either deletes or generates package data.
- */
+ /** Callback from the PermissionListener. Either deletes or generates package data. */
override fun onPermissionChange() {
updateAsync()
}
@@ -131,8 +158,11 @@ class LightPackageInfoLiveData private constructor(
registeredUid = uid
PermissionListenerMultiplexer.addCallback(it, this)
}
- if (userPackagesLiveData.hasActiveObservers() && !watchingUserPackagesLiveData &&
- !userPackagesLiveData.permChangeStale) {
+ if (
+ userPackagesLiveData.hasActiveObservers() &&
+ !watchingUserPackagesLiveData &&
+ !userPackagesLiveData.permChangeStale
+ ) {
watchingUserPackagesLiveData = true
addSource(userPackagesLiveData, userPackageInfosObserver)
} else {
@@ -140,9 +170,8 @@ class LightPackageInfoLiveData private constructor(
}
}
- private val userPackageInfosObserver = Observer<List<LightPackageInfo>> {
- updateFromUserPackageInfosLiveData()
- }
+ private val userPackageInfosObserver =
+ Observer<List<LightPackageInfo>> { updateFromUserPackageInfosLiveData() }
@MainThread
private fun updateFromUserPackageInfosLiveData() {
@@ -159,6 +188,16 @@ class LightPackageInfoLiveData private constructor(
watchingUserPackagesLiveData = false
}
+ if (SdkLevel.isAtLeastV() && deviceId != Context.DEVICE_ID_DEFAULT) {
+ packageInfo.deviceId = deviceId
+ packageInfo.requestedPermissionsFlags =
+ getPermissionsFlagsForDevice(
+ packageInfo.requestedPermissions,
+ packageInfo.requestedPermissionsFlags,
+ packageInfo.uid,
+ deviceId
+ )
+ }
value = packageInfo
} else {
// If the UserPackageInfosLiveData does not contain this package, check for removal, and
@@ -181,16 +220,57 @@ class LightPackageInfoLiveData private constructor(
}
}
+ // Given permission flags of the default device and an external device Id, return a new list of
+ // permission flags for that device by checking grant state of device aware permissions for the
+ // device.
+ private fun getPermissionsFlagsForDevice(
+ requestedPermissions: List<String>,
+ requestedPermissionsFlags: List<Int>,
+ uid: Int,
+ deviceId: Int
+ ): List<Int> {
+ val requestedPermissionsFlagsForDevice = requestedPermissionsFlags.toMutableList()
+ val deviceContext = ContextCompat.createDeviceContext(app, deviceId)
+
+ for ((idx, permName) in requestedPermissions.withIndex()) {
+ if (isPermissionDeviceAware(permName)) {
+ val result = deviceContext.checkPermission(permName, -1, uid)
+
+ if (result == PackageManager.PERMISSION_GRANTED) {
+ requestedPermissionsFlagsForDevice[idx] =
+ requestedPermissionsFlagsForDevice[idx] or
+ PackageInfo.REQUESTED_PERMISSION_GRANTED
+ }
+
+ if (result == PackageManager.PERMISSION_DENIED) {
+ requestedPermissionsFlagsForDevice[idx] =
+ requestedPermissionsFlagsForDevice[idx] and
+ PackageInfo.REQUESTED_PERMISSION_GRANTED.inv()
+ }
+ }
+ }
+
+ return requestedPermissionsFlagsForDevice
+ }
+
/**
* Repository for LightPackageInfoLiveDatas
- * <p> Key value is a string package name and UserHandle pair, value is its corresponding
- * LiveData.
+ *
+ * <p> Key value is a triple of package name, UserHandle and virtual deviceId, value is its
+ * corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<Pair<String, UserHandle>,
- LightPackageInfoLiveData>() {
- override fun newValue(key: Pair<String, UserHandle>): LightPackageInfoLiveData {
- return LightPackageInfoLiveData(PermissionControllerApplication.get(),
- key.first, key.second)
+ companion object :
+ DataRepositoryForDevice<Triple<String, UserHandle, Int>, LightPackageInfoLiveData>() {
+ override fun newValue(
+ key: Triple<String, UserHandle, Int>,
+ deviceId: Int
+ ): LightPackageInfoLiveData {
+ return LightPackageInfoLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second,
+ deviceId
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt
index 6f33cb199..091c45b92 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt
@@ -20,8 +20,8 @@ import android.app.Application
import android.content.pm.PackageManager
import android.util.Log
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.PermissionMapping.isRuntimePlatformPermission
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermInfo
+import com.android.permissioncontroller.permission.utils.PermissionMapping.isRuntimePlatformPermission
import com.android.permissioncontroller.permission.utils.Utils.OS_PKG
import kotlinx.coroutines.Job
@@ -31,11 +31,9 @@ import kotlinx.coroutines.Job
* @param app current Application
* @param permissionName name of the permission this LiveData will watch for mode changes for
*/
-class LightPermInfoLiveData private constructor(
- private val app: Application,
- private val permissionName: String
-) : SmartAsyncMediatorLiveData<LightPermInfo>(),
- PackageBroadcastReceiver.PackageBroadcastListener {
+class LightPermInfoLiveData
+private constructor(private val app: Application, private val permissionName: String) :
+ SmartAsyncMediatorLiveData<LightPermInfo>(), PackageBroadcastReceiver.PackageBroadcastListener {
private val LOG_TAG = LightPermInfoLiveData::class.java.simpleName
@@ -67,13 +65,14 @@ class LightPermInfoLiveData private constructor(
return
}
- val newValue = try {
- LightPermInfo(app.packageManager.getPermissionInfo(permissionName, 0))
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(LOG_TAG, "Permission \"$permissionName\" not found")
- invalidateSingle(permissionName)
- null
- }
+ val newValue =
+ try {
+ LightPermInfo(app.packageManager.getPermissionInfo(permissionName, 0))
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(LOG_TAG, "Permission \"$permissionName\" not found")
+ invalidateSingle(permissionName)
+ null
+ }
if (isImmutable()) {
stopListeningForChanges()
@@ -82,9 +81,7 @@ class LightPermInfoLiveData private constructor(
postValue(newValue)
}
- /**
- * @return if the permission state can never change
- */
+ /** @return if the permission state can never change */
private fun isImmutable(): Boolean {
// The os package never changes
value?.let {
@@ -97,9 +94,7 @@ class LightPermInfoLiveData private constructor(
return isRuntimePlatformPermission(permissionName)
}
- /**
- * Start listing for changes to this permission if needed
- */
+ /** Start listing for changes to this permission if needed */
private fun startListeningForChanges() {
if (!isListeningForChanges && !isImmutable()) {
isListeningForChanges = true
@@ -107,9 +102,7 @@ class LightPermInfoLiveData private constructor(
}
}
- /**
- * Stop listing for changes to this permission
- */
+ /** Stop listing for changes to this permission */
private fun stopListeningForChanges() {
if (isListeningForChanges) {
PackageBroadcastReceiver.removeAllCallback(this)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LoadAndFreezeLifeData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LoadAndFreezeLifeData.kt
index 5e8789a38..fd572e019 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/LoadAndFreezeLifeData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LoadAndFreezeLifeData.kt
@@ -23,8 +23,8 @@ import androidx.lifecycle.SavedStateHandle
* value forever.
*
* This even extends over live-cycle events as the data is stored in the {@link SaveStateHandle}.
- * This means that the data has to be writable to {@link SavedStateHandle} though, i.e.
- * Serialzable, Parcelable, list, set, map, or a literal
+ * This means that the data has to be writable to {@link SavedStateHandle} though, i.e. Serialzable,
+ * Parcelable, list, set, map, or a literal
*/
class LoadAndFreezeLifeData<T>(
private val state: SavedStateHandle,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/MicMutedLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/MicMutedLiveData.kt
index f53f60345..0c12afb02 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/MicMutedLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/MicMutedLiveData.kt
@@ -24,33 +24,35 @@ import android.media.AudioManager
import com.android.permissioncontroller.PermissionControllerApplication
import kotlinx.coroutines.Job
-/**
- * Tracks whether the mic is muted or not
- */
-val micMutedLiveData = object : SmartAsyncMediatorLiveData<Boolean>() {
- private val app = PermissionControllerApplication.get()
-
- private val isMicMuteRecevicer = object : BroadcastReceiver() {
- override fun onReceive(context: Context?, intent: Intent?) {
- update()
+/** Tracks whether the mic is muted or not */
+val micMutedLiveData =
+ object : SmartAsyncMediatorLiveData<Boolean>() {
+ private val app = PermissionControllerApplication.get()
+
+ private val isMicMuteRecevicer =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ update()
+ }
+ }
+
+ override suspend fun loadDataAndPostValue(job: Job) {
+ postValue(app.getSystemService(AudioManager::class.java)!!.isMicrophoneMute())
}
- }
-
- override suspend fun loadDataAndPostValue(job: Job) {
- postValue(app.getSystemService(AudioManager::class.java).isMicrophoneMute())
- }
- override fun onActive() {
- super.onActive()
+ override fun onActive() {
+ super.onActive()
- app.registerReceiver(isMicMuteRecevicer,
- IntentFilter(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED))
- update()
- }
+ app.registerReceiver(
+ isMicMuteRecevicer,
+ IntentFilter(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
+ )
+ update()
+ }
- override fun onInactive() {
- super.onInactive()
+ override fun onInactive() {
+ super.onInactive()
- app.unregisterReceiver(isMicMuteRecevicer)
+ app.unregisterReceiver(isMicMuteRecevicer)
+ }
}
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/OpUsageLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/OpUsageLiveData.kt
index 805d497c4..7ca0f2d96 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/OpUsageLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/OpUsageLiveData.kt
@@ -45,26 +45,28 @@ class OpUsageLiveData(
private val app: Application,
private val opNames: List<String>,
private val usageDurationMs: Long
-) : SmartAsyncMediatorLiveData<@JvmSuppressWildcards Map<String, List<OpAccess>>>(),
- AppOpsManager.OnOpActiveChangedListener {
+) :
+ SmartAsyncMediatorLiveData<@JvmSuppressWildcards Map<String, List<OpAccess>>>(),
+ AppOpsManager.OnOpActiveChangedListener {
private val appOpsManager = app.getSystemService(AppOpsManager::class.java)!!
override suspend fun loadDataAndPostValue(job: Job) {
val now = System.currentTimeMillis()
val opMap = mutableMapOf<String, MutableList<OpAccess>>()
- val packageOps = try {
- appOpsManager.getPackagesForOps(opNames.toTypedArray())
- } catch (e: NullPointerException) {
- // older builds might not support all the app-ops requested
- emptyList<AppOpsManager.PackageOps>()
- }
+ val packageOps =
+ try {
+ appOpsManager.getPackagesForOps(opNames.toTypedArray())
+ } catch (e: NullPointerException) {
+ // older builds might not support all the app-ops requested
+ emptyList<AppOpsManager.PackageOps>()
+ }
for (packageOp in packageOps) {
for (opEntry in packageOp.ops) {
for ((attributionTag, attributedOpEntry) in opEntry.attributedOpEntries) {
val user = UserHandle.getUserHandleForUid(packageOp.uid)
- val lastAccessTime: Long = attributedOpEntry.getLastAccessTime(
- OP_FLAGS_ALL_TRUSTED)
+ val lastAccessTime: Long =
+ attributedOpEntry.getLastAccessTime(OP_FLAGS_ALL_TRUSTED)
if (lastAccessTime == -1L) {
// There was no access, so skip
@@ -78,34 +80,55 @@ class OpUsageLiveData(
lastAccessDuration = 0
}
- if (attributedOpEntry.isRunning ||
- lastAccessTime + lastAccessDuration > (now - usageDurationMs)) {
+ if (
+ attributedOpEntry.isRunning ||
+ lastAccessTime + lastAccessDuration > (now - usageDurationMs)
+ ) {
val accessList = opMap.getOrPut(opEntry.opStr) { mutableListOf() }
- val accessTime = if (attributedOpEntry.isRunning) {
- OpAccess.IS_RUNNING
- } else {
- lastAccessTime
- }
+ val accessTime =
+ if (attributedOpEntry.isRunning) {
+ OpAccess.IS_RUNNING
+ } else {
+ lastAccessTime
+ }
val proxy = attributedOpEntry.getLastProxyInfo(OP_FLAGS_ALL_TRUSTED)
var proxyAccess: OpAccess? = null
if (proxy != null && proxy.packageName != null) {
- proxyAccess = OpAccess(proxy.packageName!!, proxy.attributionTag,
- UserHandle.getUserHandleForUid(proxy.uid), accessTime)
+ proxyAccess =
+ OpAccess(
+ proxy.packageName!!,
+ proxy.attributionTag,
+ UserHandle.getUserHandleForUid(proxy.uid),
+ accessTime
+ )
}
- accessList.add(OpAccess(packageOp.packageName, attributionTag,
- user, accessTime, proxyAccess))
+ accessList.add(
+ OpAccess(
+ packageOp.packageName,
+ attributionTag,
+ user,
+ accessTime,
+ proxyAccess
+ )
+ )
// TODO ntmyren: remove logs once b/160724034 is fixed
- Log.i("OpUsageLiveData", "adding ${opEntry.opStr} for " +
+ Log.i(
+ "OpUsageLiveData",
+ "adding ${opEntry.opStr} for " +
"${packageOp.packageName}/$attributionTag, access time of " +
"$lastAccessTime, isRunning: ${attributedOpEntry.isRunning} " +
"current time $now, duration $lastAccessDuration, proxy: " +
- "${proxy?.packageName}")
+ "${proxy?.packageName}"
+ )
} else {
- Log.i("OpUsageLiveData", "NOT adding ${opEntry.opStr} for " +
+ Log.i(
+ "OpUsageLiveData",
+ "NOT adding ${opEntry.opStr} for " +
"${packageOp.packageName}/$attributionTag, access time of " +
"$lastAccessTime, isRunning: ${attributedOpEntry.isRunning} " +
- "current time $now, duration $lastAccessDuration")
+ "current time $now, duration $lastAccessDuration"
+ )
}
}
}
@@ -180,26 +203,31 @@ data class OpAccess(
const val IS_RUNNING = -1L
@JvmField
- val CREATOR = object : Parcelable.Creator<OpAccess> {
- override fun createFromParcel(parcel: Parcel): OpAccess {
- val packageName = parcel.readString()!!
- val attributionTag = parcel.readString()
- val user: UserHandle = parcel.readParcelable(UserHandle::class.java.classLoader)!!
- val lastAccessTime = parcel.readLong()
- var proxyAccess: OpAccess? = null
- val proxyPackageName = parcel.readString()
- if (proxyPackageName != null) {
- proxyAccess = OpAccess(proxyPackageName,
- parcel.readString(),
- parcel.readParcelable(UserHandle::class.java.classLoader)!!,
- lastAccessTime)
+ val CREATOR =
+ object : Parcelable.Creator<OpAccess> {
+ override fun createFromParcel(parcel: Parcel): OpAccess {
+ val packageName = parcel.readString()!!
+ val attributionTag = parcel.readString()
+ val user: UserHandle =
+ parcel.readParcelable(UserHandle::class.java.classLoader)!!
+ val lastAccessTime = parcel.readLong()
+ var proxyAccess: OpAccess? = null
+ val proxyPackageName = parcel.readString()
+ if (proxyPackageName != null) {
+ proxyAccess =
+ OpAccess(
+ proxyPackageName,
+ parcel.readString(),
+ parcel.readParcelable(UserHandle::class.java.classLoader)!!,
+ lastAccessTime
+ )
+ }
+ return OpAccess(packageName, attributionTag, user, lastAccessTime, proxyAccess)
}
- return OpAccess(packageName, attributionTag, user, lastAccessTime, proxyAccess)
- }
- override fun newArray(size: Int): Array<OpAccess?> {
- return arrayOfNulls(size)
+ override fun newArray(size: Int): Array<OpAccess?> {
+ return arrayOfNulls(size)
+ }
}
- }
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt
index b2e0236fa..09a7bb1e4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt
@@ -29,31 +29,24 @@ import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
-/**
- * Listens for package additions, replacements, and removals, and notifies listeners.
- */
+/** Listens for package additions, replacements, and removals, and notifies listeners. */
object PackageBroadcastReceiver : BroadcastReceiver() {
private val app: Application = PermissionControllerApplication.get()
- private val intentFilter = IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
- addAction(Intent.ACTION_PACKAGE_REMOVED)
- addAction(Intent.ACTION_PACKAGE_REPLACED)
- addAction(Intent.ACTION_PACKAGE_CHANGED)
- addDataScheme("package")
- }
+ private val intentFilter =
+ IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
+ addAction(Intent.ACTION_PACKAGE_REMOVED)
+ addAction(Intent.ACTION_PACKAGE_REPLACED)
+ addAction(Intent.ACTION_PACKAGE_CHANGED)
+ addDataScheme("package")
+ }
- /**
- * Map<packageName, callbacks listenening to package>
- */
+ /** Map<packageName, callbacks listenening to package> */
private val changeCallbacks = mutableMapOf<String, MutableSet<PackageBroadcastListener>>()
- /**
- * A list of listener IDs, which listen to all package additions, changes, and removals.
- */
+ /** A list of listener IDs, which listen to all package additions, changes, and removals. */
private val allCallbacks = mutableSetOf<PackageBroadcastListener>()
- /**
- * Add a callback which will be notified when the specified packaged is changed or removed.
- */
+ /** Add a callback which will be notified when the specified packaged is changed or removed. */
fun addChangeCallback(packageName: String, listener: PackageBroadcastListener) {
GlobalScope.launch(Main.immediate) {
val wasEmpty = hasNoListeners()
@@ -61,8 +54,12 @@ object PackageBroadcastReceiver : BroadcastReceiver() {
changeCallbacks.getOrPut(packageName, { mutableSetOf() }).add(listener)
if (wasEmpty) {
- app.applicationContext.registerReceiverForAllUsers(this@PackageBroadcastReceiver,
- intentFilter, null, null)
+ app.applicationContext.registerReceiverForAllUsers(
+ this@PackageBroadcastReceiver,
+ intentFilter,
+ null,
+ null
+ )
}
}
}
@@ -80,8 +77,12 @@ object PackageBroadcastReceiver : BroadcastReceiver() {
allCallbacks.add(listener)
if (wasEmpty) {
- app.applicationContext.registerReceiverForAllUsers(this@PackageBroadcastReceiver,
- intentFilter, null, null)
+ app.applicationContext.registerReceiverForAllUsers(
+ this@PackageBroadcastReceiver,
+ intentFilter,
+ null,
+ null
+ )
}
}
}
@@ -171,9 +172,7 @@ object PackageBroadcastReceiver : BroadcastReceiver() {
}
}
- /**
- * A listener interface for objects desiring to be notified of package broadcasts.
- */
+ /** A listener interface for objects desiring to be notified of package broadcasts. */
interface PackageBroadcastListener {
/**
* To be called when a specific package has been changed, or when any package has been
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt
index 49be1fbd0..cc050fae2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt
@@ -35,11 +35,9 @@ import kotlinx.coroutines.Job
* @param packageName The name of the package this LiveData will watch for mode changes for
* @param user The user for whom the packageInfo will be defined
*/
-class PackagePermissionsLiveData private constructor(
- private val app: Application,
- packageName: String,
- user: UserHandle
-) : SmartAsyncMediatorLiveData<Map<String, List<String>>?>() {
+class PackagePermissionsLiveData
+private constructor(private val app: Application, packageName: String, user: UserHandle) :
+ SmartAsyncMediatorLiveData<Map<String, List<String>>?>() {
private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
@@ -60,25 +58,32 @@ class PackagePermissionsLiveData private constructor(
for (permName in packageInfo.requestedPermissions) {
var groupName = PermissionMapping.getGroupOfPlatformPermission(permName)
if (groupName == null) {
- val permInfo = try {
- app.packageManager.getPermissionInfo(permName, 0)
- } catch (e: PackageManager.NameNotFoundException) {
- continue
- }
+ val permInfo =
+ try {
+ app.packageManager.getPermissionInfo(permName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ continue
+ }
- if (permInfo.flags and PermissionInfo.FLAG_INSTALLED == 0 ||
- permInfo.flags and PermissionInfo.FLAG_REMOVED != 0) {
+ if (
+ permInfo.flags and PermissionInfo.FLAG_INSTALLED == 0 ||
+ permInfo.flags and PermissionInfo.FLAG_REMOVED != 0
+ ) {
continue
}
- if (packageInfo.isInstantApp && permInfo.protectionFlags and
- PermissionInfo.PROTECTION_FLAG_INSTANT == 0) {
+ if (
+ packageInfo.isInstantApp &&
+ permInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_INSTANT == 0
+ ) {
continue
}
- if (packageInfo.targetSdkVersion < Build.VERSION_CODES.M &&
- (permInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) !=
- 0) {
+ if (
+ packageInfo.targetSdkVersion < Build.VERSION_CODES.M &&
+ (permInfo.protectionFlags and
+ PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0
+ ) {
continue
}
@@ -104,14 +109,17 @@ class PackagePermissionsLiveData private constructor(
/**
* Repository for PackagePermissionsLiveData objects
+ *
* <p> Key value is a string package name and userHandle, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<Pair<String, UserHandle>,
- PackagePermissionsLiveData>() {
- override fun newValue(key: Pair<String, UserHandle>):
- PackagePermissionsLiveData {
- return PackagePermissionsLiveData(PermissionControllerApplication.get(), key.first,
- key.second)
+ companion object :
+ DataRepositoryForPackage<Pair<String, UserHandle>, PackagePermissionsLiveData>() {
+ override fun newValue(key: Pair<String, UserHandle>): PackagePermissionsLiveData {
+ return PackagePermissionsLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second
+ )
}
const val NON_RUNTIME_NORMAL_PERMS = "nonRuntimeNormalPerms"
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt
index 78f2f72c6..d44fea233 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt
@@ -36,19 +36,15 @@ import com.android.permissioncontroller.permission.utils.Utils
* @param app The current application
* @param groupName The name of the permission group this LiveData represents
*/
-class PermGroupLiveData private constructor(
- private val app: Application,
- private val groupName: String
-) : SmartUpdateMediatorLiveData<PermGroup>(),
- PackageBroadcastReceiver.PackageBroadcastListener {
+class PermGroupLiveData
+private constructor(private val app: Application, private val groupName: String) :
+ SmartUpdateMediatorLiveData<PermGroup>(), PackageBroadcastReceiver.PackageBroadcastListener {
private val LOG_TAG = this::class.java.simpleName
private val context = app.applicationContext!!
- /**
- * Map<packageName, LiveData<PackageInfo>>
- */
+ /** Map<packageName, LiveData<PackageInfo>> */
private val packageLiveDatas = mutableMapOf<String, LightPackageInfoLiveData>()
private lateinit var groupInfo: PackageItemInfo
@@ -69,25 +65,30 @@ class PermGroupLiveData private constructor(
override fun onUpdate() {
val permissionInfos = mutableMapOf<String, LightPermInfo>()
- groupInfo = Utils.getGroupInfo(groupName, context) ?: run {
- Log.e(LOG_TAG, "Invalid permission group $groupName")
- invalidateSingle(groupName)
- value = null
- return
- }
-
- when (groupInfo) {
- is PermissionGroupInfo -> {
- val permInfos = try {
- Utils.getInstalledRuntimePermissionInfosForGroup(context.packageManager,
- groupName)
- } catch (e: PackageManager.NameNotFoundException) {
+ groupInfo =
+ Utils.getGroupInfo(groupName, context)
+ ?: run {
Log.e(LOG_TAG, "Invalid permission group $groupName")
invalidateSingle(groupName)
value = null
return
}
+ when (groupInfo) {
+ is PermissionGroupInfo -> {
+ val permInfos =
+ try {
+ Utils.getInstalledRuntimePermissionInfosForGroup(
+ context.packageManager,
+ groupName
+ )
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.e(LOG_TAG, "Invalid permission group $groupName")
+ invalidateSingle(groupName)
+ value = null
+ return
+ }
+
for (permInfo in permInfos) {
permissionInfos[permInfo.name] = LightPermInfo(permInfo)
}
@@ -105,8 +106,8 @@ class PermGroupLiveData private constructor(
value = permGroup
- val packageNames = permissionInfos.values.map { permInfo -> permInfo.packageName }
- .toMutableSet()
+ val packageNames =
+ permissionInfos.values.map { permInfo -> permInfo.packageName }.toMutableSet()
packageNames.add(groupInfo.packageName)
// TODO ntmyren: What if the package isn't installed for the system user?
@@ -123,8 +124,8 @@ class PermGroupLiveData private constructor(
}
/**
- * Load data, and register a package change listener. We must watch for package changes,
- * because there is currently no listener for permission changes.
+ * Load data, and register a package change listener. We must watch for package changes, because
+ * there is currently no listener for permission changes.
*/
override fun onActive() {
update()
@@ -136,6 +137,7 @@ class PermGroupLiveData private constructor(
/**
* Repository for PermGroupLiveDatas.
+ *
* <p> Key value is a string permission group name, value is its corresponding LiveData.
*/
companion object : DataRepository<String, PermGroupLiveData>() {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt
index 08f9bbfb4..175f389fa 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt
@@ -41,19 +41,21 @@ class PermGroupUsageLiveData(
private val usageDurationMs: Long
) : SmartUpdateMediatorLiveData<Map<String, List<OpAccess>>>() {
/** Perm group name -> OpUsageLiveData */
- private val permGroupUsages = permGroupsNames.map { permGroup ->
- val appops = getPlatformPermissionNamesOfGroup(permGroup).mapNotNull { permName ->
- permissionToOp(permName)
- }
+ private val permGroupUsages =
+ permGroupsNames
+ .map { permGroup ->
+ val appops =
+ getPlatformPermissionNamesOfGroup(permGroup).mapNotNull { permName ->
+ permissionToOp(permName)
+ }
- permGroup to OpUsageLiveData[appops, usageDurationMs]
- }.toMap()
+ permGroup to OpUsageLiveData[appops, usageDurationMs]
+ }
+ .toMap()
init {
for (usage in permGroupUsages.values) {
- addSource(usage) {
- update()
- }
+ addSource(usage) { update() }
}
}
@@ -68,25 +70,33 @@ class PermGroupUsageLiveData(
}
// Only keep the last access for a permission group
- value = permGroupUsages.map { (permGroupName, usageLiveData) ->
- // (packageName, attributionTag) -> access
- val lastAccess = mutableMapOf<Pair<String, String?>, OpAccess>()
- for (access in usageLiveData.value!!.values.flatten()) {
- val key = access.packageName to access.attributionTag
- if (access.isRunning ||
- lastAccess[key]?.lastAccessTime ?: 0 < access.lastAccessTime) {
- lastAccess[key] = access
- }
- }
+ value =
+ permGroupUsages
+ .map { (permGroupName, usageLiveData) ->
+ // (packageName, attributionTag) -> access
+ val lastAccess = mutableMapOf<Pair<String, String?>, OpAccess>()
+ for (access in usageLiveData.value!!.values.flatten()) {
+ val key = access.packageName to access.attributionTag
+ if (
+ access.isRunning ||
+ lastAccess[key]?.lastAccessTime ?: 0 < access.lastAccessTime
+ ) {
+ lastAccess[key] = access
+ }
+ }
- permGroupName to lastAccess.values.toList()
- }.toMap()
+ permGroupName to lastAccess.values.toList()
+ }
+ .toMap()
}
companion object : DataRepository<Pair<List<String>, Long>, PermGroupUsageLiveData>() {
override fun newValue(key: Pair<List<String>, Long>): PermGroupUsageLiveData {
- return PermGroupUsageLiveData(PermissionControllerApplication.get(), key.first,
- key.second)
+ return PermGroupUsageLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt
index e4fa75bd6..7fce5bac7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt
@@ -31,10 +31,9 @@ import com.android.permissioncontroller.permission.utils.Utils.OS_PKG
*
* @param app The current application
*/
-class PermGroupsPackagesLiveData private constructor(
- private val app: Application,
- groupNamesLiveData: LiveData<List<String>>
-) : SmartUpdateMediatorLiveData<Map<String, Set<Pair<String, UserHandle>>>>() {
+class PermGroupsPackagesLiveData
+private constructor(private val app: Application, groupNamesLiveData: LiveData<List<String>>) :
+ SmartUpdateMediatorLiveData<Map<String, Set<Pair<String, UserHandle>>>>() {
private val packagesLiveData = AllPackageInfosLiveData
private val permGroupLiveDatas = mutableMapOf<String, PermGroupLiveData>()
@@ -47,8 +46,10 @@ class PermGroupsPackagesLiveData private constructor(
val getLiveData = { groupName: String -> PermGroupLiveData[groupName] }
setSourcesToDifference(groupNames, permGroupLiveDatas, getLiveData) {
- if (packagesLiveData.isInitialized &&
- permGroupLiveDatas.all { it.value.isInitialized }) {
+ if (
+ packagesLiveData.isInitialized &&
+ permGroupLiveDatas.all { it.value.isInitialized }
+ ) {
update()
}
}
@@ -62,9 +63,9 @@ class PermGroupsPackagesLiveData private constructor(
}
/**
- * Using the current list of permission groups, go through all packages in the system,
- * and figure out which permission groups they have permissions for. If applicable, remove
- * any lone-permission permission that are not requested by any packages.
+ * Using the current list of permission groups, go through all packages in the system, and
+ * figure out which permission groups they have permissions for. If applicable, remove any
+ * lone-permission permission that are not requested by any packages.
*/
override fun onUpdate() {
if (groupNames.isEmpty()) {
@@ -108,8 +109,10 @@ class PermGroupsPackagesLiveData private constructor(
* group, if also empty.
*/
for (permGroup in permGroups) {
- if (permGroup.groupInfo.isSinglePermGroup ||
- permGroup.name == Manifest.permission_group.UNDEFINED) {
+ if (
+ permGroup.groupInfo.isSinglePermGroup ||
+ permGroup.name == Manifest.permission_group.UNDEFINED
+ ) {
val groupPackages = groupApps[permGroup.name] ?: continue
if (groupPackages.isEmpty()) {
groupApps.remove(permGroup.name)
@@ -121,17 +124,22 @@ class PermGroupsPackagesLiveData private constructor(
}
companion object {
- private val customInstance = PermGroupsPackagesLiveData(
- PermissionControllerApplication.get(), CustomPermGroupNamesLiveData)
- private val standardInstance = PermGroupsPackagesLiveData(
- PermissionControllerApplication.get(), StandardPermGroupNamesLiveData)
+ private val customInstance =
+ PermGroupsPackagesLiveData(
+ PermissionControllerApplication.get(),
+ CustomPermGroupNamesLiveData
+ )
+ private val standardInstance =
+ PermGroupsPackagesLiveData(
+ PermissionControllerApplication.get(),
+ StandardPermGroupNamesLiveData
+ )
/**
* Get either the PermGroupsPackageLiveData instance corresponding either to the custom
* permission groups, or the standard permission group.
*
* @param customGroups Whether to get the custom groups instance, or the standard
- *
* @return The specified PermGroupsPackageLiveData
*/
@JvmStatic
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt
index 37967840b..cc5f156ce 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt
@@ -37,8 +37,10 @@ import com.android.permissioncontroller.permission.utils.Utils
class PermGroupsPackagesUiInfoLiveData(
private val app: Application,
private val groupNamesLiveData: LiveData<List<String>>
-) : SmartUpdateMediatorLiveData<
- @kotlin.jvm.JvmSuppressWildcards Map<String, PermGroupPackagesUiInfo?>>() {
+) :
+ SmartUpdateMediatorLiveData<
+ @kotlin.jvm.JvmSuppressWildcards Map<String, PermGroupPackagesUiInfo?>
+ >() {
private val SYSTEM_SHELL = "android.app.role.SYSTEM_SHELL"
private val STAGGER_LOAD_TIME_MS = 50L
@@ -54,11 +56,9 @@ class PermGroupsPackagesUiInfoLiveData(
private val handler: Handler = Handler(Looper.getMainLooper())
- /**
- * Map<permission group name, PermGroupUiLiveDatas>
- */
- private val permGroupPackagesLiveDatas = mutableMapOf<String,
- SinglePermGroupPackagesUiInfoLiveData>()
+ /** Map<permission group name, PermGroupUiLiveDatas> */
+ private val permGroupPackagesLiveDatas =
+ mutableMapOf<String, SinglePermGroupPackagesUiInfoLiveData>()
private val allPackageData = mutableMapOf<String, PermGroupPackagesUiInfo?>()
private lateinit var groupNames: List<String>
@@ -78,7 +78,7 @@ class PermGroupsPackagesUiInfoLiveData(
private fun isGranted(grantState: AppPermGroupUiInfo.PermGrantState): Boolean {
return grantState != AppPermGroupUiInfo.PermGrantState.PERMS_DENIED &&
- grantState != AppPermGroupUiInfo.PermGrantState.PERMS_ASK
+ grantState != AppPermGroupUiInfo.PermGrantState.PERMS_ASK
}
private fun createPermGroupPackageUiInfo(
@@ -118,10 +118,19 @@ class PermGroupsPackagesUiInfoLiveData(
}
}
}
- val onlyShellGranted = grantedNonSystem == 0 && grantedSystem == 1 &&
+ val onlyShellGranted =
+ grantedNonSystem == 0 &&
+ grantedSystem == 1 &&
isPackageShell(firstGrantedSystemPackageName)
- return PermGroupPackagesUiInfo(groupName, nonSystem, grantedNonSystem,
- userInteractedNonSystem, grantedSystem, userInteractedSystem, onlyShellGranted)
+ return PermGroupPackagesUiInfo(
+ groupName,
+ nonSystem,
+ grantedNonSystem,
+ userInteractedNonSystem,
+ grantedSystem,
+ userInteractedSystem,
+ onlyShellGranted
+ )
}
private fun isPackageShell(packageName: String?): Boolean {
@@ -130,27 +139,30 @@ class PermGroupsPackagesUiInfoLiveData(
}
// This method is only called at most once per permission group, so no need to cache value
- val roleManager = Utils.getSystemServiceSafe(PermissionControllerApplication.get(),
- RoleManager::class.java)
+ val roleManager =
+ Utils.getSystemServiceSafe(
+ PermissionControllerApplication.get(),
+ RoleManager::class.java
+ )
return roleManager.getRoleHolders(SYSTEM_SHELL).contains(packageName)
}
override fun onUpdate() {
/**
- * Only update when either-
- * We have a list of groups, and none have loaded their data, or
+ * Only update when either- We have a list of groups, and none have loaded their data, or
* All packages have loaded their data
*/
val haveAllLiveDatas = groupNames.all { permGroupPackagesLiveDatas.contains(it) }
val allInitialized = permGroupPackagesLiveDatas.all { it.value.isInitialized }
for (groupName in groupNames) {
- allPackageData[groupName] = if (haveAllLiveDatas && allInitialized) {
- permGroupPackagesLiveDatas[groupName]?.value?.let { uiInfo ->
- createPermGroupPackageUiInfo(groupName, uiInfo)
+ allPackageData[groupName] =
+ if (haveAllLiveDatas && allInitialized) {
+ permGroupPackagesLiveDatas[groupName]?.value?.let { uiInfo ->
+ createPermGroupPackageUiInfo(groupName, uiInfo)
+ }
+ } else {
+ null
}
- } else {
- null
- }
}
value = allPackageData.toMap()
}
@@ -172,7 +184,7 @@ class PermGroupsPackagesUiInfoLiveData(
private fun addLiveDataDelayed(groupName: String, delayTimeMs: Long) {
val liveData = SinglePermGroupPackagesUiInfoLiveData[groupName]
permGroupPackagesLiveDatas[groupName] = liveData
- handler.postDelayed( { addSource(liveData) { update() } }, delayTimeMs)
+ handler.postDelayed({ addSource(liveData) { update() } }, delayTimeMs)
}
override fun onActive() {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermStateLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermStateLiveData.kt
index c385cf0e5..358081ff5 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermStateLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermStateLiveData.kt
@@ -23,30 +23,39 @@ import android.os.UserHandle
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.model.livedatatypes.PermState
+import com.android.permissioncontroller.permission.utils.ContextCompat
+import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.Utils
import kotlinx.coroutines.Job
/**
* A LiveData which tracks the permission state for one permission group for one package. It
- * includes both the granted state of every permission in the group, and the flags stored
- * in the PermissionController service.
+ * includes both the granted state of every permission in the group, and the flags stored in the
+ * PermissionController service.
*
* @param app The current application
* @param packageName The name of the package this LiveData will watch for mode changes for
- * @param permGroupName The name of the permission group whose app ops this LiveData
- * will watch
+ * @param permGroupName The name of the permission group whose app ops this LiveData will watch
* @param user The user of the package
*/
-class PermStateLiveData private constructor(
+class PermStateLiveData
+private constructor(
private val app: Application,
private val packageName: String,
private val permGroupName: String,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<Map<String, PermState>>(),
+ private val user: UserHandle,
+ private val deviceId: Int
+) :
+ SmartAsyncMediatorLiveData<Map<String, PermState>>(),
PermissionListenerMultiplexer.PermissionChangeCallback {
- private val context = Utils.getUserContext(app, user)
- private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
+ private val context =
+ Utils.getUserContext(app, user).let {
+ if (deviceId == ContextCompat.DEVICE_ID_DEFAULT) {
+ it
+ } else ContextCompat.createDeviceContext(it, deviceId)
+ }
+ private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user, deviceId]
private val groupLiveData = PermGroupLiveData[permGroupName]
private var uid: Int? = null
@@ -58,9 +67,7 @@ class PermStateLiveData private constructor(
updateAsync()
}
- addSource(groupLiveData) {
- updateAsync()
- }
+ addSource(groupLiveData) { updateAsync() }
}
/**
@@ -75,19 +82,19 @@ class PermStateLiveData private constructor(
val packageInfo = packageInfoLiveData.value
val permissionGroup = groupLiveData.value
if (packageInfo == null || permissionGroup == null) {
- invalidateSingle(Triple(packageName, permGroupName, user))
+ invalidateSingle(KotlinUtils.Quadruple(packageName, permGroupName, user, deviceId))
postValue(null)
return
}
val permissionStates = mutableMapOf<String, PermState>()
for ((index, permissionName) in packageInfo.requestedPermissions.withIndex()) {
-
permissionGroup.permissionInfos[permissionName]?.let { permInfo ->
val packageFlags = packageInfo.requestedPermissionsFlags[index]
- val permFlags = context.packageManager.getPermissionFlags(permInfo.name,
- packageName, user)
- val granted = packageFlags and PackageInfo.REQUESTED_PERMISSION_GRANTED != 0 &&
- permFlags and PackageManager.FLAG_PERMISSION_REVOKED_COMPAT == 0
+ val permFlags =
+ context.packageManager.getPermissionFlags(permInfo.name, packageName, user)
+ val granted =
+ packageFlags and PackageInfo.REQUESTED_PERMISSION_GRANTED != 0 &&
+ permFlags and PackageManager.FLAG_PERMISSION_REVOKED_COMPAT == 0
if (job.isCancelled) {
return
@@ -105,15 +112,12 @@ class PermStateLiveData private constructor(
private fun checkForUidUpdate(packageInfo: LightPackageInfo?) {
if (packageInfo == null) {
- registeredUid?.let {
- PermissionListenerMultiplexer.removeCallback(it, this)
- }
+ registeredUid?.let { PermissionListenerMultiplexer.removeCallback(it, this) }
return
}
uid = packageInfo.uid
if (uid != registeredUid && hasActiveObservers()) {
- PermissionListenerMultiplexer.addOrReplaceCallback(
- registeredUid, packageInfo.uid, this)
+ PermissionListenerMultiplexer.addOrReplaceCallback(registeredUid, packageInfo.uid, this)
registeredUid = uid
}
}
@@ -136,14 +140,25 @@ class PermStateLiveData private constructor(
/**
* Repository for PermStateLiveDatas.
- * <p> Key value is a triple of string package name, string permission group name, and UserHandle,
- * value is its corresponding LiveData.
+ *
+ * <p> Key value is a triple of string package name, string permission group name, and
+ * UserHandle, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<Triple<String, String, UserHandle>,
- PermStateLiveData>() {
- override fun newValue(key: Triple<String, String, UserHandle>): PermStateLiveData {
- return PermStateLiveData(PermissionControllerApplication.get(),
- key.first, key.second, key.third)
+ companion object :
+ DataRepositoryForDevice<
+ KotlinUtils.Quadruple<String, String, UserHandle, Int>, PermStateLiveData
+ >() {
+ override fun newValue(
+ key: KotlinUtils.Quadruple<String, String, UserHandle, Int>,
+ deviceId: Int
+ ): PermStateLiveData {
+ return PermStateLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second,
+ key.third,
+ deviceId
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionChange.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionChange.kt
index 29789b0f7..4959a7fba 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionChange.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionChange.kt
@@ -19,10 +19,8 @@ package com.android.permissioncontroller.permission.data
/**
* A record of the user changing permissions for the app but not including any information on what
* actual decision was made. This information is not included for privacy reasons and allows us to
- * persist the data for longer periods of time than we'd be able to otherwise
- * (e.g. [PermissionDecision]).
+ * persist the data for longer periods of time than we'd be able to otherwise (e.g.
+ * [PermissionDecision]).
*/
-data class PermissionChange(
- override val packageName: String,
- override val eventTime: Long
-) : PermissionEvent(packageName, eventTime)
+data class PermissionChange(override val packageName: String, override val eventTime: Long) :
+ PermissionEvent(packageName, eventTime)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionEvent.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionEvent.kt
index ad759795b..2fa64cd43 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionEvent.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionEvent.kt
@@ -20,10 +20,7 @@ package com.android.permissioncontroller.permission.data
* A record of a permission event caused by the user.
*
* @param packageName package name of the app the event is for
- * @param eventTime the time of the event, in epoch time. Should be rounded to day-level
- * precision for user privacy.
+ * @param eventTime the time of the event, in epoch time. Should be rounded to day-level precision
+ * for user privacy.
*/
-abstract class PermissionEvent(
- open val packageName: String,
- open val eventTime: Long
-)
+abstract class PermissionEvent(open val packageName: String, open val eventTime: Long)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionListenerMultiplexer.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionListenerMultiplexer.kt
index d6d532341..fb0f3077a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionListenerMultiplexer.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionListenerMultiplexer.kt
@@ -20,24 +20,19 @@ import android.app.Application
import android.content.pm.PackageManager
import com.android.permissioncontroller.PermissionControllerApplication
-/**
- * Serves as a single shared Permission Change Listener for all AppPermissionGroupLiveDatas.
- *
- */
+/** Serves as a single shared Permission Change Listener for all AppPermissionGroupLiveDatas. */
object PermissionListenerMultiplexer : PackageManager.OnPermissionsChangedListener {
private val app: Application = PermissionControllerApplication.get()
/**
- * Map<UID, list of PermissionChangeCallbacks that wish to be informed when
- * permissions are updated for that UID>
+ * Map<UID, list of PermissionChangeCallbacks that wish to be informed when permissions are
+ * updated for that UID>
*/
private val callbacks = mutableMapOf<Int, MutableList<PermissionChangeCallback>>()
private val pm = app.applicationContext.packageManager
override fun onPermissionsChanged(uid: Int) {
- callbacks[uid]?.toList()?.forEach { callback ->
- callback.onPermissionChange()
- }
+ callbacks[uid]?.toList()?.forEach { callback -> callback.onPermissionChange() }
}
fun addOrReplaceCallback(oldUid: Int?, newUid: Int, callback: PermissionChangeCallback) {
@@ -78,4 +73,4 @@ object PermissionListenerMultiplexer : PackageManager.OnPermissionsChangedListen
interface PermissionChangeCallback {
fun onPermissionChange()
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PreinstalledUserPackageInfosLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PreinstalledUserPackageInfosLiveData.kt
index b4205acff..243fe5b03 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PreinstalledUserPackageInfosLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PreinstalledUserPackageInfosLiveData.kt
@@ -33,23 +33,23 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param user The user whose packages are desired
*/
-class PreinstalledUserPackageInfosLiveData private constructor(
- private val app: Application,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<@kotlin.jvm.JvmSuppressWildcards List<LightPackageInfo>>(
- isStaticVal = true, alwaysUpdateOnActive = false
-) {
+class PreinstalledUserPackageInfosLiveData
+private constructor(private val app: Application, private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<@kotlin.jvm.JvmSuppressWildcards List<LightPackageInfo>>(
+ isStaticVal = true,
+ alwaysUpdateOnActive = false
+ ) {
- /**
- * Get all of the preinstalled packages in the system for this user
- */
+ /** Get all of the preinstalled packages in the system for this user */
override suspend fun loadDataAndPostValue(job: Job) {
if (job.isCancelled) {
return
}
- val packageInfos = app.applicationContext.packageManager
- .getInstalledPackagesAsUser(GET_PERMISSIONS or MATCH_UNINSTALLED_PACKAGES
- or MATCH_FACTORY_ONLY, user.identifier)
+ val packageInfos =
+ app.applicationContext.packageManager.getInstalledPackagesAsUser(
+ GET_PERMISSIONS or MATCH_UNINSTALLED_PACKAGES or MATCH_FACTORY_ONLY,
+ user.identifier
+ )
postValue(packageInfos.map { packageInfo -> LightPackageInfo(packageInfo) })
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/RoleHoldersLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/RoleHoldersLiveData.kt
index 2cf17fb95..744b5bdbd 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/RoleHoldersLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/RoleHoldersLiveData.kt
@@ -29,7 +29,8 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param roleName The name of the role
*/
-class RoleHoldersLiveData private constructor(
+class RoleHoldersLiveData
+private constructor(
private val app: Application,
private val roleName: String,
private val user: UserHandle
@@ -57,6 +58,7 @@ class RoleHoldersLiveData private constructor(
/**
* Repository for RoleHoldersLiveData.
+ *
* <p> Key value is the name of the role.
*/
companion object : DataRepository<Pair<String, UserHandle>, RoleHoldersLiveData>() {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/RoleListenerMultiplexer.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/RoleListenerMultiplexer.kt
index ac853439d..fefaa5fc4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/RoleListenerMultiplexer.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/RoleListenerMultiplexer.kt
@@ -23,16 +23,14 @@ import android.os.UserHandle
import androidx.annotation.GuardedBy
import com.android.permissioncontroller.PermissionControllerApplication
-/**
- * Serves as a single shared Role Change Listener.
- */
+/** Serves as a single shared Role Change Listener. */
object RoleListenerMultiplexer : OnRoleHoldersChangedListener {
private val app: Application = PermissionControllerApplication.get()
@GuardedBy("lock")
- private val callbacks = mutableMapOf<UserHandle,
- MutableMap<String, MutableList<RoleHoldersChangeCallback>>>()
+ private val callbacks =
+ mutableMapOf<UserHandle, MutableMap<String, MutableList<RoleHoldersChangeCallback>>>()
private val roleManager = app.getSystemService(RoleManager::class.java)!!
@@ -40,12 +38,8 @@ object RoleListenerMultiplexer : OnRoleHoldersChangedListener {
override fun onRoleHoldersChanged(roleName: String, user: UserHandle) {
val callbacksCopy: List<RoleHoldersChangeCallback>?
- synchronized(lock) {
- callbacksCopy = callbacks[user]?.get(roleName)?.toList()
- }
- callbacksCopy?.forEach { listener ->
- listener.onRoleHoldersChanged()
- }
+ synchronized(lock) { callbacksCopy = callbacks[user]?.get(roleName)?.toList() }
+ callbacksCopy?.forEach { listener -> listener.onRoleHoldersChanged() }
}
fun addCallback(roleName: String, user: UserHandle, callback: RoleHoldersChangeCallback) {
@@ -88,4 +82,4 @@ object RoleListenerMultiplexer : OnRoleHoldersChangedListener {
interface RoleHoldersChangeCallback {
fun onRoleHoldersChanged()
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedAutofillServiceLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedAutofillServiceLiveData.kt
index 9aced3e2b..3ab59237c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedAutofillServiceLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedAutofillServiceLiveData.kt
@@ -29,20 +29,19 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param user The user the services should be determined for
*/
-class SelectedAutofillServiceLiveData(
- private val app: Application,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<String?>() {
+class SelectedAutofillServiceLiveData(private val app: Application, private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<String?>() {
override suspend fun loadDataAndPostValue(job: Job) {
if (job.isCancelled) {
return
}
- val packageName = Utils.getUserContext(app, user)
- .getSystemService(AutofillManager::class.java)
- ?.autofillServiceComponentName
- ?.packageName
+ val packageName =
+ Utils.getUserContext(app, user)
+ .getSystemService(AutofillManager::class.java)
+ ?.autofillServiceComponentName
+ ?.packageName
postValue(packageName)
}
@@ -52,10 +51,9 @@ class SelectedAutofillServiceLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- SelectedAutofillServiceLiveData>() {
+ companion object : DataRepositoryForPackage<UserHandle, SelectedAutofillServiceLiveData>() {
override fun newValue(key: UserHandle): SelectedAutofillServiceLiveData {
return SelectedAutofillServiceLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedVoiceInteractionServiceLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedVoiceInteractionServiceLiveData.kt
index 72a6da139..9bb749323 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedVoiceInteractionServiceLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedVoiceInteractionServiceLiveData.kt
@@ -40,12 +40,14 @@ class SelectedVoiceInteractionServiceLiveData(
return
}
- val packageName = Settings.Secure.getString(
- Utils.getUserContext(app, user).contentResolver,
- // Settings.Secure.VOICE_INTERACTION_SERVICE
- "voice_interaction_service")
- ?.let(ComponentName::unflattenFromString)
- ?.packageName
+ val packageName =
+ Settings.Secure.getString(
+ Utils.getUserContext(app, user).contentResolver,
+ // Settings.Secure.VOICE_INTERACTION_SERVICE
+ "voice_interaction_service"
+ )
+ ?.let(ComponentName::unflattenFromString)
+ ?.packageName
postValue(packageName)
}
@@ -55,11 +57,13 @@ class SelectedVoiceInteractionServiceLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- SelectedVoiceInteractionServiceLiveData>() {
+ companion object :
+ DataRepositoryForPackage<UserHandle, SelectedVoiceInteractionServiceLiveData>() {
override fun newValue(key: UserHandle): SelectedVoiceInteractionServiceLiveData {
return SelectedVoiceInteractionServiceLiveData(
- PermissionControllerApplication.get(), key)
+ PermissionControllerApplication.get(),
+ key
+ )
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedWallpaperServiceLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedWallpaperServiceLiveData.kt
index e4c1314c1..d004f79dc 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedWallpaperServiceLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SelectedWallpaperServiceLiveData.kt
@@ -29,24 +29,23 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param user The user the services should be determined for
*/
-class SelectedWallpaperServiceLiveData(
- private val app: Application,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<String?>() {
+class SelectedWallpaperServiceLiveData(private val app: Application, private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<String?>() {
override suspend fun loadDataAndPostValue(job: Job) {
if (job.isCancelled) {
return
}
- val packageName = try {
- Utils.getUserContext(app, user)
+ val packageName =
+ try {
+ Utils.getUserContext(app, user)
.getSystemService(WallpaperManager::class.java)
?.wallpaperInfo
?.packageName
- } catch (e: NullPointerException) {
- null
- }
+ } catch (e: NullPointerException) {
+ null
+ }
postValue(packageName)
}
@@ -56,10 +55,9 @@ class SelectedWallpaperServiceLiveData(
*
* <p> Key value is a user, value is its corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<UserHandle,
- SelectedWallpaperServiceLiveData>() {
+ companion object : DataRepositoryForPackage<UserHandle, SelectedWallpaperServiceLiveData>() {
override fun newValue(key: UserHandle): SelectedWallpaperServiceLiveData {
return SelectedWallpaperServiceLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt
index 6d59fd585..2deae79cc 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt
@@ -49,9 +49,10 @@ class ServiceLiveData(
override val intentAction: String,
private val permission: String,
private val user: UserHandle
-) : SmartAsyncMediatorLiveData<Set<String>>(),
- PackageBroadcastReceiver.PackageBroadcastListener,
- HasIntentAction {
+) :
+ SmartAsyncMediatorLiveData<Set<String>>(),
+ PackageBroadcastReceiver.PackageBroadcastListener,
+ HasIntentAction {
private val name = intentAction.substringAfterLast(".")
@@ -60,7 +61,7 @@ class ServiceLiveData(
private val enabledNotificationListenersLiveData = EnabledNotificationListenersLiveData[user]
private val selectedWallpaperServiceLiveData = SelectedWallpaperServiceLiveData[user]
private val selectedVoiceInteractionServiceLiveData =
- SelectedVoiceInteractionServiceLiveData[user]
+ SelectedVoiceInteractionServiceLiveData[user]
private val selectedAutofillServiceLiveData = SelectedAutofillServiceLiveData[user]
private val enabledDreamServicesLiveData = EnabledDreamServicesLiveData[user]
private val disabledPrintServicesLiveData = DisabledPrintServicesLiveData[user]
@@ -68,49 +69,31 @@ class ServiceLiveData(
init {
if (intentAction == AccessibilityService.SERVICE_INTERFACE) {
- addSource(enabledAccessibilityServicesLiveData) {
- updateAsync()
- }
+ addSource(enabledAccessibilityServicesLiveData) { updateAsync() }
}
if (intentAction == InputMethod.SERVICE_INTERFACE) {
- addSource(enabledInputMethodsLiveData) {
- updateAsync()
- }
+ addSource(enabledInputMethodsLiveData) { updateAsync() }
}
if (intentAction == NotificationListenerService.SERVICE_INTERFACE) {
- addSource(enabledNotificationListenersLiveData) {
- updateAsync()
- }
+ addSource(enabledNotificationListenersLiveData) { updateAsync() }
}
if (intentAction == WallpaperService.SERVICE_INTERFACE) {
- addSource(selectedWallpaperServiceLiveData) {
- updateAsync()
- }
+ addSource(selectedWallpaperServiceLiveData) { updateAsync() }
}
if (intentAction == VoiceInteractionService.SERVICE_INTERFACE) {
- addSource(selectedVoiceInteractionServiceLiveData) {
- updateAsync()
- }
+ addSource(selectedVoiceInteractionServiceLiveData) { updateAsync() }
}
if (intentAction == AutofillService.SERVICE_INTERFACE) {
- addSource(selectedAutofillServiceLiveData) {
- updateAsync()
- }
+ addSource(selectedAutofillServiceLiveData) { updateAsync() }
}
if (intentAction == DreamService.SERVICE_INTERFACE) {
- addSource(enabledDreamServicesLiveData) {
- updateAsync()
- }
+ addSource(enabledDreamServicesLiveData) { updateAsync() }
}
if (intentAction == PrintService.SERVICE_INTERFACE) {
- addSource(disabledPrintServicesLiveData) {
- updateAsync()
- }
+ addSource(disabledPrintServicesLiveData) { updateAsync() }
}
if (intentAction == DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE) {
- addSource(enabledDeviceAdminsLiveDataLiveData) {
- updateAsync()
- }
+ addSource(enabledDeviceAdminsLiveDataLiveData) { updateAsync() }
}
}
@@ -122,48 +105,69 @@ class ServiceLiveData(
if (job.isCancelled) {
return
}
- if (intentAction == AccessibilityService.SERVICE_INTERFACE &&
- !enabledAccessibilityServicesLiveData.isInitialized) {
+ if (
+ intentAction == AccessibilityService.SERVICE_INTERFACE &&
+ !enabledAccessibilityServicesLiveData.isInitialized
+ ) {
return
}
- if (intentAction == InputMethod.SERVICE_INTERFACE &&
- !enabledInputMethodsLiveData.isInitialized) {
+ if (
+ intentAction == InputMethod.SERVICE_INTERFACE &&
+ !enabledInputMethodsLiveData.isInitialized
+ ) {
return
}
- if (intentAction == NotificationListenerService.SERVICE_INTERFACE &&
- !enabledNotificationListenersLiveData.isInitialized) {
+ if (
+ intentAction == NotificationListenerService.SERVICE_INTERFACE &&
+ !enabledNotificationListenersLiveData.isInitialized
+ ) {
return
}
- if (intentAction == WallpaperService.SERVICE_INTERFACE &&
- !selectedWallpaperServiceLiveData.isInitialized) {
+ if (
+ intentAction == WallpaperService.SERVICE_INTERFACE &&
+ !selectedWallpaperServiceLiveData.isInitialized
+ ) {
return
}
- if (intentAction == VoiceInteractionService.SERVICE_INTERFACE &&
- !selectedVoiceInteractionServiceLiveData.isInitialized) {
+ if (
+ intentAction == VoiceInteractionService.SERVICE_INTERFACE &&
+ !selectedVoiceInteractionServiceLiveData.isInitialized
+ ) {
return
}
- if (intentAction == AutofillService.SERVICE_INTERFACE &&
- !selectedAutofillServiceLiveData.isInitialized) {
+ if (
+ intentAction == AutofillService.SERVICE_INTERFACE &&
+ !selectedAutofillServiceLiveData.isInitialized
+ ) {
return
}
- if (intentAction == DreamService.SERVICE_INTERFACE &&
- !enabledDreamServicesLiveData.isInitialized) {
+ if (
+ intentAction == DreamService.SERVICE_INTERFACE &&
+ !enabledDreamServicesLiveData.isInitialized
+ ) {
return
}
- if (intentAction == PrintService.SERVICE_INTERFACE &&
- !disabledPrintServicesLiveData.isInitialized) {
+ if (
+ intentAction == PrintService.SERVICE_INTERFACE &&
+ !disabledPrintServicesLiveData.isInitialized
+ ) {
return
}
- if (intentAction == DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE &&
- !enabledDeviceAdminsLiveDataLiveData.isInitialized) {
+ if (
+ intentAction == DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE &&
+ !enabledDeviceAdminsLiveDataLiveData.isInitialized
+ ) {
return
}
- val packageNames = getUserContext(app, user).packageManager
+ val packageNames =
+ getUserContext(app, user)
+ .packageManager
.queryIntentServices(
- Intent(intentAction),
- PackageManager.GET_SERVICES or PackageManager.GET_META_DATA)
+ Intent(intentAction),
+ PackageManager.GET_SERVICES or PackageManager.GET_META_DATA
+ )
.mapNotNull { resolveInfo ->
if (resolveInfo?.serviceInfo?.permission != permission) {
return@mapNotNull null
@@ -171,17 +175,19 @@ class ServiceLiveData(
val packageName = resolveInfo.serviceInfo?.packageName
if (!isServiceEnabled(packageName)) {
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG,
- "Not exempting $packageName - not an active $name " +
- "for u${user.identifier}")
+ DumpableLog.i(
+ LOG_TAG,
+ "Not exempting $packageName - not an active $name " +
+ "for u${user.identifier}"
+ )
}
return@mapNotNull null
}
packageName
- }.toSet()
+ }
+ .toSet()
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG,
- "Detected ${name}s: $packageNames")
+ DumpableLog.i(LOG_TAG, "Detected ${name}s: $packageNames")
}
postValue(packageNames)
@@ -241,13 +247,17 @@ class ServiceLiveData(
* <p> Key value is a (string service name, required permission, user) triple, value is its
* corresponding LiveData.
*/
- companion object : DataRepositoryForPackage<Triple<String, String, UserHandle>,
- ServiceLiveData>() {
+ companion object :
+ DataRepositoryForPackage<Triple<String, String, UserHandle>, ServiceLiveData>() {
private const val LOG_TAG = "ServiceLiveData"
override fun newValue(key: Triple<String, String, UserHandle>): ServiceLiveData {
- return ServiceLiveData(PermissionControllerApplication.get(),
- key.first, key.second, key.third)
+ return ServiceLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second,
+ key.third
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SinglePermGroupPackagesUiInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SinglePermGroupPackagesUiInfoLiveData.kt
index a46882c04..b2348a17a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/SinglePermGroupPackagesUiInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SinglePermGroupPackagesUiInfoLiveData.kt
@@ -19,8 +19,8 @@ package com.android.permissioncontroller.permission.data
import android.app.Application
import android.os.UserHandle
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo
+import com.android.permissioncontroller.permission.utils.PermissionMapping
/**
* LiveData for the UI info for all packages in a single permission group. Tracks which packages
@@ -30,26 +30,21 @@ import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGr
* @param app The current application
* @param permGroupName The name of the permission group this LiveData represents
*/
-class SinglePermGroupPackagesUiInfoLiveData private constructor(
- private val app: Application,
- private val permGroupName: String
-) : SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, AppPermGroupUiInfo>>() {
+class SinglePermGroupPackagesUiInfoLiveData
+private constructor(private val app: Application, private val permGroupName: String) :
+ SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, AppPermGroupUiInfo>>() {
private val permGroupLiveData = PermGroupLiveData[permGroupName]
private val isCustomGroup =
!PermissionMapping.getPlatformPermissionGroups().contains(permGroupName)
- private val permGroupPackagesLiveData = PermGroupsPackagesLiveData.get(
- customGroups = isCustomGroup)
+ private val permGroupPackagesLiveData =
+ PermGroupsPackagesLiveData.get(customGroups = isCustomGroup)
- /**
- * Map<Pair<package name, UserHandle>, UI data LiveData>
- */
- private val appPermGroupLiveDatas = mutableMapOf<Pair<String, UserHandle>,
- AppPermGroupUiInfoLiveData>()
+ /** Map<Pair<package name, UserHandle>, UI data LiveData> */
+ private val appPermGroupLiveDatas =
+ mutableMapOf<Pair<String, UserHandle>, AppPermGroupUiInfoLiveData>()
- /**
- * Map<Pair<packageName, userHandle>, UI data>.
- */
+ /** Map<Pair<packageName, userHandle>, UI data>. */
private val shownPackages = mutableMapOf<Pair<String, UserHandle>, AppPermGroupUiInfo>()
init {
@@ -60,9 +55,7 @@ class SinglePermGroupPackagesUiInfoLiveData private constructor(
}
}
- addSource(permGroupPackagesLiveData) {
- update()
- }
+ addSource(permGroupPackagesLiveData) { update() }
}
override fun onUpdate() {
@@ -71,9 +64,7 @@ class SinglePermGroupPackagesUiInfoLiveData private constructor(
addAndRemoveAppPermGroupLiveDatas(thisPermGroupPackages.toList())
if (thisPermGroupPackages.isEmpty()) {
- permGroupLiveData.value?.groupInfo?.let {
- value = emptyMap()
- }
+ permGroupLiveData.value?.groupInfo?.let { value = emptyMap() }
}
}
}
@@ -83,48 +74,46 @@ class SinglePermGroupPackagesUiInfoLiveData private constructor(
AppPermGroupUiInfoLiveData[key.first, permGroupName, key.second]
}
- val (_, removed) = setSourcesToDifference(pkgs, appPermGroupLiveDatas, getLiveData) { key ->
- val appPermGroupUiInfoLiveData = appPermGroupLiveDatas[key]
- val appPermGroupUiInfo = appPermGroupUiInfoLiveData?.value
- shownPackages.remove(key)
-
- if (appPermGroupUiInfo == null) {
- if (appPermGroupUiInfoLiveData != null &&
- appPermGroupUiInfoLiveData.isInitialized) {
- removeSource(appPermGroupUiInfoLiveData)
- appPermGroupLiveDatas.remove(key)
+ val (_, removed) =
+ setSourcesToDifference(pkgs, appPermGroupLiveDatas, getLiveData) { key ->
+ val appPermGroupUiInfoLiveData = appPermGroupLiveDatas[key]
+ val appPermGroupUiInfo = appPermGroupUiInfoLiveData?.value
+ shownPackages.remove(key)
+
+ if (appPermGroupUiInfo == null) {
+ if (
+ appPermGroupUiInfoLiveData != null &&
+ appPermGroupUiInfoLiveData.isInitialized
+ ) {
+ removeSource(appPermGroupUiInfoLiveData)
+ appPermGroupLiveDatas.remove(key)
+ }
+ } else {
+ shownPackages[key] = appPermGroupUiInfo
}
- } else {
- shownPackages[key] = appPermGroupUiInfo
- }
- if (appPermGroupLiveDatas.all { entry -> entry.value.isInitialized }) {
- permGroupLiveData.value?.groupInfo?.let {
- value = shownPackages.toMap()
+ if (appPermGroupLiveDatas.all { entry -> entry.value.isInitialized }) {
+ permGroupLiveData.value?.groupInfo?.let { value = shownPackages.toMap() }
}
}
- }
for (removedKey in removed) {
shownPackages.remove(removedKey)
}
if (appPermGroupLiveDatas.all { entry -> entry.value.isInitialized }) {
- permGroupLiveData.value?.groupInfo?.let {
- value = shownPackages.toMap()
- }
+ permGroupLiveData.value?.groupInfo?.let { value = shownPackages.toMap() }
}
}
/**
* Repository for SinglePermGroupPackagesUiInfoLiveData objects.
+ *
* <p> Key value is a string permission group name, value is its corresponding LiveData.
*/
- companion object : DataRepository<String,
- SinglePermGroupPackagesUiInfoLiveData>() {
+ companion object : DataRepository<String, SinglePermGroupPackagesUiInfoLiveData>() {
override fun newValue(key: String): SinglePermGroupPackagesUiInfoLiveData {
- return SinglePermGroupPackagesUiInfoLiveData(PermissionControllerApplication.get(),
- key)
+ return SinglePermGroupPackagesUiInfoLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SmartAsyncMediatorLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SmartAsyncMediatorLiveData.kt
index b7491a7a4..1cc248956 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/SmartAsyncMediatorLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SmartAsyncMediatorLiveData.kt
@@ -36,14 +36,12 @@ abstract class SmartAsyncMediatorLiveData<T>(
) : SmartUpdateMediatorLiveData<T>(isStaticVal) {
private var currentJob: Job? = null
- @Volatile
- private var jobQueued = false
- @Volatile
- private var jobRunning = false
+ @Volatile private var jobQueued = false
+ @Volatile private var jobRunning = false
/**
- * The main function which will load data. It should periodically check isCancelled to see if
- * it should stop working. If data is loaded, it should call "postValue".
+ * The main function which will load data. It should periodically check isCancelled to see if it
+ * should stop working. If data is loaded, it should call "postValue".
*/
abstract suspend fun loadDataAndPostValue(job: Job)
@@ -67,9 +65,7 @@ abstract class SmartAsyncMediatorLiveData<T>(
jobRunning = false
if (jobQueued) {
jobQueued = false
- GlobalScope.launch(Main.immediate) {
- updateAsync()
- }
+ GlobalScope.launch(Main.immediate) { updateAsync() }
}
}
}
@@ -95,4 +91,4 @@ abstract class SmartAsyncMediatorLiveData<T>(
}
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt
index 7c3ebe0b3..bdb80382d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt
@@ -31,8 +31,8 @@ import kotlinx.coroutines.launch
/**
* A MediatorLiveData which tracks how long it has been inactive, compares new values before setting
- * its value (avoiding unnecessary updates), and can calculate the set difference between a list
- * and a map (used when determining whether or not to add a LiveData as a source).
+ * its value (avoiding unnecessary updates), and can calculate the set difference between a list and
+ * a map (used when determining whether or not to add a LiveData as a source).
*
* @param isStaticVal Whether or not this LiveData value is expected to change
*/
@@ -40,7 +40,7 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
MediatorLiveData<T>(), DataRepository.InactiveTimekeeper {
companion object {
- const val DEBUG_UPDATES = false
+ const val DEBUG = false
val LOG_TAG = SmartUpdateMediatorLiveData::class.java.simpleName
}
@@ -86,7 +86,7 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
*/
@MainThread
fun update() {
- if (DEBUG_UPDATES) {
+ if (DEBUG) {
Log.i(LOG_TAG, "update ${javaClass.simpleName} ${shortStackTrace()}")
}
@@ -96,8 +96,7 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
onUpdate()
}
- @MainThread
- protected abstract fun onUpdate()
+ @MainThread protected abstract fun onUpdate()
override var timeWentInactive: Long? = System.nanoTime()
@@ -107,7 +106,6 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
*
* @param valOne The first T to be compared
* @param valTwo The second T to be compared
- *
* @return True if the two values are different, false otherwise
*/
protected open fun valueNotEqual(valOne: T?, valTwo: T?): Boolean {
@@ -115,15 +113,20 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
}
override fun <S : Any?> addSource(source: LiveData<S>, onChanged: Observer<in S>) {
- addSourceWithStackTraceAttribution(source, onChanged,
- IllegalStateException().getStackTrace())
+ addSourceWithStackTraceAttribution(source, onChanged)
}
private fun <S : Any?> addSourceWithStackTraceAttribution(
source: LiveData<S>,
- onChanged: Observer<in S>,
- stackTrace: Array<StackTraceElement>
+ onChanged: Observer<in S>
) {
+ val stackTrace =
+ if (DEBUG) {
+ IllegalStateException().stackTrace
+ } else {
+ null
+ }
+
GlobalScope.launch(Main.immediate) {
if (source is SmartUpdateMediatorLiveData) {
if (source in sources) {
@@ -134,7 +137,9 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
try {
super.addSource(source, onChanged)
} catch (ex: IllegalStateException) {
- ex.setStackTrace(stackTrace)
+ if (DEBUG) {
+ ex.stackTrace = stackTrace!!
+ }
throw ex
}
}
@@ -158,8 +163,7 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
* @param have The map of livedatas we currently have as sources
* @param getLiveDataFun A function to turn a key into a liveData
* @param onUpdateFun An optional function which will update differently based on different
- * LiveDatas. If blank, will simply call update.
- *
+ * LiveDatas. If blank, will simply call update.
* @return a pair of (all keys added, all keys removed)
*/
fun <K, V : LiveData<*>> setSourcesToDifference(
@@ -167,7 +171,7 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
have: MutableMap<K, V>,
getLiveDataFun: (K) -> V,
onUpdateFun: ((K) -> Unit)? = null
- ): Pair<Set<K>, Set<K>>{
+ ): Pair<Set<K>, Set<K>> {
// Ensure the map is correct when method returns
val (toAdd, toRemove) = KotlinUtils.getMapAndListDifferences(desired, have)
for (key in toAdd) {
@@ -176,8 +180,6 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
val removed = toRemove.map { have.remove(it) }.toMutableList()
- val stackTrace = IllegalStateException().getStackTrace()
-
GlobalScope.launch(Main.immediate) {
// If any state got out of sorts before this coroutine ran, correct it
for (key in toRemove) {
@@ -192,14 +194,15 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
val liveData = getLiveDataFun(key)
// Should be a no op, but there is a slight possibility it isn't
have[key] = liveData
- val observer = Observer<Any?> {
- if (onUpdateFun != null) {
- onUpdateFun(key)
- } else {
- update()
+ val observer =
+ Observer<Any?> {
+ if (onUpdateFun != null) {
+ onUpdateFun(key)
+ } else {
+ update()
+ }
}
- }
- addSourceWithStackTraceAttribution(liveData, observer, stackTrace)
+ addSourceWithStackTraceAttribution(liveData, observer)
}
}
return toAdd to toRemove
@@ -209,8 +212,11 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
timeWentInactive = null
// If this is not an async livedata, and we have sources, and all sources are non-stale,
// force update our value
- if (sources.isNotEmpty() && sources.all { !it.isStale } &&
- this !is SmartAsyncMediatorLiveData<T>) {
+ if (
+ sources.isNotEmpty() &&
+ sources.all { !it.isStale } &&
+ this !is SmartAsyncMediatorLiveData<T>
+ ) {
update()
}
super.onActive()
@@ -238,6 +244,7 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
update()
}
},
- isValueInitialized = { isInitialized && (staleOk || !isStale) })
+ isValueInitialized = { isInitialized && (staleOk || !isStale) }
+ )
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/StandardPermGroupNamesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/StandardPermGroupNamesLiveData.kt
index 3b3b76171..a3b1799de 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/StandardPermGroupNamesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/StandardPermGroupNamesLiveData.kt
@@ -19,9 +19,7 @@ package com.android.permissioncontroller.permission.data
import androidx.lifecycle.LiveData
import com.android.permissioncontroller.permission.utils.PermissionMapping
-/**
- * A LiveData which tracks Platform Permission Group names.
- */
+/** A LiveData which tracks Platform Permission Group names. */
object StandardPermGroupNamesLiveData : LiveData<List<String>>() {
init {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/UnusedPackagesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/UnusedPackagesLiveData.kt
index b97c27501..89bb93dbd 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/UnusedPackagesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/UnusedPackagesLiveData.kt
@@ -28,11 +28,12 @@ import com.android.permissioncontroller.hibernation.lastTimePackageUsed
import com.android.permissioncontroller.permission.utils.Utils
/**
- * Gets all unused packages from an existing live data that have not been opened in a few months
- * and the permission groups that have been revoked for them, if any. This will let us removed used
- * apps from the Unused Apps screen.
+ * Gets all unused packages from an existing live data that have not been opened in a few months and
+ * the permission groups that have been revoked for them, if any. This will let us removed used apps
+ * from the Unused Apps screen.
*
* @param sourceLiveData the live data for packages to base this list of unused apps on
+ *
* ```(packageName, user) -> [groupName]```
*/
class UnusedPackagesLiveData(
@@ -45,15 +46,9 @@ class UnusedPackagesLiveData(
private var usageStatsLiveData = UsageStatsLiveData[unusedThreshold]
init {
- addSource(usageStatsLiveData) {
- update()
- }
- addSource(AutoRevokedPackagesLiveData) {
- update()
- }
- addSource(sourceLiveData) {
- update()
- }
+ addSource(usageStatsLiveData) { update() }
+ addSource(AutoRevokedPackagesLiveData) { update() }
+ addSource(sourceLiveData) { update() }
DeviceConfig.addOnPropertiesChangedListener(
NAMESPACE_PERMISSIONS,
PermissionControllerApplication.get().mainExecutor,
@@ -63,9 +58,7 @@ class UnusedPackagesLiveData(
removeSource(usageStatsLiveData)
unusedThreshold = getUnusedThresholdMs()
usageStatsLiveData = UsageStatsLiveData[unusedThreshold]
- addSource(usageStatsLiveData) {
- update()
- }
+ addSource(usageStatsLiveData) { update() }
}
}
}
@@ -73,9 +66,11 @@ class UnusedPackagesLiveData(
}
override fun onUpdate() {
- if (!usageStatsLiveData.isInitialized ||
- !AutoRevokedPackagesLiveData.isInitialized ||
- !sourceLiveData.isInitialized) {
+ if (
+ !usageStatsLiveData.isInitialized ||
+ !AutoRevokedPackagesLiveData.isInitialized ||
+ !sourceLiveData.isInitialized
+ ) {
return
}
@@ -92,8 +87,10 @@ class UnusedPackagesLiveData(
for ((user, stats) in usageStatsLiveData.value!!) {
for (stat in stats) {
val userPackage = stat.packageName to user
- if (userPackage in autoRevokedPackages &&
- (now - stat.lastTimePackageUsed()) < unusedThreshold) {
+ if (
+ userPackage in autoRevokedPackages &&
+ (now - stat.lastTimePackageUsed()) < unusedThreshold
+ ) {
unusedPackages.remove(userPackage)
}
}
@@ -111,4 +108,4 @@ fun getUnusedPackages(): UnusedPackagesLiveData {
} else {
unusedAutoRevokePackagesLiveData
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/UsageStatsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/UsageStatsLiveData.kt
index b7a44d1d3..72ff21a0a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/UsageStatsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/UsageStatsLiveData.kt
@@ -30,19 +30,18 @@ import kotlinx.coroutines.Job
*
* @param app The current application
* @param searchTimeMs The length of time, in milliseconds, that this LiveData will track. The time
- * will start when the liveData is loaded, and extend backwards searchTimeMs milliseconds.
+ * will start when the liveData is loaded, and extend backwards searchTimeMs milliseconds.
* @param interval The interval to measure in. Default is monthly.
*/
-class UsageStatsLiveData private constructor(
+class UsageStatsLiveData
+private constructor(
private val app: Application,
private val searchTimeMs: Long,
private val interval: Int = INTERVAL_MONTHLY
) : SmartAsyncMediatorLiveData<Map<UserHandle, List<UsageStats>>>() {
init {
- addSource(UsersLiveData) {
- update()
- }
+ addSource(UsersLiveData) { update() }
}
override suspend fun loadDataAndPostValue(job: Job) {
@@ -58,8 +57,8 @@ class UsageStatsLiveData private constructor(
if (Utils.isUserDisabledOrWorkProfile(user)) {
continue
}
- val statsManager = Utils.getUserContext(app, user).getSystemService(
- UsageStatsManager::class.java)!!
+ val statsManager =
+ Utils.getUserContext(app, user).getSystemService(UsageStatsManager::class.java)!!
statsManager.queryUsageStats(interval, now - searchTimeMs, now)?.let { stats ->
userMap[user] = stats
}
@@ -77,4 +76,4 @@ class UsageStatsLiveData private constructor(
return get(interval to INTERVAL_MONTHLY)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt
index 02285809c..884772f37 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt
@@ -85,11 +85,13 @@ private constructor(private val app: Application, private val user: UserHandle)
)
} else if (SdkLevel.isAtLeastS()) {
app.applicationContext.packageManager.getInstalledPackagesAsUser(
- GET_PERMISSIONS or GET_ATTRIBUTIONS or MATCH_ALL, user.identifier
+ GET_PERMISSIONS or GET_ATTRIBUTIONS or MATCH_ALL,
+ user.identifier
)
} else {
app.applicationContext.packageManager.getInstalledPackagesAsUser(
- GET_PERMISSIONS or MATCH_ALL, user.identifier
+ GET_PERMISSIONS or MATCH_ALL,
+ user.identifier
)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt
index c138dc36d..fe4517173 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt
@@ -23,25 +23,25 @@ import android.content.pm.PackageManager
import android.os.Process
import android.os.Process.INVALID_UID
import android.os.UserHandle
-
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.model.livedatatypes.UidSensitivityState
import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.Utils
-import kotlinx.coroutines.Job
import java.lang.IllegalArgumentException
+import kotlinx.coroutines.Job
/**
- * Live data of the user sensitivity of either one uid, or all uids that belong to a user.
- * Maps <uid, user sensitive state>
+ * Live data of the user sensitivity of either one uid, or all uids that belong to a user. Maps
+ * <uid, user sensitive state>
*
* @param app The current application
* @param uid The uid whose user sensitivity we would like to observer, or INVALID_UID if we want
- * all uids for a user
+ * all uids for a user
* @param user The user for whom we want the uid/s
*/
-class UserSensitivityLiveData private constructor(
+class UserSensitivityLiveData
+private constructor(
private val app: Application,
private val uid: Int,
private val user: UserHandle
@@ -60,12 +60,8 @@ class UserSensitivityLiveData private constructor(
}
if (getAllUids) {
- addSource(userPackageInfosLiveData) {
- update()
- }
- addSource(LauncherPackagesLiveData) {
- update()
- }
+ addSource(userPackageInfosLiveData) { update() }
+ addSource(LauncherPackagesLiveData) { update() }
} else {
update()
}
@@ -76,10 +72,10 @@ class UserSensitivityLiveData private constructor(
if (!getAllUids) {
val uidHasPackages = getAndObservePackageLiveDatas()
- if (!uidHasPackages || packageLiveDatas.all {
- it.value.isInitialized &&
- it.value.value == null
- }) {
+ if (
+ !uidHasPackages ||
+ packageLiveDatas.all { it.value.isInitialized && it.value.value == null }
+ ) {
packageLiveDatas.clear()
invalidateSingle(uid to user)
postValue(null)
@@ -88,11 +84,12 @@ class UserSensitivityLiveData private constructor(
return
}
}
- val pkgs = if (getAllUids) {
- userPackageInfosLiveData.value ?: return
- } else {
- packageLiveDatas.mapNotNull { it.value.value }
- }
+ val pkgs =
+ if (getAllUids) {
+ userPackageInfosLiveData.value ?: return
+ } else {
+ packageLiveDatas.mapNotNull { it.value.value }
+ }
if (job.isCancelled) {
return
}
@@ -105,17 +102,19 @@ class UserSensitivityLiveData private constructor(
for (pkg in pkgs) {
// sensitivityState for one uid
- val userSensitiveState = sensitiveStatePerUid.getOrPut(pkg.uid) {
- UidSensitivityState(mutableSetOf(), mutableMapOf())
- }
+ val userSensitiveState =
+ sensitiveStatePerUid.getOrPut(pkg.uid) {
+ UidSensitivityState(mutableSetOf(), mutableMapOf())
+ }
userSensitiveState.packages.add(pkg)
- val pkgHasLauncherIcon = if (getAllUids) {
- // The launcher packages set will only be null when it is uninitialized.
- LauncherPackagesLiveData.value?.contains(pkg.packageName) ?: return
- } else {
- KotlinUtils.packageHasLaunchIntent(context, pkg.packageName)
- }
+ val pkgHasLauncherIcon =
+ if (getAllUids) {
+ // The launcher packages set will only be null when it is uninitialized.
+ LauncherPackagesLiveData.value?.contains(pkg.packageName) ?: return
+ } else {
+ KotlinUtils.packageHasLaunchIntent(context, pkg.packageName)
+ }
val pkgIsSystemApp = pkg.appFlags and ApplicationInfo.FLAG_SYSTEM != 0
// Iterate through all runtime perms, setting their keys
for (perm in pkg.requestedPermissions.intersect(runtimePerms)) {
@@ -125,18 +124,20 @@ class UserSensitivityLiveData private constructor(
* - the permission is not pre-granted, or
* - the package is not a system app (i.e. not preinstalled)
*/
- var flags = if (pkgIsSystemApp && !pkgHasLauncherIcon) {
- val permGrantedByDefault = pm.getPermissionFlags(perm, pkg.packageName,
- user) and PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT != 0
-
- if (permGrantedByDefault) {
- 0
+ var flags =
+ if (pkgIsSystemApp && !pkgHasLauncherIcon) {
+ val permGrantedByDefault =
+ pm.getPermissionFlags(perm, pkg.packageName, user) and
+ PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT != 0
+
+ if (permGrantedByDefault) {
+ 0
+ } else {
+ PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
+ }
} else {
- PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
+ Utils.FLAGS_ALWAYS_USER_SENSITIVE
}
- } else {
- Utils.FLAGS_ALWAYS_USER_SENSITIVE
- }
/*
* If two packages share a UID there can be two cases:
@@ -147,11 +148,12 @@ class UserSensitivityLiveData private constructor(
*/
val previousFlags = userSensitiveState.permStates[perm]
if (previousFlags != null) {
- flags = if (pkg.uid < Process.FIRST_APPLICATION_UID) {
- flags and previousFlags
- } else {
- flags or previousFlags
- }
+ flags =
+ if (pkg.uid < Process.FIRST_APPLICATION_UID) {
+ flags and previousFlags
+ } else {
+ flags or previousFlags
+ }
}
userSensitiveState.permStates[perm] = flags
@@ -173,13 +175,17 @@ class UserSensitivityLiveData private constructor(
/**
* Repository for a UserSensitivityLiveData
- * <p> Key value is a pair of int uid (INVALID_UID for all uids), and UserHandle,
- * value is its corresponding LiveData.
+ *
+ * <p> Key value is a pair of int uid (INVALID_UID for all uids), and UserHandle, value is its
+ * corresponding LiveData.
*/
companion object : DataRepository<Pair<Int, UserHandle>, UserSensitivityLiveData>() {
override fun newValue(key: Pair<Int, UserHandle>): UserSensitivityLiveData {
- return UserSensitivityLiveData(PermissionControllerApplication.get(), key.first,
- key.second)
+ return UserSensitivityLiveData(
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second
+ )
}
/**
@@ -187,7 +193,6 @@ class UserSensitivityLiveData private constructor(
* throw an exception if the uid is INVALID_UID.
*
* @param uid The uid for which we want the liveData
- *
* @return The liveData associated with the given UID
*/
operator fun get(uid: Int): UserSensitivityLiveData {
@@ -201,7 +206,6 @@ class UserSensitivityLiveData private constructor(
* Gets a liveData for a user, which will track all uids under
*
* @param user The user for whom we want the liveData
- *
* @return The liveData associated with that user, for all uids
*/
operator fun get(user: UserHandle): UserSensitivityLiveData {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt
index 0e78ec5f6..0fe3f6007 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt
@@ -23,31 +23,26 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.UserHandle
import android.os.UserManager
-
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.Utils
/**
* Live data of the users of the current profile group.
*
- *
* Data source: system server
*/
object UsersLiveData : SmartUpdateMediatorLiveData<List<UserHandle>>() {
- @SuppressLint("StaticFieldLeak")
- private val app = PermissionControllerApplication.get()
+ @SuppressLint("StaticFieldLeak") private val app = PermissionControllerApplication.get()
- /** Monitors changes to the users on this device */
- private val mUserMonitor = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- onUpdate()
+ /** Monitors changes to the users on this device */
+ private val mUserMonitor =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ onUpdate()
+ }
}
- }
- /**
- * Update the encapsulated data with the current list of users.
- */
+ /** Update the encapsulated data with the current list of users. */
override fun onUpdate() {
value = app.getSystemService(UserManager::class.java)!!.userProfiles
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt
index 6483c9f9c..74b29043d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt
@@ -117,7 +117,9 @@ class AllLightPackageOpsLiveData(app: Application) :
.filter { UserHandle.getUserHandleForUid(it.uid) in allProfilesInCurrentUser }
.associateBy(
{ Pair(it.packageName, UserHandle.getUserHandleForUid(it.uid)) },
- { LightPackageOps(opNames, it) }))
+ { LightPackageOps(opNames, it) }
+ )
+ )
}
override fun onOpChanged(op: String?, packageName: String?) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/RecentPermissionDecisionsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v33/RecentPermissionDecisionsLiveData.kt
index 4c18d6987..ec4f936b7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/RecentPermissionDecisionsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v33/RecentPermissionDecisionsLiveData.kt
@@ -20,8 +20,8 @@ import android.os.Build
import androidx.annotation.RequiresApi
import androidx.annotation.VisibleForTesting
import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
-import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl
import com.android.permissioncontroller.permission.service.PermissionEventStorage
+import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl
import kotlinx.coroutines.Job
/** Gets all recent permission decisions made by the user. */
@@ -39,8 +39,6 @@ class RecentPermissionDecisionsLiveData(
// no need to subscribe to decision changes, since those will also be bubbled up through
// package info changes
- recentDecisionsStorage.loadEvents().also {
- postValue(it)
- }
+ recentDecisionsStorage.loadEvents().also { postValue(it) }
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt
index d5fd59242..7844a172f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt
@@ -40,14 +40,16 @@ class AppDataSharingUpdatesLiveData(val app: Application) :
DeviceConfig.getLong(
DeviceConfig.NAMESPACE_PRIVACY,
PROPERTY_DATA_SHARING_UPDATE_PERIOD_MILLIS,
- Duration.ofDays(DEFAULT_DATA_SHARING_UPDATE_PERIOD_DAYS).toMillis())
+ Duration.ofDays(DEFAULT_DATA_SHARING_UPDATE_PERIOD_DAYS).toMillis()
+ )
val file =
AppsSafetyLabelHistoryPersistence.getSafetyLabelHistoryFile(app.applicationContext)
val appSafetyLabelDiffsFromPersistence =
AppsSafetyLabelHistoryPersistence.getAppSafetyLabelDiffs(
Instant.now().atZone(ZoneId.systemDefault()).toInstant().minusMillis(updatePeriod),
- file)
+ file
+ )
val updatesFromPersistence =
appSafetyLabelDiffsFromPersistence.mapNotNull { it.buildUpdateIfSignificantChange() }
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt
index bbc62dfc9..716d8dfe5 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt
@@ -74,7 +74,9 @@ private constructor(
try {
val installSourceInfo = getInstallSourceInfo(packageName)
LightInstallSourceInfo(
- installSourceInfo.packageSource, installSourceInfo.initiatingPackageName)
+ installSourceInfo.packageSource,
+ installSourceInfo.initiatingPackageName
+ )
} catch (e: PackageManager.NameNotFoundException) {
Log.w(LOG_TAG, "InstallSourceInfo for $packageName not found")
invalidateSingle(packageName to user)
@@ -101,7 +103,10 @@ private constructor(
override fun newValue(key: Pair<String, UserHandle>): LightInstallSourceInfoLiveData {
return LightInstallSourceInfoLiveData(
- PermissionControllerApplication.get(), key.first, key.second)
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/SafetyLabelInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/SafetyLabelInfoLiveData.kt
index 6229218d4..5c63de6ce 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/SafetyLabelInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/SafetyLabelInfoLiveData.kt
@@ -115,7 +115,8 @@ private constructor(
}
return SafetyLabel.getSafetyLabelFromMetadata(
- userContext.packageManager.getAppMetadata(packageName))
+ userContext.packageManager.getAppMetadata(packageName)
+ )
}
companion object :
@@ -124,7 +125,10 @@ private constructor(
override fun newValue(key: Pair<String, UserHandle>): SafetyLabelInfoLiveData {
return SafetyLabelInfoLiveData(
- PermissionControllerApplication.get(), key.first, key.second)
+ PermissionControllerApplication.get(),
+ key.first,
+ key.second
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java b/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java
index e096a1a7e..3b2cc7ee0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java
@@ -56,6 +56,7 @@ import com.android.permissioncontroller.PermissionControllerApplication;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.service.LocationAccessCheck;
import com.android.permissioncontroller.permission.utils.ArrayUtils;
+import com.android.permissioncontroller.permission.utils.ContextCompat;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.LocationUtils;
import com.android.permissioncontroller.permission.utils.PermissionMapping;
@@ -336,8 +337,14 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
continue;
}
- final boolean granted = (packageInfo.requestedPermissionsFlags[i]
- & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
+ boolean granted;
+ if (ContextCompat.getDeviceId(context) == ContextCompat.DEVICE_ID_DEFAULT) {
+ granted = (packageInfo.requestedPermissionsFlags[i]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
+ } else {
+ int result = packageManager.checkPermission(requestedPermission, packageName);
+ granted = result == PackageManager.PERMISSION_GRANTED;
+ }
final String appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
|| (isHealthPermissionUiEnabled() && HEALTH_PERMISSION_GROUP.equals(
@@ -936,8 +943,12 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
}
boolean wasGranted = permission.isGrantedIncludingAppOp();
+ boolean isPermissionSplitFromNonRuntime = KotlinUtils.isPermissionSplitFromNonRuntime(
+ mContext,
+ permission.getName(),
+ mPackageInfo.applicationInfo.targetSdkVersion);
- if (mAppSupportsRuntimePermissions) {
+ if (mAppSupportsRuntimePermissions && !isPermissionSplitFromNonRuntime) {
// Do not touch permissions fixed by the system.
if (permission.isSystemFixed()) {
wasAllGranted = false;
@@ -1127,7 +1138,14 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
boolean wasGranted = permission.isGrantedIncludingAppOp();
- if (mAppSupportsRuntimePermissions) {
+ boolean isPermissionSplitFromNonRuntime =
+ KotlinUtils.isPermissionSplitFromNonRuntime(
+ mContext,
+ permission.getName(),
+ mPackageInfo.applicationInfo.targetSdkVersion);
+
+ if (mAppSupportsRuntimePermissions && !isPermissionSplitFromNonRuntime) {
+
// Revoke the permission if needed.
if (permission.isGranted()) {
permission.setGranted(false);
@@ -1172,6 +1190,8 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
if (!permission.isRevokedCompat()) {
permission.setRevokedCompat(true);
}
+
+ permission.setRevokeWhenRequested(false);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/Permission.java b/PermissionController/src/com/android/permissioncontroller/permission/model/Permission.java
index 5ddea4605..4daaeaec8 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/Permission.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/Permission.java
@@ -169,6 +169,18 @@ public final class Permission {
}
/**
+ * Sets the REVOKE_WHEN_REQUESTED permission flag
+ * @param revokeWhenRequested true to set the flag, false to unset it
+ */
+ public void setRevokeWhenRequested(boolean revokeWhenRequested) {
+ if (revokeWhenRequested) {
+ mFlags |= PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+ }
+ }
+
+ /**
* Sets the one-time permission flag
* @param oneTime true to set the flag, false to unset it
*/
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt
index 7b5b7994a..fd9c49f3d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt
@@ -23,25 +23,23 @@ import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_EX
* Tracks the setting state of hibernation and auto revoke for a package
*
* @param hibernationEligibility state saying whether the package is eligible for hibernation. See
- * [HIBERNATION_ELIGIBILITY_ELIGIBLE].
+ * [HIBERNATION_ELIGIBILITY_ELIGIBLE].
* @param revocableGroupNames A list of which permission groups of this package are eligible for
- * auto-revoke. A permission group is auto-revocable if it does not contain a default granted
- * permission.
+ * auto-revoke. A permission group is auto-revocable if it does not contain a default granted
+ * permission.
*/
data class HibernationSettingState(
val hibernationEligibility: Int,
val revocableGroupNames: List<String>
) {
- /**
- * Whether package will hibernate if it is unused.
- */
+ /** Whether package will hibernate if it is unused. */
fun isEligibleForHibernation(): Boolean {
return hibernationEligibility == HIBERNATION_ELIGIBILITY_ELIGIBLE
}
/**
- * Whether the package is exempt from hibernation by the system. This means the app can never
- * be hibernated, and the user setting to exempt it is disabled.
+ * Whether the package is exempt from hibernation by the system. This means the app can never be
+ * hibernated, and the user setting to exempt it is disabled.
*/
fun isExemptBySystem(): Boolean {
return hibernationEligibility == HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt
index 3c87f0b7a..a5736ca83 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt
@@ -28,12 +28,12 @@ import android.os.UserHandle
* @param packageInfo Information about the package
* @param permGroupInfo Information about the permission group
* @param allPermissions The permissions in the permission group that the package requests
- * (including restricted ones).
+ * (including restricted ones).
* @param hasInstallToRuntimeSplit If this group contains a permission that was previously an
- * install permission, but is currently a runtime permission
+ * install permission, but is currently a runtime permission
* @param specialLocationGrant If this package is the location provider, or the extra location
- * package, then the grant state of the group is not determined by the grant state of individual
- * permissions, but by other system properties
+ * package, then the grant state of the group is not determined by the grant state of individual
+ * permissions, but by other system properties
*/
data class LightAppPermGroup(
val packageInfo: LightPackageInfo,
@@ -48,61 +48,58 @@ data class LightAppPermGroup(
perms: Map<String, LightPermission>
) : this(pI, pGI, perms, false, null)
- /**
- * All unrestricted permissions. Usually restricted permissions are ignored
- */
+ /** All unrestricted permissions. Usually restricted permissions are ignored */
val permissions: Map<String, LightPermission> =
- allPermissions.filter { (_, permission) -> !permission.isRestricted }
+ allPermissions.filter { (_, permission) -> !permission.isRestricted }
- /**
- * The package name of this group
- */
+ /** The package name of this group */
val packageName = packageInfo.packageName
- /**
- * The permission group name of this group
- */
+ /** The permission group name of this group */
val permGroupName = permGroupInfo.name
- /**
- * The current userHandle of this AppPermGroup.
- */
+ /** The current userHandle of this AppPermGroup. */
val userHandle: UserHandle = UserHandle.getUserHandleForUid(packageInfo.uid)
+ /** The device ID of this group, inferred from LightPackageInfo */
+ val deviceId = packageInfo.deviceId
+
/**
* The names of all background permissions in the permission group which are requested by the
* package.
*/
val backgroundPermNames = permissions.mapNotNull { it.value.backgroundPermission }
- /**
- * All foreground permissions in the permission group which are requested by the package.
- */
- val foregroundPermNames get() = permissions.mapNotNull { (name, _) ->
- if (name !in backgroundPermNames) name else null
- }
-
- val foreground = AppPermSubGroup(permissions.filter { it.key in foregroundPermNames },
- packageInfo, specialLocationGrant)
-
- val background = AppPermSubGroup(permissions.filter { it.key in backgroundPermNames },
- packageInfo, specialLocationGrant)
-
- /**
- * Whether or not this App Permission Group has a permission which has a background mode
- */
+ /** All foreground permissions in the permission group which are requested by the package. */
+ val foregroundPermNames
+ get() =
+ permissions.mapNotNull { (name, _) -> if (name !in backgroundPermNames) name else null }
+
+ val foreground =
+ AppPermSubGroup(
+ permissions.filter { it.key in foregroundPermNames },
+ packageInfo,
+ specialLocationGrant
+ )
+
+ val background =
+ AppPermSubGroup(
+ permissions.filter { it.key in backgroundPermNames },
+ packageInfo,
+ specialLocationGrant
+ )
+
+ /** Whether or not this App Permission Group has a permission which has a background mode */
val hasPermWithBackgroundMode = backgroundPermNames.isNotEmpty()
- /**
- * Whether or not this App Permission Group requests a background permission
- */
+ /** Whether or not this App Permission Group requests a background permission */
val hasBackgroundGroup = backgroundPermNames.any { permissions.contains(it) }
/**
* Whether this App Permission Group's background and foreground permissions are fixed by policy
*/
- val isPolicyFullyFixed = foreground.isPolicyFixed && (!hasBackgroundGroup ||
- background.isPolicyFixed)
+ val isPolicyFullyFixed =
+ foreground.isPolicyFixed && (!hasBackgroundGroup || background.isPolicyFixed)
/**
* Whether this App Permission Group's background permissions are fixed by the system or policy
@@ -114,107 +111,91 @@ data class LightAppPermGroup(
*/
val isForegroundFixed = foreground.isPolicyFixed || foreground.isSystemFixed
- /**
- * Whether or not this group supports runtime permissions
- */
+ /** Whether or not this group supports runtime permissions */
val supportsRuntimePerms = packageInfo.targetSdkVersion >= Build.VERSION_CODES.M
/**
* Whether this App Permission Group is one-time. 2 cases:
* 1. If the perm group is not LOCATION, check if any of the permissions is one-time and none of
- * the granted permissions are not one-time.
+ * the granted permissions are not one-time.
* 2. If the perm group is LOCATION, check if ACCESS_COARSE_LOCATION is one-time.
*/
- val isOneTime = (permGroupName != Manifest.permission_group.LOCATION &&
+ val isOneTime =
+ (permGroupName != Manifest.permission_group.LOCATION &&
permissions.any { it.value.isOneTime } &&
permissions.none { !it.value.isOneTime && it.value.isGrantedIncludingAppOp }) ||
(permGroupName == Manifest.permission_group.LOCATION &&
- permissions[ACCESS_COARSE_LOCATION]?.isOneTime == true)
+ permissions[ACCESS_COARSE_LOCATION]?.isOneTime == true)
- /**
- * Whether any permissions in this group are granted by default (pregrant)
- */
+ /** Whether any permissions in this group are granted by default (pregrant) */
val isGrantedByDefault = foreground.isGrantedByDefault || background.isGrantedByDefault
- /**
- * Whether any permissions in this group are granted by being a role holder
- */
+ /** Whether any permissions in this group are granted by being a role holder */
val isGrantedByRole = foreground.isGrantedByRole || background.isGrantedByRole
- /**
- * Whether any of the permission (foreground/background) is fixed by the system
- */
+ /** Whether any of the permission (foreground/background) is fixed by the system */
val isSystemFixed = foreground.isSystemFixed || background.isSystemFixed
- /**
- * Whether any of the permission (foreground/background) in this group requires a review
- */
+ /** Whether any of the permission (foreground/background) in this group requires a review */
val isReviewRequired = foreground.isReviewRequired || background.isReviewRequired
- /**
- * Whether any of the permission (foreground/background) is granted in this permission group
- */
+ /** Whether any of the permission (foreground/background) is granted in this permission group */
var isGranted = foreground.isGranted || background.isGranted
- /**
- * Whether any permissions in this group are user sensitive
- */
+ /** Whether any permissions in this group are user sensitive */
val isUserSensitive = permissions.any { it.value.isUserSensitive }
- /**
- * Whether any permissions in this group are revoke-when-requested
- */
+ /** Whether any permissions in this group are revoke-when-requested */
val isRevokeWhenRequested = permissions.any { it.value.isRevokeWhenRequested }
- /**
- * Whether any of this App Permission Groups permissions are fixed by the user
- */
+ /** Whether any of this App Permission Groups permissions are fixed by the user */
val isUserFixed = foreground.isUserFixed || background.isUserFixed
- /**
- * Whether any of this App Permission Group's permissions are set by the user
- */
+ /** Whether any of this App Permission Group's permissions are set by the user */
val isUserSet = foreground.isUserSet || background.isUserSet
/**
- * A subset of the AppPermissionGroup, representing either the background or foreground permissions
- * of the full group.
+ * A subset of the AppPermissionGroup, representing either the background or foreground
+ * permissions of the full group.
*
- * @param permissions The permissions contained within this subgroup, a subset of those contained
- * in the full group
+ * @param permissions The permissions contained within this subgroup, a subset of those
+ * contained in the full group
* @param specialLocationGrant Whether this is a special location package
*/
- data class AppPermSubGroup internal constructor(
+ data class AppPermSubGroup
+ internal constructor(
private val permissions: Map<String, LightPermission>,
private val packageInfo: LightPackageInfo,
private val specialLocationGrant: Boolean?
) {
- /**
- * Whether any of this App Permission SubGroup's permissions are granted
- */
+ /** Whether any of this App Permission SubGroup's permissions are granted */
val isGranted = specialLocationGrant ?: permissions.any { it.value.isGrantedIncludingAppOp }
/**
* Whether this App Permission SubGroup should be treated as granted. This means either:
* 1) At least one permission was granted excluding auto-granted permissions (i.e., granted
- * during install time with flag RevokeWhenRequested.) Or,
+ * during install time with flag RevokeWhenRequested.) Or,
* 2) All permissions were auto-granted (all permissions are all granted and all
- * RevokeWhenRequested.)
- */
- val isGrantedExcludingRWROrAllRWR = specialLocationGrant ?: (permissions
- .any { it.value.isGrantedIncludingAppOp && !it.value.isRevokeWhenRequested } ||
- permissions.all { it.value.isGrantedIncludingAppOp && it.value.isRevokeWhenRequested })
-
- /**
- * Whether any of this App Permission SubGroup's permissions are granted by default
+ * RevokeWhenRequested.)
*/
+ val isGrantedExcludingRWROrAllRWR =
+ specialLocationGrant
+ ?: (permissions.any {
+ it.value.isGrantedIncludingAppOp && !it.value.isRevokeWhenRequested
+ } ||
+ permissions.all {
+ it.value.isGrantedIncludingAppOp && it.value.isRevokeWhenRequested
+ })
+
+ /** Whether any of this App Permission SubGroup's permissions are granted by default */
val isGrantedByDefault = permissions.any { it.value.isGrantedByDefault }
/**
- * Whether at least one of this App Permission SubGroup's permissions is one-time and
- * none of the granted permissions are not one-time.
+ * Whether at least one of this App Permission SubGroup's permissions is one-time and none
+ * of the granted permissions are not one-time.
*/
- val isOneTime = permissions.any { it.value.isOneTime } &&
+ val isOneTime =
+ permissions.any { it.value.isOneTime } &&
permissions.none { it.value.isGrantedIncludingAppOp && !it.value.isOneTime }
/**
@@ -222,24 +203,16 @@ data class LightAppPermGroup(
*/
val isPolicyFixed = permissions.any { it.value.isPolicyFixed }
- /**
- * Whether any of this App Permission Subgroup's permissions are fixed by the system
- */
+ /** Whether any of this App Permission Subgroup's permissions are fixed by the system */
val isSystemFixed = permissions.any { it.value.isSystemFixed }
- /**
- * Whether any of this App Permission Subgroup's permissions are fixed by the user
- */
+ /** Whether any of this App Permission Subgroup's permissions are fixed by the user */
val isUserFixed = permissions.any { it.value.isUserFixed }
- /**
- * Whether any of this App Permission Subgroup's permissions are set by the user
- */
+ /** Whether any of this App Permission Subgroup's permissions are set by the user */
val isUserSet = permissions.any { it.value.isUserSet }
- /**
- * whether review is required or not for the permission group
- */
+ /** whether review is required or not for the permission group */
val isReviewRequired = permissions.any { it.value.isReviewRequired }
/**
@@ -251,10 +224,9 @@ data class LightAppPermGroup(
private val hasInstantPerm = permissions.any { (_, perm) -> perm.isInstantPerm }
- /**
- * Whether or not any permissions in this App Permission Subgroup can be granted
- */
- val isGrantable = (!packageInfo.isInstantApp || hasInstantPerm) &&
+ /** Whether or not any permissions in this App Permission Subgroup can be granted */
+ val isGrantable =
+ (!packageInfo.isInstantApp || hasInstantPerm) &&
(packageInfo.targetSdkVersion >= Build.VERSION_CODES.M || hasPreRuntimePerm)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt
index 0f6b6c000..0830857d0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt
@@ -24,6 +24,7 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.UserHandle
import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.permission.utils.ContextCompat
import com.android.permissioncontroller.permission.utils.Utils
/**
@@ -43,7 +44,7 @@ data class LightPackageInfo(
val packageName: String,
val permissions: List<LightPermInfo>,
val requestedPermissions: List<String>,
- val requestedPermissionsFlags: List<Int>,
+ var requestedPermissionsFlags: List<Int>,
val uid: Int,
val targetSdkVersion: Int,
val isInstantApp: Boolean,
@@ -52,7 +53,8 @@ data class LightPackageInfo(
val firstInstallTime: Long,
val lastUpdateTime: Long,
val areAttributionsUserVisible: Boolean,
- val attributionTagsToLabels: Map<String, Int>
+ val attributionTagsToLabels: Map<String, Int>,
+ var deviceId: Int
) {
constructor(
pI: PackageInfo
@@ -61,23 +63,35 @@ data class LightPackageInfo(
pI.permissions?.map { perm -> LightPermInfo(perm) } ?: emptyList(),
pI.requestedPermissions?.toList() ?: emptyList(),
pI.requestedPermissionsFlags?.toList() ?: emptyList(),
- pI.applicationInfo.uid,
- pI.applicationInfo.targetSdkVersion,
- pI.applicationInfo.isInstantApp,
- pI.applicationInfo.enabled,
- pI.applicationInfo.flags,
+ pI.applicationInfo!!.uid,
+ pI.applicationInfo!!.targetSdkVersion,
+ pI.applicationInfo!!.isInstantApp,
+ pI.applicationInfo!!.enabled,
+ pI.applicationInfo!!.flags,
pI.firstInstallTime,
pI.lastUpdateTime,
- if (SdkLevel.isAtLeastS()) pI.applicationInfo.areAttributionsUserVisible() else false,
- if (SdkLevel.isAtLeastS()) buildAttributionTagsToLabelsMap(pI.attributions) else emptyMap())
+ if (SdkLevel.isAtLeastS()) pI.applicationInfo!!.areAttributionsUserVisible() else false,
+ if (SdkLevel.isAtLeastS()) buildAttributionTagsToLabelsMap(pI.attributions) else emptyMap(),
+ ContextCompat.DEVICE_ID_DEFAULT
+ )
+
+ constructor(
+ pI: PackageInfo,
+ deviceId: Int,
+ requestedPermissionsFlagsForDevice: List<Int>
+ ) : this(pI) {
+ this.deviceId = deviceId
+ this.requestedPermissionsFlags = requestedPermissionsFlagsForDevice
+ }
/** Permissions which are granted according to the [requestedPermissionsFlags] */
val grantedPermissions: List<String>
get() {
val grantedPermissions = mutableListOf<String>()
for (i in 0 until requestedPermissions.size) {
- if ((requestedPermissionsFlags[i] and PackageInfo.REQUESTED_PERMISSION_GRANTED) !=
- 0) {
+ if (
+ (requestedPermissionsFlags[i] and PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
+ ) {
grantedPermissions.add(requestedPermissions[i])
}
}
@@ -89,9 +103,8 @@ data class LightPackageInfo(
* often.
*
* @param app The current application, which will be used to get the ApplicationInfo
- *
* @return The ApplicationInfo corresponding to this package, with this UID, or null, if no such
- * package exists
+ * package exists
*/
fun getApplicationInfo(app: Application): ApplicationInfo? {
try {
@@ -112,7 +125,9 @@ data class LightPackageInfo(
try {
val userContext = Utils.getUserContext(app, UserHandle.getUserHandleForUid(uid))
return userContext.packageManager.getPackageInfo(
- packageName, PackageManager.GET_PERMISSIONS)
+ packageName,
+ PackageManager.GET_PERMISSIONS
+ )
} catch (e: PackageManager.NameNotFoundException) {}
return null
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermGroupInfo.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermGroupInfo.kt
index 6aff2f3c9..7abf5ff1a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermGroupInfo.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermGroupInfo.kt
@@ -41,21 +41,22 @@ data class LightPermGroupInfo(
val isSinglePermGroup: Boolean
) {
- constructor(pII: PackageItemInfo) : this(pII.name, pII.packageName, pII.labelRes, pII.icon,
- 0, pII is PermissionInfo)
+ constructor(
+ pII: PackageItemInfo
+ ) : this(pII.name, pII.packageName, pII.labelRes, pII.icon, 0, pII is PermissionInfo)
- constructor(pGI: PermissionGroupInfo) : this(pGI.name, pGI.packageName, pGI.labelRes, pGI.icon,
- pGI.descriptionRes, false)
+ constructor(
+ pGI: PermissionGroupInfo
+ ) : this(pGI.name, pGI.packageName, pGI.labelRes, pGI.icon, pGI.descriptionRes, false)
/**
* Gets the PackageItemInfo for this permission group from the system.
*
* @param app The current application, which will be used to get the PackageItemInfo
- *
- * @return The PackageItemInfo corresponding to this permission group, or null, if no
- * such group exists
+ * @return The PackageItemInfo corresponding to this permission group, or null, if no such group
+ * exists
*/
fun toPackageItemInfo(app: Application): PackageItemInfo? {
return Utils.getGroupInfo(name, app.applicationContext)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt
index 3954b7472..c1d271098 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt
@@ -40,23 +40,29 @@ data class LightPermInfo(
val protectionFlags: Int,
val flags: Int
) {
- constructor (permInfo: PermissionInfo): this(permInfo.name, permInfo.packageName,
- permInfo.group, permInfo.backgroundPermission, permInfo.protection,
- permInfo.protectionFlags, permInfo.flags)
+ constructor(
+ permInfo: PermissionInfo
+ ) : this(
+ permInfo.name,
+ permInfo.packageName,
+ permInfo.group,
+ permInfo.backgroundPermission,
+ permInfo.protection,
+ permInfo.protectionFlags,
+ permInfo.flags
+ )
/**
* Gets the PermissionInfo for this permission from the system.
*
* @param app The current application, which will be used to get the PermissionInfo
- *
- * @return The PermissionInfo corresponding to this permission, or null, if no
- * such permission exists
+ * @return The PermissionInfo corresponding to this permission, or null, if no such permission
+ * exists
*/
fun toPermissionInfo(app: Application): PermissionInfo? {
try {
return app.packageManager.getPermissionInfo(name, 0)
- } catch (e: PackageManager.NameNotFoundException) {
- }
+ } catch (e: PackageManager.NameNotFoundException) {}
return null
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt
index fd7d82dfc..7492ea6e0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt
@@ -28,11 +28,11 @@ import com.android.permissioncontroller.permission.utils.Utils
*
* @param pkgInfo The package requesting the permission
* @param permInfo The permissionInfo this represents
- * @param isGrantedIncludingAppOp Whether or not this permission is functionally granted.
- * A non-granted app op but granted permission is counted as not granted
+ * @param isGrantedIncludingAppOp Whether or not this permission is functionally granted. A
+ * non-granted app op but granted permission is counted as not granted
* @param flags The PermissionController flags for this permission
* @param foregroundPerms The foreground permission names corresponding to this permission, if this
- * permission is a background permission
+ * permission is a background permission
*/
data class LightPermission(
val pkgInfo: LightPackageInfo,
@@ -47,14 +47,13 @@ data class LightPermission(
permInfo: LightPermInfo,
permState: PermState,
foregroundPerms: List<String>?
- ) :
- this(pkgInfo, permInfo, permState.granted, permState.permFlags, foregroundPerms)
+ ) : this(pkgInfo, permInfo, permState.granted, permState.permFlags, foregroundPerms)
/** The name of this permission */
val name = permInfo.name
/** The background permission name of this permission, if it exists */
val backgroundPermission: String? = permInfo.backgroundPermission
- /** If this is a background permission **/
+ /** If this is a background permission */
val isBackgroundPermission = foregroundPerms?.isNotEmpty() ?: false
/** Whether this permission is fixed by policy */
val isPolicyFixed = flags and PackageManager.FLAG_PERMISSION_POLICY_FIXED != 0
@@ -76,9 +75,10 @@ data class LightPermission(
val isImplicit: Boolean by lazy {
var implicit = false
for ((permName, permFlags) in
- pkgInfo.requestedPermissions.zip(pkgInfo.requestedPermissionsFlags)) {
- if (permName == permInfo.name &&
- (permFlags and PackageInfo.REQUESTED_PERMISSION_IMPLICIT) != 0
+ pkgInfo.requestedPermissions.zip(pkgInfo.requestedPermissionsFlags)) {
+ if (
+ permName == permInfo.name &&
+ (permFlags and PackageInfo.REQUESTED_PERMISSION_IMPLICIT) != 0
) {
implicit = true
break
@@ -96,23 +96,25 @@ data class LightPermission(
/** Whether this permission is set to be revoked upon being requested */
val isRevokeWhenRequested = flags and PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED != 0
/** Whether this permission is user sensitive in its current grant state */
- val isUserSensitive = !isRuntimePlatformPermission(permInfo.name) ||
+ val isUserSensitive =
+ !isRuntimePlatformPermission(permInfo.name) ||
(isGrantedIncludingAppOp &&
- (flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0) ||
+ (flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0) ||
(!isGrantedIncludingAppOp &&
- (flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) != 0)
+ (flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) != 0)
/** Whether the permission is restricted */
- val isRestricted = when {
- (permInfo.flags and PermissionInfo.FLAG_HARD_RESTRICTED) != 0 -> {
- flags and Utils.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT == 0
- }
- (permInfo.flags and PermissionInfo.FLAG_SOFT_RESTRICTED) != 0 -> {
- !SoftRestrictedPermissionPolicy.shouldShow(pkgInfo, permInfo.name, flags)
- }
- else -> {
- false
+ val isRestricted =
+ when {
+ (permInfo.flags and PermissionInfo.FLAG_HARD_RESTRICTED) != 0 -> {
+ flags and Utils.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT == 0
+ }
+ (permInfo.flags and PermissionInfo.FLAG_SOFT_RESTRICTED) != 0 -> {
+ !SoftRestrictedPermissionPolicy.shouldShow(pkgInfo, permInfo.name, flags)
+ }
+ else -> {
+ false
+ }
}
- }
/** Whether the permission is auto revoked */
val isAutoRevoked = flags and PackageManager.FLAG_PERMISSION_AUTO_REVOKED != 0
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroup.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroup.kt
index c5079a950..e6913f57e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroup.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroup.kt
@@ -17,8 +17,8 @@
package com.android.permissioncontroller.permission.model.livedatatypes
/**
- * A permission Group, represented as a PackageItemInfo groupInfo, and a map of permission name
- * to PermissionInfo objects.
+ * A permission Group, represented as a PackageItemInfo groupInfo, and a map of permission name to
+ * PermissionInfo objects.
*
* @param groupInfo information about the permission group
* @param permissionInfos the Permissions in this group
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroupPackagesUiInfo.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroupPackagesUiInfo.kt
index e11e895a9..ba4aa0a20 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroupPackagesUiInfo.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/PermGroupPackagesUiInfo.kt
@@ -22,17 +22,17 @@ package com.android.permissioncontroller.permission.model.livedatatypes
*
* @param name The name of the permission group whose UI data this represents
* @param nonSystemTotal The total number of non-system applications that request permissions in
- * this group
+ * this group
* @param nonSystemGranted The total number of non-system applications that request permissions in
- * this group, and have at least one permission in this group granted.
+ * this group, and have at least one permission in this group granted.
* @param nonSystemUserSetOrPreGranted The total number of non-system applications that request
- * permissions in this group, and have at least one permission in this group granted, or one
- * permission denied by the user
- * @param systemGranted The total number of system applications that request permissions in
- * this group, and have at least one permission in this group granted.
- * @param systemUserSetOrPreGranted The total number of system applications that request
- * permissions in this group, and have at least one permission in this group granted, or one
- * permission denied by the user
+ * permissions in this group, and have at least one permission in this group granted, or one
+ * permission denied by the user
+ * @param systemGranted The total number of system applications that request permissions in this
+ * group, and have at least one permission in this group granted.
+ * @param systemUserSetOrPreGranted The total number of system applications that request permissions
+ * in this group, and have at least one permission in this group granted, or one permission denied
+ * by the user
*/
data class PermGroupPackagesUiInfo(
val name: String,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/UidSensitivityState.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/UidSensitivityState.kt
index 3d0be0c0a..d8cdf01d6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/UidSensitivityState.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/UidSensitivityState.kt
@@ -22,8 +22,8 @@ package com.android.permissioncontroller.permission.model.livedatatypes
*
* @param packages A LightPackageInfo for every package with this uid
* @param permStates A map <requested permission name, use sensitive state>, with the state being a
- * combination of FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED and
- * FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED
+ * combination of FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED and
+ * FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED
*/
data class UidSensitivityState(
val packages: MutableSet<LightPackageInfo>,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt
index 4c2051f9c..d5451c208 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt
@@ -82,7 +82,10 @@ data class LightHistoricalPackageOps(
this.getDiscreteAccesses(permissionToOpNames.value)?.let {
appPermissionDiscreteAccesses.add(
AppPermissionDiscreteAccesses(
- AppPermissionId(packageName, userHandle, permissionToOpNames.key), it))
+ AppPermissionId(packageName, userHandle, permissionToOpNames.key),
+ it
+ )
+ )
}
}
@@ -117,7 +120,9 @@ data class LightHistoricalPackageOps(
mutableMapOf()
}
attributedAppPermissionDiscreteAccesses[appPermissionId]?.put(
- attributedHistoricalOps.tag ?: NO_ATTRIBUTION_TAG, discAccessData)
+ attributedHistoricalOps.tag ?: NO_ATTRIBUTION_TAG,
+ discAccessData
+ )
}
}
}
@@ -152,7 +157,9 @@ data class LightHistoricalPackageOps(
DiscreteAccess(
opEntry.getLastAccessTime(DISCRETE_ACCESS_OP_FLAGS),
opEntry.getLastDuration(DISCRETE_ACCESS_OP_FLAGS),
- opEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS)))
+ opEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS)
+ )
+ )
}
}
@@ -187,7 +194,9 @@ data class LightHistoricalPackageOps(
DiscreteAccess(
attributedOpEntry.getLastAccessTime(DISCRETE_ACCESS_OP_FLAGS),
attributedOpEntry.getLastDuration(DISCRETE_ACCESS_OP_FLAGS),
- attributedOpEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS)))
+ attributedOpEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS)
+ )
+ )
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightPackageOps.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightPackageOps.kt
index dde4857e2..b65fda5ea 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightPackageOps.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightPackageOps.kt
@@ -44,7 +44,8 @@ data class LightPackageOps(
) : this(
packageOps.packageName,
UserHandle.getUserHandleForUid(packageOps.uid),
- createLastPermissionGroupAccessTimesMap(ops, packageOps))
+ createLastPermissionGroupAccessTimesMap(ops, packageOps)
+ )
/** Companion object for [LightPackageOps]. */
companion object {
@@ -70,7 +71,8 @@ data class LightPackageOps(
lastAccessTimeMs[permissionGroupOfOp] =
maxOf(
lastAccessTimeMs[permissionGroupOfOp] ?: -1,
- opEntry.getLastAccessTime(OPS_LAST_ACCESS_FLAGS))
+ opEntry.getLastAccessTime(OPS_LAST_ACCESS_FLAGS)
+ )
}
return lastAccessTimeMs
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/LightInstallSourceInfo.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/LightInstallSourceInfo.kt
index e75c1eadf..85f77b823 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/LightInstallSourceInfo.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/LightInstallSourceInfo.kt
@@ -36,12 +36,12 @@ class LightInstallSourceInfo {
// default source of unspecified. All other sources should be explicitly set to another
// PACKAGE_SOURCE_ value
val isStoreInstalled =
- initiatingPackageName != null &&
- (packageSource == PACKAGE_SOURCE_STORE ||
- packageSource == PACKAGE_SOURCE_UNSPECIFIED)
+ initiatingPackageName != null &&
+ (packageSource == PACKAGE_SOURCE_STORE ||
+ packageSource == PACKAGE_SOURCE_UNSPECIFIED)
- isPreloadedApp = initiatingPackageName == null &&
- packageSource == PACKAGE_SOURCE_UNSPECIFIED
+ isPreloadedApp =
+ initiatingPackageName == null && packageSource == PACKAGE_SOURCE_UNSPECIFIED
supportsSafetyLabel = isStoreInstalled || isPreloadedApp
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/SafetyLabelInfo.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/SafetyLabelInfo.kt
index 7128e3069..2107e9944 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/SafetyLabelInfo.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/SafetyLabelInfo.kt
@@ -28,7 +28,7 @@ import com.android.permissioncontroller.permission.model.livedatatypes.v34.Light
class SafetyLabelInfo(
val safetyLabel: SafetyLabel?,
val installSourceInfo: LightInstallSourceInfo
- ) {
+) {
companion object {
/** Default definition of unavailable or no safety label found */
val UNAVAILABLE = SafetyLabelInfo(null, INSTALL_SOURCE_UNAVAILABLE)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt
index ae9ccf19e..8e1721219 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt
@@ -32,25 +32,25 @@ import com.android.permissioncontroller.PermissionControllerStatsLog
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_UNUSED_APP_PERMISSION_REVOKED
import com.android.permissioncontroller.hibernation.getUnusedThresholdMs
-import com.android.permissioncontroller.permission.utils.PermissionMapping
+import com.android.permissioncontroller.permission.data.AutoRevokedPackagesLiveData
import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData
import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData
import com.android.permissioncontroller.permission.data.get
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.application
import com.android.permissioncontroller.permission.utils.forEachInParallel
import com.android.permissioncontroller.permission.utils.updatePermissionFlags
-import kotlinx.coroutines.Dispatchers.Main
import java.util.concurrent.atomic.AtomicBoolean
+import kotlinx.coroutines.Dispatchers.Main
private const val LOG_TAG = "AutoRevokePermissions"
const val DEBUG_AUTO_REVOKE = true
-private val EXEMPT_PERMISSIONS = listOf(
- Manifest.permission.ACTIVITY_RECOGNITION,
- Manifest.permission.POST_NOTIFICATIONS)
+val AUTO_REVOKE_EXEMPT_PERMISSIONS =
+ listOf(Manifest.permission.ACTIVITY_RECOGNITION, Manifest.permission.POST_NOTIFICATIONS)
private val SERVER_LOG_ID =
PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_UNUSED_APP_PERMISSION_REVOKED
@@ -78,11 +78,14 @@ suspend fun revokeAppPermissions(
continue
}
- val pkgPermChanges = PermissionChangeStorageImpl.getInstance().loadEvents()
- .associateBy { it.packageName }
+ val pkgPermChanges =
+ PermissionChangeStorageImpl.getInstance().loadEvents().associateBy { it.packageName }
// For each autorevoke-eligible app...
- userApps.forEachInParallel(Main) forEachInParallelOuter@ { pkg: LightPackageInfo ->
+ userApps.forEachInParallel(Main) forEachInParallelOuter@{ pkg: LightPackageInfo ->
if (pkg.grantedPermissions.isEmpty()) {
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(LOG_TAG, "${pkg.packageName}: no granted permissions")
+ }
return@forEachInParallelOuter
}
val packageName = pkg.packageName
@@ -90,15 +93,28 @@ suspend fun revokeAppPermissions(
val now = System.currentTimeMillis()
if (pkgPermChange != null && now - pkgPermChange.eventTime < getUnusedThresholdMs()) {
if (DEBUG_AUTO_REVOKE) {
- DumpableLog.i(LOG_TAG, "Not revoking because permissions were changed " +
- "recently for package $packageName")
+ DumpableLog.i(
+ LOG_TAG,
+ "Not revoking because permissions were changed " +
+ "recently for package $packageName"
+ )
}
return@forEachInParallelOuter
}
val targetSdk = pkg.targetSdkVersion
- val pkgPermGroups: Map<String, List<String>> =
- PackagePermissionsLiveData[packageName, user]
- .getInitializedValue() ?: return@forEachInParallelOuter
+ val pkgPermGroups: Map<String, List<String>>? =
+ PackagePermissionsLiveData[packageName, user].getInitializedValue()
+
+ if (pkgPermGroups == null || pkgPermGroups.isEmpty()) {
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(LOG_TAG, "$packageName: no permission groups found.")
+ }
+ return@forEachInParallelOuter
+ }
+
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(LOG_TAG, "$packageName: perm groups: ${pkgPermGroups.keys}.")
+ }
// Determine which permGroups are revocable
val revocableGroups = mutableSetOf<String>()
@@ -110,26 +126,34 @@ suspend fun revokeAppPermissions(
continue
}
val group: LightAppPermGroup =
- LightAppPermGroupLiveData[packageName, groupName, user]
- .getInitializedValue() ?: continue
+ LightAppPermGroupLiveData[packageName, groupName, user].getInitializedValue()
+ ?: continue
val fixed = group.isBackgroundFixed || group.isForegroundFixed
- val granted = group.permissions.any { (_, perm) ->
- perm.isGrantedIncludingAppOp && perm.name !in EXEMPT_PERMISSIONS
- }
- if (!fixed && granted &&
- !group.isGrantedByDefault &&
- !group.isGrantedByRole &&
- !group.isRevokeWhenRequested &&
- group.isUserSensitive) {
+ val granted =
+ group.permissions.any { (_, perm) ->
+ perm.isGrantedIncludingAppOp && perm.name !in AUTO_REVOKE_EXEMPT_PERMISSIONS
+ }
+ if (
+ !fixed &&
+ granted &&
+ !group.isGrantedByDefault &&
+ !group.isGrantedByRole &&
+ !group.isRevokeWhenRequested &&
+ group.isUserSensitive
+ ) {
revocableGroups.add(groupName)
}
}
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(LOG_TAG, "$packageName: initial revocable groups: $revocableGroups")
+ }
+
// Mark any groups that split from an install-time permission as unrevocable
for (fromPerm in
- pkgPermGroups[PackagePermissionsLiveData.NON_RUNTIME_NORMAL_PERMS] ?: emptyList()) {
+ pkgPermGroups[PackagePermissionsLiveData.NON_RUNTIME_NORMAL_PERMS] ?: emptyList()) {
for (toGroup in
- splitPermissionIndex.getPermToGroupSplitsFrom(fromPerm, targetSdk)) {
+ splitPermissionIndex.getPermToGroupSplitsFrom(fromPerm, targetSdk)) {
revocableGroups.remove(toGroup)
}
}
@@ -138,88 +162,117 @@ suspend fun revokeAppPermissions(
for (groupName in pkgPermGroups.keys) {
if (!revocableGroups.contains(groupName)) {
for (fromGroup in
- splitPermissionIndex.getGroupToGroupSplitsTo(groupName, targetSdk)) {
+ splitPermissionIndex.getGroupToGroupSplitsTo(groupName, targetSdk)) {
revocableGroups.remove(fromGroup)
}
for (toGroup in
- splitPermissionIndex.getGroupToGroupSplitsFrom(groupName, targetSdk)) {
+ splitPermissionIndex.getGroupToGroupSplitsFrom(groupName, targetSdk)) {
revocableGroups.remove(toGroup)
}
}
}
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(LOG_TAG, "$packageName: final revocable groups: $revocableGroups")
+ }
// For each revocable group, revoke all of its permissions
val anyPermsRevoked = AtomicBoolean(false)
pkgPermGroups.entries
.filter { revocableGroups.contains(it.key) }
- .forEachInParallel(Main) forEachInParallelInner@ { (groupName, _) ->
- val group: LightAppPermGroup =
- LightAppPermGroupLiveData[packageName, groupName, user]
- .getInitializedValue()!!
+ .forEachInParallel(Main) forEachInParallelInner@{ (groupName, _) ->
+ val group: LightAppPermGroup =
+ LightAppPermGroupLiveData[packageName, groupName, user]
+ .getInitializedValue()!!
- val revocablePermissions = group.permissions.keys.toList()
+ val revocablePermissions = group.permissions.keys.toList()
- if (revocablePermissions.isEmpty()) {
- return@forEachInParallelInner
- }
+ if (revocablePermissions.isEmpty()) {
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(LOG_TAG, "$packageName: revocable permissions empty")
+ }
+ return@forEachInParallelInner
+ }
- if (DEBUG_AUTO_REVOKE) {
- DumpableLog.i(LOG_TAG,
- "revokeUnused $packageName - $revocablePermissions")
- }
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(LOG_TAG, "revokeUnused $packageName - $revocablePermissions")
+ }
- val uid = group.packageInfo.uid
- for (permName in revocablePermissions) {
- PermissionControllerStatsLog.write(
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED,
- sessionId, uid, packageName, permName, false, SERVER_LOG_ID,
- /* permission_rationale_shown = */ false)
- }
+ val uid = group.packageInfo.uid
+ for (permName in revocablePermissions) {
+ PermissionControllerStatsLog.write(
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED,
+ sessionId,
+ uid,
+ packageName,
+ permName,
+ false,
+ SERVER_LOG_ID,
+ /* permission_rationale_shown = */ false
+ )
+ }
- if (DEBUG_AUTO_REVOKE) {
- DumpableLog.i(LOG_TAG, "revoking $packageName - $revocablePermissions")
- DumpableLog.i(LOG_TAG, "State pre revocation: ${group.allPermissions}")
- }
- anyPermsRevoked.compareAndSet(false, true)
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(LOG_TAG, "revoking $packageName - $revocablePermissions")
+ DumpableLog.i(LOG_TAG, "State pre revocation: ${group.allPermissions}")
+ }
+ anyPermsRevoked.compareAndSet(false, true)
- val bgRevokedState = KotlinUtils.revokeBackgroundRuntimePermissions(
- context.application, group,
- userFixed = false, oneTime = false,
- filterPermissions = revocablePermissions)
- if (DEBUG_AUTO_REVOKE) {
- DumpableLog.i(LOG_TAG,
- "Bg state post revocation: ${bgRevokedState.allPermissions}")
- }
- val fgRevokedState = KotlinUtils.revokeForegroundRuntimePermissions(
- context.application, group,
- userFixed = false, oneTime = false,
- filterPermissions = revocablePermissions)
- if (DEBUG_AUTO_REVOKE) {
- DumpableLog.i(LOG_TAG,
- "Fg state post revocation: ${fgRevokedState.allPermissions}")
- }
+ val bgRevokedState =
+ KotlinUtils.revokeBackgroundRuntimePermissions(
+ context.application,
+ group,
+ userFixed = false,
+ oneTime = false,
+ filterPermissions = revocablePermissions
+ )
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(
+ LOG_TAG,
+ "Bg state post revocation: ${bgRevokedState.allPermissions}"
+ )
+ }
+ val fgRevokedState =
+ KotlinUtils.revokeForegroundRuntimePermissions(
+ context.application,
+ group,
+ userFixed = false,
+ oneTime = false,
+ filterPermissions = revocablePermissions
+ )
+ if (DEBUG_AUTO_REVOKE) {
+ DumpableLog.i(
+ LOG_TAG,
+ "Fg state post revocation: ${fgRevokedState.allPermissions}"
+ )
+ }
- for (permission in revocablePermissions) {
- context.packageManager.updatePermissionFlags(
- permission, packageName, user,
- FLAG_PERMISSION_AUTO_REVOKED to true,
- FLAG_PERMISSION_USER_SET to false)
+ for (permission in revocablePermissions) {
+ context.packageManager.updatePermissionFlags(
+ permission,
+ packageName,
+ user,
+ FLAG_PERMISSION_AUTO_REVOKED to true,
+ FLAG_PERMISSION_USER_SET to false
+ )
+ }
}
- }
if (anyPermsRevoked.get()) {
- synchronized(revokedApps) {
- revokedApps.add(packageName to user)
- }
+ synchronized(revokedApps) { revokedApps.add(packageName to user) }
}
}
if (DEBUG_AUTO_REVOKE) {
synchronized(revokedApps) {
- DumpableLog.i(LOG_TAG,
- "Done auto-revoke for user ${user.identifier} - revoked $revokedApps")
+ DumpableLog.i(
+ LOG_TAG,
+ "Done auto-revoke for user ${user.identifier} - revoked $revokedApps"
+ )
}
}
}
+ if (revokedApps.isNotEmpty()) {
+ AutoRevokedPackagesLiveData.update()
+ }
return revokedApps
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java b/PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java
index 9082b6931..39e289fd2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/BackupHelper.java
@@ -136,8 +136,8 @@ public class BackupHelper {
case END_TAG:
numOpenTags--;
break;
- default:
- // ignore
+ case END_DOCUMENT:
+ return;
}
}
}
@@ -763,8 +763,6 @@ public class BackupHelper {
return new BackupSigningInfoState(
currentCertDigests,
pastCertDigests);
- default:
- throw new XmlPullParserException("Could not parse signing info");
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/BasePermissionEventStorage.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/BasePermissionEventStorage.kt
index 840b7e483..8bbb41c56 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/BasePermissionEventStorage.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/BasePermissionEventStorage.kt
@@ -22,17 +22,14 @@ import android.util.AtomicFile
import android.util.Log
import com.android.permissioncontroller.DumpableLog
import com.android.permissioncontroller.permission.data.PermissionEvent
-import org.xmlpull.v1.XmlPullParserException
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
+import org.xmlpull.v1.XmlPullParserException
-/**
- * Thread-safe implementation of [PermissionEventStorage] using an XML file as the
- * database.
- */
+/** Thread-safe implementation of [PermissionEventStorage] using an XML file as the database. */
abstract class BasePermissionEventStorage<T : PermissionEvent>(
private val context: Context,
jobScheduler: JobScheduler = context.getSystemService(JobScheduler::class.java)!!
@@ -75,9 +72,7 @@ abstract class BasePermissionEventStorage<T : PermissionEvent>(
}
override suspend fun clearEvents() {
- synchronized(fileLock) {
- dbFile.delete()
- }
+ synchronized(fileLock) { dbFile.delete() }
}
override suspend fun removeOldData(): Boolean {
@@ -85,12 +80,15 @@ abstract class BasePermissionEventStorage<T : PermissionEvent>(
val existingEvents = readData()
val originalCount = existingEvents.size
- val newEvents = existingEvents.filter {
- (System.currentTimeMillis() - it.eventTime) <= getMaxDataAgeMs()
- }
+ val newEvents =
+ existingEvents.filter {
+ (System.currentTimeMillis() - it.eventTime) <= getMaxDataAgeMs()
+ }
- DumpableLog.d(LOG_TAG,
- "${originalCount - newEvents.size} old permission events removed")
+ DumpableLog.d(
+ LOG_TAG,
+ "${originalCount - newEvents.size} old permission events removed"
+ )
return writeData(newEvents)
}
@@ -109,20 +107,19 @@ abstract class BasePermissionEventStorage<T : PermissionEvent>(
synchronized(fileLock) {
val existingEvents = readData()
- val newEvents = existingEvents.map {
- it.copyWithTimeDelta(diffSystemTimeMillis)
- }
+ val newEvents = existingEvents.map { it.copyWithTimeDelta(diffSystemTimeMillis) }
return writeData(newEvents)
}
}
private fun writeData(events: List<T>): Boolean {
- val stream: FileOutputStream = try {
- dbFile.startWrite()
- } catch (e: IOException) {
- Log.e(LOG_TAG, "Failed to save db file", e)
- return false
- }
+ val stream: FileOutputStream =
+ try {
+ dbFile.startWrite()
+ } catch (e: IOException) {
+ Log.e(LOG_TAG, "Failed to save db file", e)
+ return false
+ }
try {
serialize(stream, events)
dbFile.finishWrite(stream)
@@ -167,23 +164,15 @@ abstract class BasePermissionEventStorage<T : PermissionEvent>(
@Throws(XmlPullParserException::class, IOException::class)
abstract fun parse(inputStream: InputStream): List<T>
- /**
- * Returns file name for database.
- */
+ /** Returns file name for database. */
abstract fun getDatabaseFileName(): String
- /**
- * Returns max time that data should be persisted before being removed.
- */
+ /** Returns max time that data should be persisted before being removed. */
abstract fun getMaxDataAgeMs(): Long
- /**
- * Returns true if the two events have the same primary key for the database store.
- */
+ /** Returns true if the two events have the same primary key for the database store. */
abstract fun hasTheSamePrimaryKey(first: T, second: T): Boolean
- /**
- * Copies the event with the time delta applied to the [PermissionEvent.eventTime].
- */
+ /** Copies the event with the time delta applied to the [PermissionEvent.eventTime]. */
abstract fun T.copyWithTimeDelta(timeDelta: Long): T
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/CheckLifecycleRegistry.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/CheckLifecycleRegistry.kt
index 506fa0ef0..678caa168 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/CheckLifecycleRegistry.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/CheckLifecycleRegistry.kt
@@ -29,17 +29,13 @@ class CheckLifecycleRegistry(provider: LifecycleOwner) : LifecycleRegistry(provi
if (Looper.myLooper() != Looper.getMainLooper()) {
throw IllegalStateException("Lifecycle running on non main thread")
}
- synchronized(observerLock) {
- super.addObserver(observer)
- }
+ synchronized(observerLock) { super.addObserver(observer) }
}
override fun removeObserver(observer: LifecycleObserver) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw IllegalStateException("Lifecycle running on non main thread")
}
- synchronized(observerLock) {
- super.removeObserver(observer)
- }
+ synchronized(observerLock) { super.removeObserver(observer) }
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/ExemptRestrictedPermission.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/ExemptRestrictedPermission.kt
index dbf844b27..33e579eef 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/ExemptRestrictedPermission.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/ExemptRestrictedPermission.kt
@@ -8,8 +8,8 @@ import android.os.Process
import android.os.UserHandle
/**
- * For manually exempting a restricted permission.
- * STOPSHIP This functionality should not be in the final release.
+ * For manually exempting a restricted permission. STOPSHIP This functionality should not be in the
+ * final release.
*/
class ExemptRestrictedPermission : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -21,7 +21,10 @@ class ExemptRestrictedPermission : BroadcastReceiver() {
// Use upgrade flag. If the permission needs to be manually exempted then it probably
// should have been done on upgrade.
- userContext.packageManager.addWhitelistedRestrictedPermission(packageName, permission,
- PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE)
+ userContext.packageManager.addWhitelistedRestrictedPermission(
+ packageName,
+ permission,
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ )
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java b/PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java
index e21be6a05..e258b42cd 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java
@@ -41,6 +41,9 @@ import static android.os.UserHandle.getUserHandleForUid;
import static android.os.UserHandle.myUserId;
import static android.provider.Settings.Secure.LOCATION_ACCESS_CHECK_DELAY_MILLIS;
import static android.provider.Settings.Secure.LOCATION_ACCESS_CHECK_INTERVAL_MILLIS;
+import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID;
+import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID;
+import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_USER_HANDLE;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
@@ -75,6 +78,7 @@ import static java.util.concurrent.TimeUnit.DAYS;
import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
import android.app.AppOpsManager.PackageOps;
+import android.app.Application;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -123,6 +127,8 @@ import androidx.annotation.WorkerThread;
import androidx.core.util.Preconditions;
import com.android.modules.utils.build.SdkLevel;
+import com.android.permissioncontroller.Constants;
+import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
@@ -409,30 +415,24 @@ public class LocationAccessCheck {
@WorkerThread
private void addLocationNotificationIfNeeded(@NonNull JobParameters params,
@NonNull LocationAccessCheckJobService service) {
- if (!checkLocationAccessCheckEnabledAndUpdateEnabledTime()) {
- Log.v(LOG_TAG, "LocationAccessCheck feature is not enabled.");
- service.jobFinished(params, false);
- return;
- }
-
synchronized (sLock) {
try {
if (currentTimeMillis() - mSharedPrefs.getLong(
KEY_LAST_LOCATION_ACCESS_NOTIFICATION_SHOWN, 0)
< getInBetweenNotificationsMillis()) {
- Log.v(LOG_TAG, "location notification interval is not enough.");
+ Log.i(LOG_TAG, "location notification interval is not enough.");
service.jobFinished(params, false);
return;
}
if (getCurrentlyShownNotificationLocked() != null) {
- Log.v(LOG_TAG, "already location notification exist.");
+ Log.i(LOG_TAG, "already location notification exist.");
service.jobFinished(params, false);
return;
}
addLocationNotificationIfNeeded(mAppOpsManager.getPackagesForOps(
- new String[]{OPSTR_FINE_LOCATION}));
+ new String[]{OPSTR_FINE_LOCATION}), service.getApplication());
service.jobFinished(params, false);
} catch (Exception e) {
Log.e(LOG_TAG, "Could not check for location access", e);
@@ -440,20 +440,19 @@ public class LocationAccessCheck {
} finally {
synchronized (sLock) {
service.mAddLocationNotificationIfNeededTask = null;
- Log.v(LOG_TAG, "LocationAccessCheck privacy job marked complete.");
}
}
}
}
- private void addLocationNotificationIfNeeded(@NonNull List<PackageOps> ops)
+ private void addLocationNotificationIfNeeded(@NonNull List<PackageOps> ops, Application app)
throws InterruptedException {
synchronized (sLock) {
List<UserPackage> packages = getLocationUsersLocked(ops);
ArraySet<UserPackage> alreadyNotifiedPackages = loadAlreadyNotifiedPackagesLocked();
if (DEBUG) {
- Log.v(LOG_TAG, "location packages: " + packages);
- Log.v(LOG_TAG, "already notified packages: " + alreadyNotifiedPackages);
+ Log.d(LOG_TAG, "location packages: " + packages);
+ Log.d(LOG_TAG, "already notified packages: " + alreadyNotifiedPackages);
}
throwInterruptedExceptionIfTaskIsCanceled();
// Send these issues to safety center
@@ -471,7 +470,7 @@ public class LocationAccessCheck {
if (packages.isEmpty()) {
if (DEBUG) {
- Log.v(LOG_TAG, "No package found to send a notification");
+ Log.d(LOG_TAG, "No package found to send a notification");
}
return;
}
@@ -503,7 +502,7 @@ public class LocationAccessCheck {
}
}
createPermissionReminderChannel(getUserHandleForUid(pkgInfo.applicationInfo.uid));
- createNotificationForLocationUser(pkgInfo);
+ createNotificationForLocationUser(pkgInfo, app);
}
}
@@ -583,8 +582,8 @@ public class LocationAccessCheck {
// to handle cases where the feature is remotely toggled since we don't want to
// notify for accesses before the feature was turned on.
long featureEnabledTime = getLocationAccessCheckEnabledTime();
- if (featureEnabledTime >= 0 && entry.getLastAccessBackgroundTime(
- AppOpsManager.OP_FLAGS_ALL_TRUSTED) >= featureEnabledTime) {
+ if (entry.getLastAccessBackgroundTime(AppOpsManager.OP_FLAGS_ALL_TRUSTED)
+ >= featureEnabledTime) {
pkgsWithLocationAccess.add(userPkg);
break;
}
@@ -601,36 +600,27 @@ public class LocationAccessCheck {
}
/**
- * Checks whether the location access check feature is enabled and updates the
- * time when the feature was first enabled. If the feature is enabled and no
- * enabled time persisted we persist the current time as the enabled time. If
- * the feature is disabled and an enabled time is persisted we delete the
- * persisted time.
- *
- * @return Whether the location access feature is enabled.
+ * Sets the LocationAccessCheckEnabledTime if not set.
*/
- private boolean checkLocationAccessCheckEnabledAndUpdateEnabledTime() {
- final long enabledTime = getLocationAccessCheckEnabledTime();
- if (Utils.isLocationAccessCheckEnabled()) {
- if (enabledTime <= 0) {
- mSharedPrefs.edit().putLong(KEY_LOCATION_ACCESS_CHECK_ENABLED_TIME,
- currentTimeMillis()).commit();
- }
- return true;
- } else {
- if (enabledTime > 0) {
- mSharedPrefs.edit().remove(KEY_LOCATION_ACCESS_CHECK_ENABLED_TIME)
- .commit();
- }
- return false;
+ private void setLocationAccessCheckEnabledTime() {
+ if (isLocationAccessCheckEnabledTimeNotSet()) {
+ mSharedPrefs.edit().putLong(KEY_LOCATION_ACCESS_CHECK_ENABLED_TIME,
+ currentTimeMillis()).apply();
}
}
/**
- * @return The time the location access check was enabled, or 0 if not enabled.
+ * @return true if the LocationAccessCheckEnabledTime has not been set, else false.
+ */
+ private boolean isLocationAccessCheckEnabledTimeNotSet() {
+ return mSharedPrefs.getLong(KEY_LOCATION_ACCESS_CHECK_ENABLED_TIME, 0) == 0;
+ }
+
+ /**
+ * @return The time the location access check was enabled, or currentTimeMillis if not set.
*/
private long getLocationAccessCheckEnabledTime() {
- return mSharedPrefs.getLong(KEY_LOCATION_ACCESS_CHECK_ENABLED_TIME, 0);
+ return mSharedPrefs.getLong(KEY_LOCATION_ACCESS_CHECK_ENABLED_TIME, currentTimeMillis());
}
/**
@@ -639,7 +629,7 @@ public class LocationAccessCheck {
*
* @param pkg The {@link PackageInfo} for the package to to be changed
*/
- private void createNotificationForLocationUser(@NonNull PackageInfo pkg) {
+ private void createNotificationForLocationUser(@NonNull PackageInfo pkg, Application app) {
CharSequence pkgLabel = mPackageManager.getApplicationLabel(pkg.applicationInfo);
boolean safetyCenterBgLocationReminderEnabled = isSafetyCenterBgLocationReminderEnabled();
@@ -707,20 +697,27 @@ public class LocationAccessCheck {
b.setLargeIcon(pkgIconBmp);
}
+ Bundle extras = new Bundle();
+ if (DeviceUtils.isAuto(mContext)) {
+ Bitmap settingsIcon = KotlinUtils.INSTANCE.getSettingsIcon(app, user, mPackageManager);
+ b.setLargeIcon(settingsIcon);
+ extras.putBoolean(Constants.NOTIFICATION_EXTRA_USE_LAUNCHER_ICON, false);
+ }
+
if (!TextUtils.isEmpty(appLabel)) {
- Bundle extras = new Bundle();
String appNameSubstitute = appLabel.toString();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appNameSubstitute);
- b.addExtras(extras);
}
+ b.addExtras(extras);
notificationManager.notify(pkgName, LOCATION_ACCESS_CHECK_NOTIFICATION_ID, b.build());
markAsNotified(pkgName, user, false);
- if (DEBUG) Log.i(LOG_TAG, "Notified " + pkgName);
-
- Log.v(LOG_TAG, "Location access check notification shown with sessionId=" + sessionId + ""
- + " uid=" + pkg.applicationInfo.uid + " pkgName=" + pkgName);
+ if (DEBUG) {
+ Log.d(LOG_TAG,
+ "Location access check notification shown with sessionId=" + sessionId + ""
+ + " uid=" + pkg.applicationInfo.uid + " pkgName=" + pkgName);
+ }
if (safetyCenterBgLocationReminderEnabled) {
PermissionControllerStatsLog.write(
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
@@ -1054,6 +1051,10 @@ public class LocationAccessCheck {
Intent clickIntent = null;
if (isSafetyCenterBgLocationReminderEnabled()) {
clickIntent = new Intent(ACTION_SAFETY_CENTER);
+ clickIntent.putExtra(EXTRA_SAFETY_SOURCE_ID, BG_LOCATION_SOURCE_ID);
+ clickIntent.putExtra(
+ EXTRA_SAFETY_SOURCE_ISSUE_ID, createSafetySourceIssueId(pkg, user));
+ clickIntent.putExtra(EXTRA_SAFETY_SOURCE_USER_HANDLE, user);
} else {
clickIntent = new Intent(ACTION_MANAGE_APP_PERMISSION);
clickIntent.putExtra(EXTRA_PERMISSION_GROUP_NAME, LOCATION);
@@ -1128,7 +1129,7 @@ public class LocationAccessCheck {
}
// Init LocationAccessCheckEnabledTime if needed
- locationAccessCheck.checkLocationAccessCheckEnabledAndUpdateEnabledTime();
+ locationAccessCheck.setLocationAccessCheckEnabledTime();
if (jobScheduler.getPendingJob(PERIODIC_LOCATION_ACCESS_CHECK_JOB_ID) == null) {
JobInfo.Builder b = (new JobInfo.Builder(PERIODIC_LOCATION_ACCESS_CHECK_JOB_ID,
@@ -1159,7 +1160,6 @@ public class LocationAccessCheck {
@Override
public void onCreate() {
- Log.v(LOG_TAG, "LocationAccessCheck privacy job is created");
super.onCreate();
mLocationAccessCheck = new LocationAccessCheck(this, () -> {
synchronized (sLock) {
@@ -1178,10 +1178,9 @@ public class LocationAccessCheck {
*/
@Override
public boolean onStartJob(JobParameters params) {
- Log.v(LOG_TAG, "LocationAccessCheck privacy job is started");
synchronized (LocationAccessCheck.sLock) {
if (mAddLocationNotificationIfNeededTask != null) {
- Log.v(LOG_TAG, "LocationAccessCheck old job not completed yet.");
+ Log.i(LOG_TAG, "LocationAccessCheck old job not completed yet.");
return false;
}
@@ -1202,7 +1201,6 @@ public class LocationAccessCheck {
*/
@Override
public boolean onStopJob(JobParameters params) {
- Log.v(LOG_TAG, "LocationAccessCheck privacy source onStopJob called.");
AddLocationNotificationIfNeededTask task;
synchronized (sLock) {
if (mAddLocationNotificationIfNeededTask == null) {
@@ -1250,7 +1248,7 @@ public class LocationAccessCheck {
long sessionId = intent.getLongExtra(EXTRA_SESSION_ID, INVALID_SESSION_ID);
int uid = intent.getIntExtra(EXTRA_UID, -1);
- Log.v(LOG_TAG,
+ Log.i(LOG_TAG,
"Location access check notification declined with sessionId=" + sessionId + ""
+ " uid=" + uid + " pkgName=" + pkg);
LocationAccessCheck locationAccessCheck = new LocationAccessCheck(context, null);
@@ -1325,7 +1323,7 @@ public class LocationAccessCheck {
UserHandle user = getParcelableExtraSafe(intent, EXTRA_USER);
long sessionId = intent.getLongExtra(EXTRA_SESSION_ID, INVALID_SESSION_ID);
int uid = intent.getIntExtra(EXTRA_UID, -1);
- Log.v(LOG_TAG,
+ Log.i(LOG_TAG,
"Location access check warning card dismissed with sessionId=" + sessionId + ""
+ " uid=" + uid + " pkgName=" + pkg);
PermissionControllerStatsLog.write(
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt
index bdcf833fc..5a49b7ebe 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt
@@ -25,12 +25,6 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.hibernation.getUnusedThresholdMs
import com.android.permissioncontroller.permission.data.PermissionChange
import com.android.permissioncontroller.permission.utils.Utils
-import kotlinx.coroutines.DelicateCoroutinesApi
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
-import org.xmlpull.v1.XmlPullParser
-import org.xmlpull.v1.XmlPullParserException
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
@@ -39,6 +33,12 @@ import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParserException
/**
* Implementation of [BasePermissionEventStorage] for storing [PermissionChange] events for long
@@ -52,14 +52,10 @@ class PermissionChangeStorageImpl(
// We don't use namespaces
private val ns: String? = null
- /**
- * The format for how dates are stored.
- */
+ /** The format for how dates are stored. */
private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US)
- /**
- * Exact format if [PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME] is true
- */
+ /** Exact format if [PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME] is true */
private val exactTimeFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US)
companion object {
@@ -67,9 +63,7 @@ class PermissionChangeStorageImpl(
private const val DB_VERSION = 1
- /**
- * Config store file name for general shared store file.
- */
+ /** Config store file name for general shared store file. */
private const val STORE_FILE_NAME = "permission_changes.xml"
private const val TAG_PERMISSION_CHANGES = "permission-changes"
@@ -79,13 +73,10 @@ class PermissionChangeStorageImpl(
private const val ATTR_PACKAGE_NAME = "package-name"
private const val ATTR_EVENT_TIME = "event-time"
- @Volatile
- private var INSTANCE: PermissionEventStorage<PermissionChange>? = null
+ @Volatile private var INSTANCE: PermissionEventStorage<PermissionChange>? = null
fun getInstance(): PermissionEventStorage<PermissionChange> =
- INSTANCE ?: synchronized(this) {
- INSTANCE ?: createInstance().also { INSTANCE = it }
- }
+ INSTANCE ?: synchronized(this) { INSTANCE ?: createInstance().also { INSTANCE = it } }
private fun createInstance(): PermissionEventStorage<PermissionChange> {
return PermissionChangeStorageImpl(PermissionControllerApplication.get())
@@ -142,9 +133,7 @@ class PermissionChangeStorageImpl(
val storesExactTime = storesExactTime()
val truncateToDay = didStoreExactTime != storesExactTime && !storesExactTime
while (parser.next() != XmlPullParser.END_TAG) {
- readPermissionChange(parser, format, truncateToDay)?.let {
- entries.add(it)
- }
+ readPermissionChange(parser, format, truncateToDay)?.let { entries.add(it) }
}
return entries
}
@@ -160,9 +149,11 @@ class PermissionChangeStorageImpl(
try {
val packageName = parser.getAttributeValueNullSafe(ns, ATTR_PACKAGE_NAME)
val changeDate = parser.getAttributeValueNullSafe(ns, ATTR_EVENT_TIME)
- var changeTime = format.parse(changeDate)?.time
- ?: throw IllegalArgumentException(
- "Could not parse date $changeDate on package $packageName")
+ var changeTime =
+ format.parse(changeDate)?.time
+ ?: throw IllegalArgumentException(
+ "Could not parse date $changeDate on package $packageName"
+ )
if (truncateToDay) {
changeTime = dateFormat.parse(dateFormat.format(Date(changeTime)))!!.time
}
@@ -184,7 +175,8 @@ class PermissionChangeStorageImpl(
private fun XmlPullParser.getAttributeValueNullSafe(namespace: String?, name: String): String {
return this.getAttributeValue(namespace, name)
?: throw XmlPullParserException(
- "Could not find attribute: namespace $namespace, name $name")
+ "Could not find attribute: namespace $namespace, name $name"
+ )
}
override fun getDatabaseFileName(): String {
@@ -204,11 +196,12 @@ class PermissionChangeStorageImpl(
return this.copy(eventTime = this.eventTime + timeDelta)
}
- /**
- * Should only be true in tests and never true in prod.
- */
+ /** Should only be true in tests and never true in prod. */
private fun storesExactTime(): Boolean {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PERMISSIONS,
- Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME, /* defaultValue= */ false)
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PERMISSIONS,
+ Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME,
+ /* defaultValue= */ false
+ )
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
index d5c43335c..3e7ebfec0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
@@ -30,6 +30,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import android.Manifest;
import android.app.admin.DevicePolicyManager;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -62,6 +63,7 @@ import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGr
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState;
import com.android.permissioncontroller.permission.ui.AutoGrantPermissionsNotifier;
import com.android.permissioncontroller.permission.utils.ArrayUtils;
+import com.android.permissioncontroller.permission.utils.ContextCompat;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.UserSensitiveFlagsUtils;
@@ -641,7 +643,14 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
@Override
public void onOneTimePermissionSessionTimeout(@NonNull String packageName) {
- PackageManager pm = getPackageManager();
+ onOneTimePermissionSessionTimeout(packageName, ContextCompat.DEVICE_ID_DEFAULT);
+ }
+
+ @Override
+ public void onOneTimePermissionSessionTimeout(@NonNull String packageName,
+ int deviceId) {
+ Context deviceContext = ContextCompat.createDeviceContext(this, deviceId);
+ PackageManager pm = deviceContext.getPackageManager();
PackageInfo packageInfo;
int uid;
try {
@@ -655,11 +664,10 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
if (permissions == null) {
return;
}
-
Set<AppPermissionGroup> groups = new ArraySet<>();
for (String permission : permissions) {
- AppPermissionGroup group = AppPermissionGroup.create(this, packageInfo, permission,
- true);
+ AppPermissionGroup group = AppPermissionGroup.create(deviceContext, packageInfo,
+ permission, true);
if (group != null) {
AppPermissionGroup bgGroup = group.getBackgroundPermissions();
boolean isBgGroupOneTime = bgGroup != null && bgGroup.isOneTime();
@@ -730,7 +738,7 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
for (Permission permission : group.getPermissions()) {
if (permission.isGranted()) {
String permName = permission.getName();
- Log.v(LOG_TAG,
+ Log.i(LOG_TAG,
"Permission grant result requestId=" + requestId + " callingUid="
+ uid + " callingPackage=" + packageName + " permission="
+ permName + " isImplicit=false" + " result=" + r);
@@ -779,13 +787,21 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
+ onRevokeSelfPermissionsOnKill(
+ packageName, permissions, ContextCompat.DEVICE_ID_DEFAULT, callback);
+ }
+
+ @Override
+ public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
+ @NonNull List<String> permissions, int deviceId, @NonNull Runnable callback) {
+ Context deviceContext = ContextCompat.createDeviceContext(this, deviceId);
PackageInfo pkgInfo = getPkgInfo(packageName);
if (pkgInfo == null) {
throw new SecurityException("Cannot revoke permission " + String.join(",", permissions)
+ " for package " + packageName);
}
Set<AppPermissionGroup> groups = new HashSet<>();
- AppPermissions app = new AppPermissions(this, pkgInfo, false, true, null);
+ AppPermissions app = new AppPermissions(deviceContext, pkgInfo, false, true, null);
for (String permName : permissions) {
AppPermissionGroup group = app.getGroupForPermission(permName);
if (group == null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt
index 4b239ec71..fc812a71f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt
@@ -28,7 +28,6 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.map
import com.android.permissioncontroller.DumpableLog
import com.android.permissioncontroller.PermissionControllerProto.PermissionControllerDumpProto
-import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.data.AppPermGroupUiInfoLiveData
import com.android.permissioncontroller.permission.data.HibernationSettingStateLiveData
import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData
@@ -39,14 +38,15 @@ import com.android.permissioncontroller.permission.data.getUnusedPackages
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.Utils
+import java.util.function.IntConsumer
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
-import java.util.function.IntConsumer
/**
* A model for the PermissionControllerServiceImpl. Handles the data gathering for some methods of
@@ -57,10 +57,10 @@ class PermissionControllerServiceModel(private val service: PermissionController
private val observedLiveDatas = mutableListOf<LiveData<*>>()
/**
- * *Must* be used instead of LiveData.observe, in order to allow the lifecycle state to
- * be set to "started" correctly. If the liveData was inactive, create a no op observer, which
- * will survive until the service goes inactive. Will remove the provided observer after one
- * update (one non-stale update, in the case of a SmartUpdateMediatorLiveData).
+ * *Must* be used instead of LiveData.observe, in order to allow the lifecycle state to be set
+ * to "started" correctly. If the liveData was inactive, create a no op observer, which will
+ * survive until the service goes inactive. Will remove the provided observer after one update
+ * (one non-stale update, in the case of a SmartUpdateMediatorLiveData).
*
* @param liveData The livedata we wish to observe
* @param onChangedFun The function we wish to be called upon livedata updates
@@ -72,14 +72,13 @@ class PermissionControllerServiceModel(private val service: PermissionController
onChangedFun: (t: T?) -> Unit
) {
GlobalScope.launch(Main.immediate) {
-
if (service.lifecycle.currentState != Lifecycle.State.STARTED) {
service.setLifecycleToStarted()
}
if (!liveData.hasActiveObservers()) {
observedLiveDatas.add(liveData)
- liveData.observe(service, Observer { })
+ liveData.observe(service, Observer {})
}
if (forceUpdate && liveData is SmartUpdateMediatorLiveData<T>) {
@@ -87,27 +86,28 @@ class PermissionControllerServiceModel(private val service: PermissionController
}
var updated = false
- val observer = object : Observer<T> {
- override fun onChanged(value: T) {
- if (updated) {
- return
- }
- if ((liveData is SmartUpdateMediatorLiveData<T> && !liveData.isStale) ||
- liveData !is SmartUpdateMediatorLiveData<T>) {
- onChangedFun(value)
- liveData.removeObserver(this)
- updated = true
+ val observer =
+ object : Observer<T> {
+ override fun onChanged(value: T) {
+ if (updated) {
+ return
+ }
+ if (
+ (liveData is SmartUpdateMediatorLiveData<T> && !liveData.isStale) ||
+ liveData !is SmartUpdateMediatorLiveData<T>
+ ) {
+ onChangedFun(value)
+ liveData.removeObserver(this)
+ updated = true
+ }
}
}
- }
liveData.observe(service, observer)
}
}
- /**
- * Stop observing all currently observed liveDatas
- */
+ /** Stop observing all currently observed liveDatas */
fun removeObservers() {
GlobalScope.launch(Main.immediate) {
for (liveData in observedLiveDatas) {
@@ -133,17 +133,16 @@ class PermissionControllerServiceModel(private val service: PermissionController
) {
val packageInfosLiveData = UserPackageInfosLiveData[Process.myUserHandle()]
observeAndCheckForLifecycleState(packageInfosLiveData) { packageInfos ->
- onPackagesLoadedForCountPermissionApps(permissionNames, flags, callback,
- packageInfos)
+ onPackagesLoadedForCountPermissionApps(permissionNames, flags, callback, packageInfos)
}
}
/**
- * Called upon receiving a list of packages which we want to filter by a list of permissions
- * and flags. Observes the AppPermGroupUiInfoLiveData for every app, and, upon receiving a
- * non-stale update, adds it to the count if it matches the permission list and flags. Will
- * only use the first non-stale update, so if an app is updated after this update, but before
- * execution is complete, the changes will not be reflected until the method is called again.
+ * Called upon receiving a list of packages which we want to filter by a list of permissions and
+ * flags. Observes the AppPermGroupUiInfoLiveData for every app, and, upon receiving a non-stale
+ * update, adds it to the count if it matches the permission list and flags. Will only use the
+ * first non-stale update, so if an app is updated after this update, but before execution is
+ * complete, the changes will not be reflected until the method is called again.
*
* @param permissionNames The list of permission names whose apps we want to count
* @param flags Flags specifying if we want to count system apps, and count only granted apps
@@ -167,11 +166,12 @@ class PermissionControllerServiceModel(private val service: PermissionController
// Store the group of all installed, runtime permissions in permissionNames
val permToGroup = mutableMapOf<String, String?>()
for (permName in permissionNames) {
- val permInfo = try {
- service.packageManager.getPermissionInfo(permName, 0)
- } catch (e: PackageManager.NameNotFoundException) {
- continue
- }
+ val permInfo =
+ try {
+ service.packageManager.getPermissionInfo(permName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ continue
+ }
if (Utils.isPermissionDangerousInstalledNotRemoved(permInfo)) {
permToGroup[permName] = PermissionMapping.getGroupOfPermission(permInfo)
@@ -184,8 +184,10 @@ class PermissionControllerServiceModel(private val service: PermissionController
val packageUiLiveDatas = mutableSetOf<AppPermGroupUiInfoLiveData>()
for (permName in permToGroup.keys) {
if (requestedPermissions.contains(permName)) {
- packageUiLiveDatas.add(AppPermGroupUiInfoLiveData[packageName,
- permToGroup[permName]!!, Process.myUserHandle()])
+ packageUiLiveDatas.add(
+ AppPermGroupUiInfoLiveData[
+ packageName, permToGroup[permName]!!, Process.myUserHandle()]
+ )
}
}
if (packageUiLiveDatas.isNotEmpty()) {
@@ -211,8 +213,9 @@ class PermissionControllerServiceModel(private val service: PermissionController
numPermAppsChecked++
if (uiInfo != null && uiInfo.shouldShow && (!uiInfo.isSystem || countSystem)) {
- val granted = uiInfo.permGrantState != PermGrantState.PERMS_DENIED &&
- uiInfo.permGrantState != PermGrantState.PERMS_ASK
+ val granted =
+ uiInfo.permGrantState != PermGrantState.PERMS_DENIED &&
+ uiInfo.permGrantState != PermGrantState.PERMS_ASK
if (granted || !countOnlyGranted && !packageAdded) {
// The permission might not be granted, but some permissions of the
// group are granted. In this case the permission is granted silently
@@ -244,8 +247,7 @@ class PermissionControllerServiceModel(private val service: PermissionController
packageName: String,
callback: Consumer<List<Pair<String, AppPermGroupUiInfo>>>
) {
- val packageGroupsLiveData = PackagePermissionsLiveData[packageName,
- Process.myUserHandle()]
+ val packageGroupsLiveData = PackagePermissionsLiveData[packageName, Process.myUserHandle()]
observeAndCheckForLifecycleState(packageGroupsLiveData) { groups ->
val groupNames = groups?.keys?.toMutableList() ?: mutableListOf()
groupNames.remove(PackagePermissionsLiveData.NON_RUNTIME_NORMAL_PERMS)
@@ -260,8 +262,8 @@ class PermissionControllerServiceModel(private val service: PermissionController
// live datas, because this method is used primarily for UI, and there is inherent
// delay when calling this method, due to binder calls, so some staleness is
// acceptable
- val uiInfoLiveData = AppPermGroupUiInfoLiveData[packageName, groupName,
- Process.myUserHandle()]
+ val uiInfoLiveData =
+ AppPermGroupUiInfoLiveData[packageName, groupName, Process.myUserHandle()]
observeAndCheckForLifecycleState(uiInfoLiveData, forceUpdate = true) { uiInfo ->
numLiveDatasUpdated++
@@ -285,9 +287,7 @@ class PermissionControllerServiceModel(private val service: PermissionController
*
* @param callback The callback our result will be returned to
*/
- fun onCountUnusedApps(
- callback: IntConsumer
- ) {
+ fun onCountUnusedApps(callback: IntConsumer) {
GlobalScope.launch(Main.immediate) {
val unusedAppsCount = getUnusedPackages().map { it?.size ?: 0 }
observeAndCheckForLifecycleState(unusedAppsCount) { count ->
@@ -297,21 +297,19 @@ class PermissionControllerServiceModel(private val service: PermissionController
}
/**
- * Gets whether the package is eligible for hibernation. The logic is the same logic used by
- * the app hibernation job when determining which apps to hibernate.
+ * Gets whether the package is eligible for hibernation. The logic is the same logic used by the
+ * app hibernation job when determining which apps to hibernate.
*
* @param packageName The package to check eligibility for
* @param callback The callback the result will be returned to
*/
- fun onGetHibernationEligibility(
- packageName: String,
- callback: IntConsumer
- ) {
+ fun onGetHibernationEligibility(packageName: String, callback: IntConsumer) {
val user = Process.myUserHandle()
val hibernationSettingLiveData = HibernationSettingStateLiveData[packageName, user]
observeAndCheckForLifecycleState(hibernationSettingLiveData) { hibernationSettingState ->
callback.accept(
- hibernationSettingState?.hibernationEligibility ?: HIBERNATION_ELIGIBILITY_UNKNOWN)
+ hibernationSettingState?.hibernationEligibility ?: HIBERNATION_ELIGIBILITY_UNKNOWN
+ )
}
}
@@ -325,9 +323,7 @@ class PermissionControllerServiceModel(private val service: PermissionController
return withTimeout(9000) {
val dumpedLogs = GlobalScope.async(IO) { DumpableLog.get() }
- PermissionControllerDumpProto.newBuilder()
- .addAllLogs(dumpedLogs.await())
- .build()
+ PermissionControllerDumpProto.newBuilder().addAllLogs(dumpedLogs.await()).build()
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventCleanupJobService.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventCleanupJobService.kt
index d22b63e9a..45501cd25 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventCleanupJobService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventCleanupJobService.kt
@@ -26,15 +26,13 @@ import android.provider.DeviceConfig
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.DumpableLog
import com.android.permissioncontroller.permission.utils.Utils
+import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
-import java.util.concurrent.TimeUnit
-/**
- * A job to clean up old permission events.
- */
+/** A job to clean up old permission events. */
class PermissionEventCleanupJobService : JobService() {
companion object {
@@ -43,13 +41,15 @@ class PermissionEventCleanupJobService : JobService() {
fun scheduleOldDataCleanupIfNecessary(context: Context, jobScheduler: JobScheduler) {
if (isNewJobScheduleRequired(jobScheduler)) {
- val jobInfo = JobInfo.Builder(
- Constants.OLD_PERMISSION_EVENT_CLEANUP_JOB_ID,
- ComponentName(context, PermissionEventCleanupJobService::class.java))
- .setPeriodic(getClearOldEventsCheckFrequencyMs())
- // persist this job across boots
- .setPersisted(true)
- .build()
+ val jobInfo =
+ JobInfo.Builder(
+ Constants.OLD_PERMISSION_EVENT_CLEANUP_JOB_ID,
+ ComponentName(context, PermissionEventCleanupJobService::class.java)
+ )
+ .setPeriodic(getClearOldEventsCheckFrequencyMs())
+ // persist this job across boots
+ .setPersisted(true)
+ .build()
val status = jobScheduler.schedule(jobInfo)
if (status != JobScheduler.RESULT_SUCCESS) {
DumpableLog.e(LOG_TAG, "Could not schedule job: $status")
@@ -64,8 +64,8 @@ class PermissionEventCleanupJobService : JobService() {
*/
private fun isNewJobScheduleRequired(jobScheduler: JobScheduler): Boolean {
var scheduleNewJob = false
- val existingJob: JobInfo? = jobScheduler
- .getPendingJob(Constants.OLD_PERMISSION_EVENT_CLEANUP_JOB_ID)
+ val existingJob: JobInfo? =
+ jobScheduler.getPendingJob(Constants.OLD_PERMISSION_EVENT_CLEANUP_JOB_ID)
when {
existingJob == null -> {
DumpableLog.i(LOG_TAG, "No existing job, scheduling a new one")
@@ -83,9 +83,11 @@ class PermissionEventCleanupJobService : JobService() {
}
private fun getClearOldEventsCheckFrequencyMs() =
- DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PERMISSIONS,
Utils.PROPERTY_PERMISSION_EVENTS_CHECK_OLD_FREQUENCY_MILLIS,
- DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY)
+ DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY
+ )
}
var job: Job? = null
@@ -98,15 +100,16 @@ class PermissionEventCleanupJobService : JobService() {
return false
}
jobStartTime = System.currentTimeMillis()
- job = GlobalScope.launch(Dispatchers.IO) {
- for (storage in storages) {
- val success = storage.removeOldData()
- if (!success) {
- DumpableLog.e(LOG_TAG, "Failed to remove old data for $storage")
+ job =
+ GlobalScope.launch(Dispatchers.IO) {
+ for (storage in storages) {
+ val success = storage.removeOldData()
+ if (!success) {
+ DumpableLog.e(LOG_TAG, "Failed to remove old data for $storage")
+ }
}
+ jobFinished(params, false)
}
- jobFinished(params, false)
- }
return true
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorage.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorage.kt
index 67a1cb4a4..fb73bcf75 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorage.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorage.kt
@@ -18,9 +18,7 @@ package com.android.permissioncontroller.permission.service
import com.android.permissioncontroller.permission.data.PermissionEvent
-/**
- * Persistent storage for retrieving persisted permission event data.
- */
+/** Persistent storage for retrieving persisted permission event data. */
interface PermissionEventStorage<T : PermissionEvent> {
/**
* Persist a permission event for retrieval later.
@@ -36,9 +34,7 @@ interface PermissionEventStorage<T : PermissionEvent> {
*/
suspend fun loadEvents(): List<T>
- /**
- * Clear all events.
- */
+ /** Clear all events. */
suspend fun clearEvents()
/**
@@ -60,9 +56,9 @@ interface PermissionEventStorage<T : PermissionEvent> {
* Update event timestamps based on the delta in system time.
*
* @param diffSystemTimeMillis the difference between the current and old system times. Positive
- * values mean that the time has changed in the future and negative means the time was changed
- * into the past.
+ * values mean that the time has changed in the future and negative means the time was changed
+ * into the past.
* @return whether the storage was successful
*/
suspend fun updateEventsBySystemTimeDelta(diffSystemTimeMillis: Long): Boolean
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorageImpls.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorageImpls.kt
index de6a0d9e2..33dc128f6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorageImpls.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorageImpls.kt
@@ -21,18 +21,13 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.data.PermissionEvent
import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl
-/**
- * Singleton of all supported [PermissionEventStorage] on the device.
- */
+/** Singleton of all supported [PermissionEventStorage] on the device. */
class PermissionEventStorageImpls {
companion object {
- @Volatile
- private var INSTANCE: List<PermissionEventStorage<out PermissionEvent>>? = null
+ @Volatile private var INSTANCE: List<PermissionEventStorage<out PermissionEvent>>? = null
fun getInstance(): List<PermissionEventStorage<out PermissionEvent>> =
- INSTANCE ?: synchronized(this) {
- INSTANCE ?: createInstance().also { INSTANCE = it }
- }
+ INSTANCE ?: synchronized(this) { INSTANCE ?: createInstance().also { INSTANCE = it } }
@SuppressLint("NewApi")
private fun createInstance(): List<PermissionEventStorage<out PermissionEvent>> {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionStorageTimeChangeReceiver.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionStorageTimeChangeReceiver.kt
index 43970dd13..ccb3acbad 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionStorageTimeChangeReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionStorageTimeChangeReceiver.kt
@@ -26,10 +26,10 @@ import com.android.permissioncontroller.DumpableLog
import com.android.permissioncontroller.permission.data.PermissionEvent
import com.android.permissioncontroller.permission.utils.SystemTimeSource
import com.android.permissioncontroller.permission.utils.TimeSource
+import kotlin.math.abs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
-import kotlin.math.abs
/**
* [BroadcastReceiver] to update the persisted timestamps when the date changes. Receives broadcasts
@@ -51,8 +51,7 @@ class PermissionStorageTimeChangeReceiver(
* Key for the last known system time from the system. First initialized after boot
* complete.
*/
- @VisibleForTesting
- const val PREF_KEY_SYSTEM_TIME_SNAPSHOT = "system_time_snapshot"
+ @VisibleForTesting const val PREF_KEY_SYSTEM_TIME_SNAPSHOT = "system_time_snapshot"
/**
* Key for the last known elapsed time since boot. First initialized after boot complete.
@@ -60,12 +59,9 @@ class PermissionStorageTimeChangeReceiver(
@VisibleForTesting
const val PREF_KEY_ELAPSED_REALTIME_SNAPSHOT = "elapsed_realtime_snapshot"
- @VisibleForTesting
- const val SNAPSHOT_UNINITIALIZED = -1L
+ @VisibleForTesting const val SNAPSHOT_UNINITIALIZED = -1L
- /**
- * The millisecond threshold for a time delta to be considered a time change.
- */
+ /** The millisecond threshold for a time delta to be considered a time change. */
private const val TIME_CHANGE_THRESHOLD_MILLIS = 60 * 1000L
}
@@ -75,8 +71,11 @@ class PermissionStorageTimeChangeReceiver(
}
when (val action = intent.action) {
Intent.ACTION_BOOT_COMPLETED -> {
- persistTimeSnapshots(context, timeSource.currentTimeMillis(),
- timeSource.elapsedRealtime())
+ persistTimeSnapshots(
+ context,
+ timeSource.currentTimeMillis(),
+ timeSource.elapsedRealtime()
+ )
}
Intent.ACTION_TIME_CHANGED -> {
checkForTimeChanged(context)
@@ -90,15 +89,16 @@ class PermissionStorageTimeChangeReceiver(
private fun checkForTimeChanged(context: Context) {
val systemTimeSnapshot = getSystemTimeSnapshot(context)
val realtimeSnapshot = getElapsedRealtimeSnapshot(context)
- if (realtimeSnapshot == SNAPSHOT_UNINITIALIZED ||
- systemTimeSnapshot == SNAPSHOT_UNINITIALIZED) {
+ if (
+ realtimeSnapshot == SNAPSHOT_UNINITIALIZED ||
+ systemTimeSnapshot == SNAPSHOT_UNINITIALIZED
+ ) {
DumpableLog.e(LOG_TAG, "Snapshots not initialized")
return
}
val actualSystemTime = timeSource.currentTimeMillis()
val actualRealtime = timeSource.elapsedRealtime()
- val expectedSystemTime = (actualRealtime - realtimeSnapshot) +
- systemTimeSnapshot
+ val expectedSystemTime = (actualRealtime - realtimeSnapshot) + systemTimeSnapshot
val diffSystemTime = actualSystemTime - expectedSystemTime
if (abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
DumpableLog.d(LOG_TAG, "Time changed by ${diffSystemTime / 1000} seconds")
@@ -131,17 +131,21 @@ class PermissionStorageTimeChangeReceiver(
}
private fun getSystemTimeSnapshot(context: Context): Long {
- return context.sharedPreferences.getLong(PREF_KEY_SYSTEM_TIME_SNAPSHOT,
- SNAPSHOT_UNINITIALIZED)
+ return context.sharedPreferences.getLong(
+ PREF_KEY_SYSTEM_TIME_SNAPSHOT,
+ SNAPSHOT_UNINITIALIZED
+ )
}
private fun getElapsedRealtimeSnapshot(context: Context): Long {
- return context.sharedPreferences.getLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT,
- SNAPSHOT_UNINITIALIZED)
+ return context.sharedPreferences.getLong(
+ PREF_KEY_ELAPSED_REALTIME_SNAPSHOT,
+ SNAPSHOT_UNINITIALIZED
+ )
}
val Context.sharedPreferences: SharedPreferences
get() {
return PreferenceManager.getDefaultSharedPreferences(this)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PersistedStoragePackageUninstalledReceiver.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PersistedStoragePackageUninstalledReceiver.kt
index 37fa2b36d..383e52dfc 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PersistedStoragePackageUninstalledReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PersistedStoragePackageUninstalledReceiver.kt
@@ -29,8 +29,8 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
/**
- * [BroadcastReceiver] to clear user decision information when a package has its data cleared or
- * is fully removed.
+ * [BroadcastReceiver] to clear user decision information when a package has its data cleared or is
+ * fully removed.
*/
class PersistedStoragePackageUninstalledReceiver(
@VisibleForTesting
@@ -48,8 +48,10 @@ class PersistedStoragePackageUninstalledReceiver(
return
}
val action = intent.action
- if (!(action == Intent.ACTION_PACKAGE_DATA_CLEARED ||
- action == Intent.ACTION_PACKAGE_FULLY_REMOVED)) {
+ if (
+ !(action == Intent.ACTION_PACKAGE_DATA_CLEARED ||
+ action == Intent.ACTION_PACKAGE_FULLY_REMOVED)
+ ) {
return
}
intent.data?.let {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt
index 3405ab014..941ae2b0d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt
@@ -28,6 +28,7 @@ import android.os.Process.myUserHandle
import android.permission.PermissionManager
import android.util.Log
import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.DeviceUtils
import com.android.permissioncontroller.PermissionControllerStatsLog
import com.android.permissioncontroller.PermissionControllerStatsLog.RUNTIME_PERMISSIONS_UPGRADE_RESULT
import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData
@@ -42,24 +43,28 @@ import com.android.permissioncontroller.permission.model.livedatatypes.LightPerm
import com.android.permissioncontroller.permission.utils.IPC
import com.android.permissioncontroller.permission.utils.KotlinUtils.grantBackgroundRuntimePermissions
import com.android.permissioncontroller.permission.utils.KotlinUtils.grantForegroundRuntimePermissions
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.PermissionMapping.getPlatformPermissionNamesOfGroup
import com.android.permissioncontroller.permission.utils.PermissionMapping.getRuntimePlatformPermissionNames
+import com.android.permissioncontroller.permission.utils.Utils.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT
import com.android.permissioncontroller.permission.utils.application
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
-/**
- * This class handles upgrading the runtime permissions database
- */
-internal object RuntimePermissionsUpgradeController {
+/** This class handles upgrading the runtime permissions database */
+object RuntimePermissionsUpgradeController {
private val LOG_TAG = RuntimePermissionsUpgradeController::class.java.simpleName
+ private const val DEBUG = false
// The latest version of the runtime permissions database
- private val LATEST_VERSION = if (SdkLevel.isAtLeastT()) {
- 10
- } else {
- 9
- }
+ private val LATEST_VERSION =
+ if (SdkLevel.isAtLeastU()) {
+ 11
+ } else if (SdkLevel.isAtLeastT()) {
+ 10
+ } else {
+ 9
+ }
fun upgradeIfNeeded(context: Context, onComplete: Runnable) {
val permissionManager = context.getSystemService(PermissionManager::class.java)
@@ -69,9 +74,13 @@ internal object RuntimePermissionsUpgradeController {
GlobalScope.launch(IPC) {
val upgradedVersion = onUpgradeLocked(context, currentVersion)
if (upgradedVersion != LATEST_VERSION) {
- Log.wtf("PermissionControllerService", "warning: upgrading permission database" +
- " to version $LATEST_VERSION left it at $currentVersion instead; this is " +
- "probably a bug. Did you update LATEST_VERSION?", Throwable())
+ Log.wtf(
+ "PermissionControllerService",
+ "warning: upgrading permission database" +
+ " to version $LATEST_VERSION left it at $currentVersion instead; this is " +
+ "probably a bug. Did you update LATEST_VERSION?",
+ Throwable()
+ )
throw RuntimeException("db upgrade error")
}
@@ -87,7 +96,6 @@ internal object RuntimePermissionsUpgradeController {
*
* @param permissionInfos permissions to exempt
* @param pkgs packages to exempt
- *
* @return the exemptions to apply
*/
private fun getExemptions(
@@ -107,9 +115,8 @@ internal object RuntimePermissionsUpgradeController {
}
/**
- * You must perform all necessary mutations to bring the runtime permissions
- * database from the old to the new version. When you add a new upgrade step
- * you *must* update LATEST_VERSION.
+ * You must perform all necessary mutations to bring the runtime permissions database from the
+ * old to the new version. When you add a new upgrade step you *must* update LATEST_VERSION.
*
* <p> NOTE: Relies upon the fact that the system will attempt to upgrade every version after
* currentVersion in order, without skipping any versions. Should this become the case, this
@@ -118,10 +125,7 @@ internal object RuntimePermissionsUpgradeController {
* @param context The current context
* @param currentVersion The current version of the permission database
*/
- private suspend fun onUpgradeLocked(
- context: Context,
- currentVersion: Int
- ): Int {
+ private suspend fun onUpgradeLocked(context: Context, currentVersion: Int): Int {
var sdkUpgradedFromP = false
var isNewUser = false
@@ -134,190 +138,256 @@ internal object RuntimePermissionsUpgradeController {
val needBackgroundAppPermGroups = sdkUpgradedFromP && currentVersion <= 6
val needAccessMediaAppPermGroups = !isNewUser && currentVersion <= 7
val needGrantedExternalStorage = currentVersion <= 9 && SdkLevel.isAtLeastT()
+ val needBodySensorsAppPermGroups =
+ DeviceUtils.isWear(context) && currentVersion <= 9 && SdkLevel.isAtLeastT()
+ val needGrantedReadMediaVisual = currentVersion <= 10 && SdkLevel.isAtLeastU()
val isDeviceUpgrading = context.packageManager.isDeviceUpgrading
// All data needed by this method.
//
// All data is loaded once and then not updated.
- val upgradeDataProvider = object : SmartUpdateMediatorLiveData<UpgradeData>() {
- /** Provides all preinstalled packages in the system */
- private val preinstalledPkgInfoProvider =
+ val upgradeDataProvider =
+ object : SmartUpdateMediatorLiveData<UpgradeData>() {
+ /** Provides all preinstalled packages in the system */
+ private val preinstalledPkgInfoProvider =
PreinstalledUserPackageInfosLiveData[myUserHandle()]
- /** Provides all platform runtime permission infos */
- private val platformRuntimePermissionInfoProviders =
+ /** Provides all platform runtime permission infos */
+ private val platformRuntimePermissionInfoProviders =
mutableListOf<LightPermInfoLiveData>()
- /** {@link #platformRuntimePermissionInfoProvider} that already provided a result */
- private val platformRuntimePermissionInfoProvidersDone =
+ /** {@link #platformRuntimePermissionInfoProvider} that already provided a result */
+ private val platformRuntimePermissionInfoProvidersDone =
mutableSetOf<LightPermInfoLiveData>()
- /** Provides all packages in the system */
- private val pkgInfoProvider = UserPackageInfosLiveData[myUserHandle()]
+ /** Provides all packages in the system */
+ private val pkgInfoProvider = UserPackageInfosLiveData[myUserHandle()]
- /** Provides all {@link LightAppPermGroup} this upgrade needs */
- private var permGroupProviders: MutableList<LightAppPermGroupLiveData>? = null
+ /** Provides all {@link LightAppPermGroup} this upgrade needs */
+ private var permGroupProviders: MutableSet<LightAppPermGroupLiveData>? = null
- /** {@link #permGroupProviders} that already provided a result */
- private val permGroupProvidersDone = mutableSetOf<LightAppPermGroupLiveData>()
+ /** {@link #permGroupProviders} that already provided a result */
+ private val permGroupProvidersDone = mutableSetOf<LightAppPermGroupLiveData>()
- init {
- // First step: Load packages + perm infos
- // TODO ntmyren: remove once b/154796729 is fixed
- Log.i("RuntimePermissions", "observing UserPackageInfoLiveData for " +
- "${myUserHandle().identifier} in RuntimePermissionsUpgradeController")
- addSource(pkgInfoProvider) { pkgInfos ->
- if (pkgInfos != null) {
- removeSource(pkgInfoProvider)
+ init {
+ // First step: Load packages + perm infos
+ addSource(pkgInfoProvider) { pkgInfos ->
+ if (pkgInfos != null) {
+ removeSource(pkgInfoProvider)
- // TODO ntmyren: remove once b/154796729 is fixed
- Log.i("RuntimePermissions", "observing " +
- "PreinstalledUserPackageInfoLiveData for ${myUserHandle().identifier}" +
- " in RuntimePermissionsUpgradeController")
- addSource(preinstalledPkgInfoProvider) { preinstalledPkgInfos ->
- if (preinstalledPkgInfos != null) {
- removeSource(preinstalledPkgInfoProvider)
+ addSource(preinstalledPkgInfoProvider) { preinstalledPkgInfos ->
+ if (preinstalledPkgInfos != null) {
+ removeSource(preinstalledPkgInfoProvider)
- update()
+ update()
+ }
}
}
}
- }
- for (platformRuntimePermission in getRuntimePlatformPermissionNames()) {
- val permProvider = LightPermInfoLiveData[platformRuntimePermission]
- platformRuntimePermissionInfoProviders.add(permProvider)
+ for (platformRuntimePermission in getRuntimePlatformPermissionNames()) {
+ val permProvider = LightPermInfoLiveData[platformRuntimePermission]
+ platformRuntimePermissionInfoProviders.add(permProvider)
- addSource(permProvider) { permInfo ->
- if (permInfo != null) {
- platformRuntimePermissionInfoProvidersDone.add(permProvider)
- removeSource(permProvider)
+ addSource(permProvider) { permInfo ->
+ if (permInfo != null) {
+ platformRuntimePermissionInfoProvidersDone.add(permProvider)
+ removeSource(permProvider)
- update()
+ update()
+ }
}
}
}
- }
-
- override fun onUpdate() {
- if (permGroupProviders == null && pkgInfoProvider.value != null) {
- // Second step: Trigger load of app-perm-groups
-
- permGroupProviders = mutableListOf()
- // Only load app-perm-groups needed for this upgrade
- if (needBackgroundAppPermGroups || needAccessMediaAppPermGroups ||
- needGrantedExternalStorage) {
- for ((pkgName, _, requestedPerms, requestedPermFlags) in
+ override fun onUpdate() {
+ if (permGroupProviders == null && pkgInfoProvider.value != null) {
+ // Second step: Trigger load of app-perm-groups
+
+ permGroupProviders = mutableSetOf()
+
+ // Only load app-perm-groups needed for this upgrade
+ if (
+ needBackgroundAppPermGroups ||
+ needAccessMediaAppPermGroups ||
+ needGrantedExternalStorage ||
+ needGrantedReadMediaVisual ||
+ needBodySensorsAppPermGroups
+ ) {
+ for ((pkgName, _, requestedPerms, requestedPermFlags) in
pkgInfoProvider.value!!) {
- var requestsAccessMediaLocation = false
- var hasGrantedExternalStorage = false
-
- for ((perm, flags) in requestedPerms.zip(requestedPermFlags)) {
- if (needBackgroundAppPermGroups &&
- perm == permission.ACCESS_BACKGROUND_LOCATION) {
- permGroupProviders!!.add(LightAppPermGroupLiveData[pkgName,
- permission_group.LOCATION, myUserHandle()])
- }
+ var requestsAccessMediaLocation = false
+ var hasGrantedExternalStorage = false
+ var hasGrantedReadMediaVisual = false
+
+ for ((perm, flags) in requestedPerms.zip(requestedPermFlags)) {
+ if (
+ needBackgroundAppPermGroups &&
+ perm == permission.ACCESS_BACKGROUND_LOCATION
+ ) {
+ permGroupProviders!!.add(
+ LightAppPermGroupLiveData[
+ pkgName, permission_group.LOCATION, myUserHandle()]
+ )
+ }
- if (needAccessMediaAppPermGroups || needGrantedExternalStorage) {
- if (needAccessMediaAppPermGroups &&
- perm == permission.ACCESS_MEDIA_LOCATION) {
- requestsAccessMediaLocation = true
+ if (
+ needAccessMediaAppPermGroups ||
+ needGrantedExternalStorage ||
+ needGrantedReadMediaVisual
+ ) {
+ if (
+ needAccessMediaAppPermGroups &&
+ perm == permission.ACCESS_MEDIA_LOCATION
+ ) {
+ requestsAccessMediaLocation = true
+ }
+
+ val isGranted =
+ flags and PackageInfo.REQUESTED_PERMISSION_GRANTED != 0
+ if (perm == permission.READ_EXTERNAL_STORAGE && isGranted) {
+ hasGrantedExternalStorage = true
+ }
+ if (
+ PermissionMapping.getGroupOfPlatformPermission(perm) ==
+ permission_group.READ_MEDIA_VISUAL && isGranted
+ ) {
+ hasGrantedReadMediaVisual = true
+ }
}
- if (perm == permission.READ_EXTERNAL_STORAGE &&
- flags and PackageInfo.REQUESTED_PERMISSION_GRANTED
- != 0) {
- hasGrantedExternalStorage = true
+ if (
+ needBodySensorsAppPermGroups &&
+ perm == permission.BODY_SENSORS_BACKGROUND
+ ) {
+ permGroupProviders!!.add(
+ LightAppPermGroupLiveData[
+ pkgName, permission_group.SENSORS, myUserHandle()]
+ )
}
}
- }
- val accessMediaLocationPermGroup =
- if (SdkLevel.isAtLeastT())
- permission_group.READ_MEDIA_VISUAL
- else
- permission_group.STORAGE
-
- if (hasGrantedExternalStorage) {
- if (needGrantedExternalStorage) {
- permGroupProviders!!.add(LightAppPermGroupLiveData[pkgName,
- permission_group.STORAGE, myUserHandle()])
- if (SdkLevel.isAtLeastT()) {
- permGroupProviders!!.add(LightAppPermGroupLiveData[pkgName,
- permission_group.READ_MEDIA_VISUAL, myUserHandle()])
- permGroupProviders!!.add(LightAppPermGroupLiveData[pkgName,
- permission_group.READ_MEDIA_AURAL, myUserHandle()])
+ val accessMediaLocationPermGroup =
+ if (SdkLevel.isAtLeastT()) permission_group.READ_MEDIA_VISUAL
+ else permission_group.STORAGE
+
+ if (hasGrantedExternalStorage) {
+ if (needGrantedExternalStorage) {
+ permGroupProviders!!.add(
+ LightAppPermGroupLiveData[
+ pkgName, permission_group.STORAGE, myUserHandle()]
+ )
+ if (SdkLevel.isAtLeastT()) {
+ permGroupProviders!!.add(
+ LightAppPermGroupLiveData[
+ pkgName,
+ permission_group.READ_MEDIA_VISUAL,
+ myUserHandle()]
+ )
+ permGroupProviders!!.add(
+ LightAppPermGroupLiveData[
+ pkgName,
+ permission_group.READ_MEDIA_AURAL,
+ myUserHandle()]
+ )
+ }
+ } else if (requestsAccessMediaLocation) {
+ permGroupProviders!!.add(
+ LightAppPermGroupLiveData[
+ pkgName,
+ accessMediaLocationPermGroup,
+ myUserHandle()]
+ )
}
- } else if (requestsAccessMediaLocation) {
- permGroupProviders!!.add(LightAppPermGroupLiveData[pkgName,
- accessMediaLocationPermGroup, myUserHandle()])
+ }
+ if (hasGrantedReadMediaVisual && needGrantedReadMediaVisual) {
+ permGroupProviders!!.add(
+ LightAppPermGroupLiveData[
+ pkgName,
+ permission_group.READ_MEDIA_VISUAL,
+ myUserHandle()]
+ )
}
}
}
- }
- // Wait until groups are loaded and then trigger third step
- for (permGroupProvider in permGroupProviders!!) {
- addSource(permGroupProvider) { group ->
- if (group != null) {
- permGroupProvidersDone.add(permGroupProvider)
- removeSource(permGroupProvider)
+ // Wait until groups are loaded and then trigger third step
+ for (permGroupProvider in permGroupProviders!!) {
+ addSource(permGroupProvider) { group ->
+ if (group != null) {
+ permGroupProvidersDone.add(permGroupProvider)
+ removeSource(permGroupProvider)
- update()
+ update()
+ }
}
}
- }
- // If no group need to be loaded, directly switch to third step
- if (permGroupProviders!!.isEmpty()) {
- update()
- }
- } else if (permGroupProviders != null &&
- permGroupProvidersDone.size == permGroupProviders!!.size &&
- preinstalledPkgInfoProvider.value != null &&
- platformRuntimePermissionInfoProviders.size
- == platformRuntimePermissionInfoProvidersDone.size) {
- // Third step: All packages, perm infos and perm groups are loaded, set value
-
- val bgGroups = mutableListOf<LightAppPermGroup>()
- val storageGroups = mutableListOf<LightAppPermGroup>()
-
- for (group in permGroupProviders!!.mapNotNull { it.value }) {
- when (group.permGroupName) {
- permission_group.LOCATION -> {
- bgGroups.add(group)
- }
- permission_group.STORAGE -> {
- storageGroups.add(group)
- }
- permission_group.READ_MEDIA_AURAL -> {
- storageGroups.add(group)
- }
- permission_group.READ_MEDIA_VISUAL -> {
- storageGroups.add(group)
+ // If no group need to be loaded, directly switch to third step
+ if (permGroupProviders!!.isEmpty()) {
+ update()
+ }
+ } else if (
+ permGroupProviders != null &&
+ permGroupProvidersDone.size == permGroupProviders!!.size &&
+ preinstalledPkgInfoProvider.value != null &&
+ platformRuntimePermissionInfoProviders.size ==
+ platformRuntimePermissionInfoProvidersDone.size
+ ) {
+ // Third step: All packages, perm infos and perm groups are loaded, set
+ // value
+
+ val bgGroups = mutableListOf<LightAppPermGroup>()
+ val storageGroups = mutableListOf<LightAppPermGroup>()
+ val bgSensorsGroups = mutableListOf<LightAppPermGroup>()
+
+ for (group in permGroupProviders!!.mapNotNull { it.value }) {
+ when (group.permGroupName) {
+ permission_group.LOCATION -> {
+ bgGroups.add(group)
+ }
+ permission_group.STORAGE -> {
+ storageGroups.add(group)
+ }
+ permission_group.READ_MEDIA_AURAL -> {
+ storageGroups.add(group)
+ }
+ permission_group.READ_MEDIA_VISUAL -> {
+ storageGroups.add(group)
+ }
+ permission_group.SENSORS -> {
+ bgSensorsGroups.add(group)
+ }
}
}
- }
- val restrictedPermissions = mutableSetOf<String>()
- for (permInfoLiveDt in platformRuntimePermissionInfoProviders) {
- val permInfo = permInfoLiveDt.value!!
+ val restrictedPermissions = mutableSetOf<String>()
+ for (permInfoLiveDt in platformRuntimePermissionInfoProviders) {
+ val permInfo = permInfoLiveDt.value!!
+
+ if (
+ permInfo.flags and
+ (PermissionInfo.FLAG_HARD_RESTRICTED or
+ PermissionInfo.FLAG_SOFT_RESTRICTED) == 0
+ ) {
+ continue
+ }
- if (permInfo.flags and (PermissionInfo.FLAG_HARD_RESTRICTED or
- PermissionInfo.FLAG_SOFT_RESTRICTED) == 0) {
- continue
+ restrictedPermissions.add(permInfo.name)
}
- restrictedPermissions.add(permInfo.name)
+ value =
+ UpgradeData(
+ preinstalledPkgInfoProvider.value!!,
+ restrictedPermissions,
+ pkgInfoProvider.value!!,
+ bgGroups,
+ storageGroups,
+ bgSensorsGroups
+ )
}
-
- value = UpgradeData(preinstalledPkgInfoProvider.value!!, restrictedPermissions,
- pkgInfoProvider.value!!, bgGroups, storageGroups)
}
}
- }
// Trigger loading of data and wait until data is loaded
val upgradeData = upgradeDataProvider.getInitializedValue(forceUpdate = true)
@@ -327,14 +397,19 @@ internal object RuntimePermissionsUpgradeController {
// always exempting them. For non-OTA updates the installer should do the exemption.
// If a restricted permission can't be exempted by the installer then it should be filtered
// out here.
- val preinstalledAppExemptions = getExemptions(
- upgradeData.restrictedPermissions,
- upgradeData.preinstalledPkgs)
+ val preinstalledAppExemptions =
+ getExemptions(upgradeData.restrictedPermissions, upgradeData.preinstalledPkgs)
- val (newVersion, upgradeExemptions, grants) = onUpgradeLockedDataLoaded(currentVersion,
- upgradeData.pkgs, upgradeData.restrictedPermissions,
- upgradeData.bgGroups, upgradeData.storageGroups,
- isDeviceUpgrading)
+ val (newVersion, upgradeExemptions, grants) =
+ onUpgradeLockedDataLoaded(
+ currentVersion,
+ upgradeData.pkgs,
+ upgradeData.restrictedPermissions,
+ upgradeData.bgGroups,
+ upgradeData.storageGroups,
+ upgradeData.bgSensorsGroups,
+ isDeviceUpgrading
+ )
// Do not run in parallel. Measurements have shown that this is slower than sequential
for (exemption in (preinstalledAppExemptions union upgradeExemptions)) {
@@ -354,6 +429,7 @@ internal object RuntimePermissionsUpgradeController {
restrictedPermissions: Set<String>,
bgApps: List<LightAppPermGroup>,
storageAndMediaAppPermGroups: List<LightAppPermGroup>,
+ bgSensorsGroups: List<LightAppPermGroup>,
isDeviceUpgrading: Boolean
): Triple<Int, List<RestrictionExemption>, List<Grant>> {
val exemptions = mutableListOf<RestrictionExemption>()
@@ -380,9 +456,10 @@ internal object RuntimePermissionsUpgradeController {
if (currentVersion == 0) {
Log.i(LOG_TAG, "Grandfathering SMS and CallLog permissions")
- val permissions = restrictedPermissions intersect
+ val permissions =
+ restrictedPermissions intersect
(getPlatformPermissionNamesOfGroup(permission_group.SMS) +
- getPlatformPermissionNamesOfGroup(permission_group.CALL_LOG))
+ getPlatformPermissionNamesOfGroup(permission_group.CALL_LOG))
exemptions.addAll(getExemptions(permissions, pkgs))
@@ -402,8 +479,7 @@ internal object RuntimePermissionsUpgradeController {
if (currentVersion == 3) {
Log.i(LOG_TAG, "Grandfathering location background permissions")
- val bgLocExemptions = getExemptions(setOf(permission.ACCESS_BACKGROUND_LOCATION),
- pkgs)
+ val bgLocExemptions = getExemptions(setOf(permission.ACCESS_BACKGROUND_LOCATION), pkgs)
// Adjust bgApps as if the exemption was applied
for ((pkgName, _) in bgLocExemptions) {
@@ -412,13 +488,22 @@ internal object RuntimePermissionsUpgradeController {
val allPermissionsWithxemption = bgApp.allPermissions.toMutableMap()
allPermissionsWithxemption[permission.ACCESS_BACKGROUND_LOCATION] =
- LightPermission(perm.pkgInfo, perm.permInfo, perm.isGrantedIncludingAppOp,
+ LightPermission(
+ perm.pkgInfo,
+ perm.permInfo,
+ perm.isGrantedIncludingAppOp,
perm.flags or FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT,
- perm.foregroundPerms)
-
- bgAppsWithExemption[pkgName] = LightAppPermGroup(bgApp.packageInfo,
- bgApp.permGroupInfo, allPermissionsWithxemption,
- bgApp.hasInstallToRuntimeSplit, bgApp.specialLocationGrant)
+ perm.foregroundPerms
+ )
+
+ bgAppsWithExemption[pkgName] =
+ LightAppPermGroup(
+ bgApp.packageInfo,
+ bgApp.permGroupInfo,
+ allPermissionsWithxemption,
+ bgApp.hasInstallToRuntimeSplit,
+ bgApp.specialLocationGrant
+ )
}
exemptions.addAll(bgLocExemptions)
@@ -434,7 +519,8 @@ internal object RuntimePermissionsUpgradeController {
if (currentVersion == 5) {
Log.i(LOG_TAG, "Grandfathering Storage permissions")
- val permissions = restrictedPermissions intersect
+ val permissions =
+ restrictedPermissions intersect
getPlatformPermissionNamesOfGroup(permission_group.STORAGE)
// We don't want to allow modification of storage post install, so put it
@@ -448,18 +534,23 @@ internal object RuntimePermissionsUpgradeController {
if (sdkUpgradedFromP) {
Log.i(LOG_TAG, "Expanding location permissions")
for (appPermGroup in bgAppsWithExemption.values) {
- if (appPermGroup.foreground.isGranted &&
- appPermGroup.hasBackgroundGroup &&
- !appPermGroup.background.isUserSet &&
- !appPermGroup.background.isSystemFixed &&
- !appPermGroup.background.isPolicyFixed &&
- !appPermGroup.background.isUserFixed) {
+ if (
+ appPermGroup.foreground.isGranted &&
+ appPermGroup.hasBackgroundGroup &&
+ !appPermGroup.background.isUserSet &&
+ !appPermGroup.background.isSystemFixed &&
+ !appPermGroup.background.isPolicyFixed &&
+ !appPermGroup.background.isUserFixed
+ ) {
grants.add(Grant(true, appPermGroup))
}
}
} else {
- Log.i(LOG_TAG, "Not expanding location permissions as this is not an upgrade " +
- "from Android P")
+ Log.i(
+ LOG_TAG,
+ "Not expanding location permissions as this is not an upgrade " +
+ "from Android P"
+ )
}
currentVersion = 7
@@ -470,18 +561,25 @@ internal object RuntimePermissionsUpgradeController {
Log.i(LOG_TAG, "Expanding read storage to access media location")
for (appPermGroup in storageAndMediaAppPermGroups) {
- val perm = appPermGroup.permissions[permission.ACCESS_MEDIA_LOCATION]
- ?: continue
-
- if (!perm.isUserSet && !perm.isSystemFixed && !perm.isPolicyFixed &&
- !perm.isGrantedIncludingAppOp) {
- grants.add(Grant(false, appPermGroup,
- listOf(permission.ACCESS_MEDIA_LOCATION)))
+ val perm =
+ appPermGroup.permissions[permission.ACCESS_MEDIA_LOCATION] ?: continue
+
+ if (
+ !perm.isUserSet &&
+ !perm.isSystemFixed &&
+ !perm.isPolicyFixed &&
+ !perm.isGrantedIncludingAppOp
+ ) {
+ grants.add(
+ Grant(false, appPermGroup, listOf(permission.ACCESS_MEDIA_LOCATION))
+ )
}
}
} else {
- Log.i(LOG_TAG, "Not expanding read storage to access media location as this is " +
- "a new user")
+ Log.i(
+ LOG_TAG,
+ "Not expanding read storage to access media location as this is " + "a new user"
+ )
}
currentVersion = 8
@@ -495,35 +593,46 @@ internal object RuntimePermissionsUpgradeController {
if (currentVersion == 9 && SdkLevel.isAtLeastT()) {
if (isNewUser) {
- Log.i(LOG_TAG, "Not migrating STORAGE permissions to READ_MEDIA permissions as" +
- " this is a new user")
+ Log.i(
+ LOG_TAG,
+ "Not migrating STORAGE and BODY_SENSORS permissions as this is a new user"
+ )
} else if (!isDeviceUpgrading) {
- Log.i(LOG_TAG, "Not migrating STORAGE permissions to READ_MEDIA permissions as" +
- " this device is not performing an upgrade")
+ Log.i(
+ LOG_TAG,
+ "Not migrating STORAGE and BODY_SENSORS permissions as" +
+ " this device is not performing an upgrade"
+ )
} else {
Log.i(LOG_TAG, "Migrating STORAGE permissions to READ_MEDIA permissions")
// Upon upgrading to platform 33, for all targetSdk>=33 apps, do the following:
// If STORAGE is granted, and the user has not set READ_MEDIA_AURAL or
// READ_MEDIA_VISUAL, grant READ_MEDIA_AURAL and READ_MEDIA_VISUAL
- val storageAppPermGroups = storageAndMediaAppPermGroups.filter {
- it.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU &&
- it.permGroupInfo.name == permission_group.STORAGE &&
- it.isGranted && it.isUserSet
- }
+ val storageAppPermGroups =
+ storageAndMediaAppPermGroups.filter {
+ it.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU &&
+ it.permGroupInfo.name == permission_group.STORAGE &&
+ it.isGranted &&
+ it.isUserSet
+ }
for (storageAppPermGroup in storageAppPermGroups) {
val pkgName = storageAppPermGroup.packageInfo.packageName
- val auralAppPermGroup = storageAndMediaAppPermGroups.firstOrNull {
- it.packageInfo.packageName == pkgName &&
- it.permGroupInfo.name == permission_group.READ_MEDIA_AURAL &&
- !it.isUserSet && !it.isUserFixed
- }
- val visualAppPermGroup = storageAndMediaAppPermGroups.firstOrNull {
- it.packageInfo.packageName == pkgName &&
- it.permGroupInfo.name == permission_group.READ_MEDIA_VISUAL &&
- !it.permissions.filter { it.key != permission.ACCESS_MEDIA_LOCATION }
- .any { it.value.isUserSet || it.value.isUserFixed }
- }
+ val auralAppPermGroup =
+ storageAndMediaAppPermGroups.firstOrNull {
+ it.packageInfo.packageName == pkgName &&
+ it.permGroupInfo.name == permission_group.READ_MEDIA_AURAL &&
+ !it.isUserSet &&
+ !it.isUserFixed
+ }
+ val visualAppPermGroup =
+ storageAndMediaAppPermGroups.firstOrNull {
+ it.packageInfo.packageName == pkgName &&
+ it.permGroupInfo.name == permission_group.READ_MEDIA_VISUAL &&
+ !it.permissions
+ .filter { it.key != permission.ACCESS_MEDIA_LOCATION }
+ .any { it.value.isUserSet || it.value.isUserFixed }
+ }
if (auralAppPermGroup != null) {
grants.add(Grant(false, auralAppPermGroup))
@@ -532,18 +641,86 @@ internal object RuntimePermissionsUpgradeController {
grants.add(Grant(false, visualAppPermGroup))
}
}
+
+ // Granting body sensors background permission to apps that had the pre-split body
+ // sensors permission granted.
+ Log.i(LOG_TAG, "Grandfathering body sensors background permissions")
+
+ for (bgSensorsGroup in bgSensorsGroups) {
+ val perm =
+ bgSensorsGroup.allPermissions[permission.BODY_SENSORS_BACKGROUND]
+ ?: continue
+ if (perm.flags and FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT != 0) {
+ continue
+ }
+
+ // Exempt the background permission to allow setting from users.
+ val pkgName = bgSensorsGroup.packageName
+ exemptions.add(
+ RestrictionExemption(
+ pkgName,
+ permission.BODY_SENSORS_BACKGROUND,
+ FLAG_PERMISSION_WHITELIST_UPGRADE
+ )
+ )
+
+ val allPermissionsWithExemption = bgSensorsGroup.allPermissions.toMutableMap()
+ allPermissionsWithExemption[permission.BODY_SENSORS_BACKGROUND] =
+ LightPermission(
+ perm.pkgInfo,
+ perm.permInfo,
+ perm.isGrantedIncludingAppOp,
+ perm.flags or FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT,
+ perm.foregroundPerms
+ )
+ val group =
+ LightAppPermGroup(
+ bgSensorsGroup.packageInfo,
+ bgSensorsGroup.permGroupInfo,
+ allPermissionsWithExemption,
+ bgSensorsGroup.hasInstallToRuntimeSplit,
+ bgSensorsGroup.specialLocationGrant
+ )
+
+ // Grant the background permission only if foreground permission is granted.
+ if (group.foreground.isGranted) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "$pkgName Granted body sensors background permissions")
+ }
+ grants.add(Grant(isBackground = true, group = group))
+ }
+ }
}
currentVersion = 10
}
+ if (currentVersion == 10 && SdkLevel.isAtLeastU()) {
+ // On U, if the app is granted READ_MEDIA_VISUAL, expand the grant to
+ // READ_MEDIA_VISUAL_USER_SELECTED
+ if (isDeviceUpgrading && !isNewUser) {
+ Log.i(
+ LOG_TAG,
+ "Grandfathering READ_MEDIA_VISUAL_USER_SELECTED to apps already " +
+ "granted visual permissions"
+ )
+ val visualAppPermGroups =
+ storageAndMediaAppPermGroups.filter {
+ it.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU &&
+ it.permGroupInfo.name == permission_group.READ_MEDIA_VISUAL &&
+ it.isGranted &&
+ it.isUserSet
+ }
+ visualAppPermGroups.forEach { grants.add(Grant(false, it)) }
+ }
+ currentVersion = 11
+ }
+
// XXX: Add new upgrade steps above this point.
return Triple(currentVersion, exemptions, grants)
}
- /**
- * All data needed by {@link #onUpgradeLocked}
- */
+ /** All data needed by {@link #onUpgradeLocked} */
private data class UpgradeData(
/** Preinstalled packages */
val preinstalledPkgs: List<LightPackageInfo>,
@@ -556,15 +733,15 @@ internal object RuntimePermissionsUpgradeController {
* {@link #onUpgradeLockedDataLoaded}
*/
val bgGroups: List<LightAppPermGroup>,
+ /** Storage groups that need to be inspected by {@link #onUpgradeLockedDataLoaded} */
+ val storageGroups: List<LightAppPermGroup>,
/**
- * Storage groups that need to be inspected by {@link #onUpgradeLockedDataLoaded}
+ * Background Sensors groups that need to be inspected by {@link #onUpgradeLockedDataLoaded}
*/
- val storageGroups: List<LightAppPermGroup>,
+ val bgSensorsGroups: List<LightAppPermGroup>,
)
- /**
- * A restricted permission of an app that should be exempted
- */
+ /** A restricted permission of an app that should be exempted */
private data class RestrictionExemption(
/** Name of package to exempt */
val pkgName: String,
@@ -583,15 +760,13 @@ internal object RuntimePermissionsUpgradeController {
}
}
- /**
- * A permission group of an app that should get granted
- */
+ /** A permission group of an app that should get granted */
private data class Grant(
/** Should the grant be for the foreground or background permissions */
private val isBackground: Boolean,
/** Group to be granted */
private val group: LightAppPermGroup,
- /** Which of th permissions in the group should be granted */
+ /** Which of the permissions in the group should be granted */
private val permissions: List<String> = group.permissions.keys.toList()
) {
/**
@@ -601,17 +776,21 @@ internal object RuntimePermissionsUpgradeController {
*/
fun applyToPlatform(context: Context) {
if (isBackground) {
- val newGroup = grantBackgroundRuntimePermissions(context.application, group,
- permissions)
+ val newGroup =
+ grantBackgroundRuntimePermissions(context.application, group, permissions)
- logRuntimePermissionUpgradeResult(newGroup,
- permissions intersect newGroup.backgroundPermNames)
+ logRuntimePermissionUpgradeResult(
+ newGroup,
+ permissions intersect newGroup.backgroundPermNames
+ )
} else {
- val newGroup = grantForegroundRuntimePermissions(context.application, group,
- permissions)
+ val newGroup =
+ grantForegroundRuntimePermissions(context.application, group, permissions)
- logRuntimePermissionUpgradeResult(newGroup,
- permissions intersect newGroup.foregroundPermNames)
+ logRuntimePermissionUpgradeResult(
+ newGroup,
+ permissions intersect newGroup.foregroundPermNames
+ )
}
}
@@ -629,10 +808,21 @@ internal object RuntimePermissionsUpgradeController {
val packageName = permissionGroup.packageName
for (permName in filterPermissions) {
val permission = permissionGroup.permissions[permName] ?: continue
- PermissionControllerStatsLog.write(RUNTIME_PERMISSIONS_UPGRADE_RESULT,
- permission.name, uid, packageName)
- Log.v(LOG_TAG, "Runtime permission upgrade logged for permissionName=" +
- permission.name + " uid=" + uid + " packageName=" + packageName)
+ PermissionControllerStatsLog.write(
+ RUNTIME_PERMISSIONS_UPGRADE_RESULT,
+ permission.name,
+ uid,
+ packageName
+ )
+ Log.i(
+ LOG_TAG,
+ "Runtime permission upgrade logged for permissionName=" +
+ permission.name +
+ " uid=" +
+ uid +
+ " packageName=" +
+ packageName
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt
index 115200b2f..eb3f2e9af 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt
@@ -40,12 +40,14 @@ class SplitPermissionIndex() {
val oldPermGroup = PermissionMapping.getGroupOfPlatformPermission(oldPerm)
val newPermGroup = PermissionMapping.getGroupOfPlatformPermission(newPerm)
if (newPermGroup != null) {
- permToGroupSplits.add(SplitPermissionIndexEntry(
- oldPerm, splitPerm.targetSdk, newPermGroup))
+ permToGroupSplits.add(
+ SplitPermissionIndexEntry(oldPerm, splitPerm.targetSdk, newPermGroup)
+ )
}
if (oldPermGroup != null && newPermGroup != null) {
- groupToGroupSplits.add(SplitPermissionIndexEntry(
- oldPermGroup, splitPerm.targetSdk, newPermGroup))
+ groupToGroupSplits.add(
+ SplitPermissionIndexEntry(oldPermGroup, splitPerm.targetSdk, newPermGroup)
+ )
}
}
}
@@ -53,9 +55,7 @@ class SplitPermissionIndex() {
this.groupToGroupSplits = groupToGroupSplits
}
- /**
- * Given a permission, return which groups split *from* it for the given targetSdk.
- */
+ /** Given a permission, return which groups split *from* it for the given targetSdk. */
fun getPermToGroupSplitsFrom(oldPermission: String, targetSdk: Int): List<String> {
return permToGroupSplits
.filter { it.oldPerm == oldPermission && it.targetSdk < targetSdk }
@@ -63,9 +63,7 @@ class SplitPermissionIndex() {
.toList()
}
- /**
- * Given a permission group, return which groups split *from* it for the given targetSdk.
- */
+ /** Given a permission group, return which groups split *from* it for the given targetSdk. */
fun getGroupToGroupSplitsFrom(oldPermissionGroup: String, targetSdk: Int): List<String> {
return groupToGroupSplits
.filter { it.oldPerm == oldPermissionGroup && it.targetSdk < targetSdk }
@@ -73,9 +71,7 @@ class SplitPermissionIndex() {
.toList()
}
- /**
- * Given a permission group, return which permissions split *to* it for the given targetSdk.
- */
+ /** Given a permission group, return which permissions split *to* it for the given targetSdk. */
fun getGroupToGroupSplitsTo(newPermissionGroup: String, targetSdk: Int): List<String> {
return groupToGroupSplits
.filter { it.newPerm == newPermissionGroup && it.targetSdk < targetSdk }
@@ -88,4 +84,4 @@ class SplitPermissionIndex() {
val targetSdk: Int,
val newPerm: String
)
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING
index b8dd3d77a..5dea9615a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING
@@ -4,21 +4,24 @@
"name": "CtsPermissionTestCases",
"options": [
{
- "include-filter": "android.permission.cts.PermissionControllerTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
},
{
- "include-filter": "android.permission.cts.OneTimePermissionTest"
+ "include-filter": "android.permission.cts.PermissionControllerTest"
},
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "include-filter": "android.permission.cts.OneTimePermissionTest"
}
]
},
{
- "name": "CtsPermission3TestCases",
+ "name": "CtsPermissionUiTestCases",
"options": [
{
- "include-filter": "android.permission3.cts.SafetyLabelChangesJobServiceTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "include-filter": "android.permissionui.cts.SafetyLabelChangesJobServiceTest"
}
]
},
@@ -26,6 +29,9 @@
"name": "CtsPermissionTestCases",
"options": [
{
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
"include-filter": "android.permission.cts.LocationAccessCheckTest"
}
],
@@ -59,7 +65,7 @@
"include-annotation": "com.android.cts.devicepolicy.annotations.PermissionsTest"
},
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
@@ -69,10 +75,43 @@
"name": "CtsPermissionTestCases",
"options": [
{
- "include-filter": "android.permission.cts.LocationAccessCheckTest"
+ "include-filter": "android.permission.cts.PermissionControllerTest"
},
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "include-filter": "android.permission.cts.OneTimePermissionTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsPermissionUiTestCases",
+ "options": [
+ {
+ "include-filter": "android.permissionui.cts.SafetyLabelChangesJobServiceTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.LocationAccessCheckTest"
+ }
+ ],
+ "file_patterns": ["LocationAccessCheck\\.java"]
+ },
+ {
+ "name": "CtsBackupTestCases",
+ "options": [
+ {
+ "include-filter": "android.backup.cts.PermissionTest"
+ }
+ ]
+ },
+ {
+ "name": "PermissionControllerOutOfProcessTests",
+ "options": [
+ {
+ "include-filter": "com.android.permissioncontroller.tests.outofprocess.DumpTest"
}
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionDecisionStorageImpl.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionDecisionStorageImpl.kt
index 578b74783..18c40e0e4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionDecisionStorageImpl.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionDecisionStorageImpl.kt
@@ -29,11 +29,6 @@ import com.android.permissioncontroller.permission.data.v33.PermissionDecision
import com.android.permissioncontroller.permission.service.BasePermissionEventStorage
import com.android.permissioncontroller.permission.service.PermissionEventStorage
import com.android.permissioncontroller.permission.utils.Utils
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
-import org.xmlpull.v1.XmlPullParser
-import org.xmlpull.v1.XmlPullParserException
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
@@ -43,10 +38,13 @@ import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParserException
-/**
- * Implementation of [BasePermissionEventStorage] for storing [PermissionDecision] events.
- */
+/** Implementation of [BasePermissionEventStorage] for storing [PermissionDecision] events. */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class PermissionDecisionStorageImpl(
context: Context,
@@ -56,9 +54,7 @@ class PermissionDecisionStorageImpl(
// We don't use namespaces
private val ns: String? = null
- /**
- * The format for how dates are stored.
- */
+ /** The format for how dates are stored. */
private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US)
companion object {
@@ -66,9 +62,7 @@ class PermissionDecisionStorageImpl(
private const val DB_VERSION = 1
- /**
- * Config store file name for general shared store file.
- */
+ /** Config store file name for general shared store file. */
private const val STORE_FILE_NAME = "recent_permission_decisions.xml"
private const val TAG_RECENT_PERMISSION_DECISIONS = "recent-permission-decisions"
@@ -81,13 +75,10 @@ class PermissionDecisionStorageImpl(
private val DEFAULT_MAX_DATA_AGE_MS = TimeUnit.DAYS.toMillis(7)
- @Volatile
- private var INSTANCE: PermissionEventStorage<PermissionDecision>? = null
+ @Volatile private var INSTANCE: PermissionEventStorage<PermissionDecision>? = null
fun getInstance(): PermissionEventStorage<PermissionDecision> =
- INSTANCE ?: synchronized(this) {
- INSTANCE ?: createInstance().also { INSTANCE = it }
- }
+ INSTANCE ?: synchronized(this) { INSTANCE ?: createInstance().also { INSTANCE = it } }
private fun createInstance(): PermissionEventStorage<PermissionDecision> {
return PermissionDecisionStorageImpl(PermissionControllerApplication.get())
@@ -101,9 +92,15 @@ class PermissionDecisionStorageImpl(
) {
if (isRecordPermissionsSupported(context)) {
GlobalScope.launch(Dispatchers.IO) {
- getInstance().storeEvent(
- PermissionDecision(packageName, System.currentTimeMillis(), permGroupName,
- isGranted))
+ getInstance()
+ .storeEvent(
+ PermissionDecision(
+ packageName,
+ System.currentTimeMillis(),
+ permGroupName,
+ isGranted
+ )
+ )
}
}
}
@@ -148,9 +145,7 @@ class PermissionDecisionStorageImpl(
parser.require(XmlPullParser.START_TAG, ns, TAG_RECENT_PERMISSION_DECISIONS)
while (parser.next() != XmlPullParser.END_TAG) {
- readPermissionDecision(parser)?.let {
- entries.add(it)
- }
+ readPermissionDecision(parser)?.let { entries.add(it) }
}
return entries
}
@@ -163,9 +158,11 @@ class PermissionDecisionStorageImpl(
val packageName = parser.getAttributeValueNullSafe(ns, ATTR_PACKAGE_NAME)
val permissionGroup = parser.getAttributeValueNullSafe(ns, ATTR_PERMISSION_GROUP)
val decisionDate = parser.getAttributeValueNullSafe(ns, ATTR_DECISION_TIME)
- val decisionTime = dateFormat.parse(decisionDate)?.time
- ?: throw IllegalArgumentException(
- "Could not parse date $decisionDate on package $packageName")
+ val decisionTime =
+ dateFormat.parse(decisionDate)?.time
+ ?: throw IllegalArgumentException(
+ "Could not parse date $decisionDate on package $packageName"
+ )
val isGranted = parser.getAttributeValueNullSafe(ns, ATTR_IS_GRANTED).toBoolean()
decision = PermissionDecision(packageName, decisionTime, permissionGroup, isGranted)
} catch (e: XmlPullParserException) {
@@ -185,7 +182,8 @@ class PermissionDecisionStorageImpl(
private fun XmlPullParser.getAttributeValueNullSafe(namespace: String?, name: String): String {
return this.getAttributeValue(namespace, name)
?: throw XmlPullParserException(
- "Could not find attribute: namespace $namespace, name $name")
+ "Could not find attribute: namespace $namespace, name $name"
+ )
}
override fun getDatabaseFileName(): String {
@@ -193,9 +191,11 @@ class PermissionDecisionStorageImpl(
}
override fun getMaxDataAgeMs(): Long {
- return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
+ return DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PERMISSIONS,
Utils.PROPERTY_PERMISSION_DECISIONS_MAX_DATA_AGE_MILLIS,
- DEFAULT_MAX_DATA_AGE_MS)
+ DEFAULT_MAX_DATA_AGE_MS
+ )
}
override fun hasTheSamePrimaryKey(
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt
index 9231dc17b..4036e260a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt
@@ -56,10 +56,11 @@ import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SH
import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION__ACTION__DISMISSED
import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_SHOWN
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.data.v34.LightInstallSourceInfoLiveData
import com.android.permissioncontroller.permission.data.LightPackageInfoLiveData
import com.android.permissioncontroller.permission.data.SinglePermGroupPackagesUiInfoLiveData
+import com.android.permissioncontroller.permission.data.get
import com.android.permissioncontroller.permission.data.v34.AppDataSharingUpdatesLiveData
+import com.android.permissioncontroller.permission.data.v34.LightInstallSourceInfoLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState.PERMS_ALLOWED_ALWAYS
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY
@@ -419,9 +420,7 @@ class SafetyLabelChangesJobService : JobService() {
// preinstalled apps.
private suspend fun getAllStoreInstalledPackagesRequestingLocation():
Set<Pair<String, UserHandle>> =
- getAllPackagesRequestingLocation()
- .filter { isSafetyLabelSupported(it) }
- .toSet()
+ getAllPackagesRequestingLocation().filter { isSafetyLabelSupported(it) }.toSet()
private suspend fun getAllPackagesRequestingLocation(): Set<Pair<String, UserHandle>> =
SinglePermGroupPackagesUiInfoLiveData[Manifest.permission_group.LOCATION]
@@ -439,7 +438,7 @@ class SafetyLabelChangesJobService : JobService() {
private suspend fun isSafetyLabelSupported(packageUser: Pair<String, UserHandle>): Boolean {
val lightInstallSourceInfo =
- LightInstallSourceInfoLiveData[packageUser].getInitializedValue()
+ LightInstallSourceInfoLiveData[packageUser].getInitializedValue()
return lightInstallSourceInfo.supportsSafetyLabel
}
@@ -531,8 +530,9 @@ class SafetyLabelChangesJobService : JobService() {
createNotificationChannel(context, notificationManager)
val (appLabel, smallIcon, color) = KotlinUtils.getSafetyCenterNotificationResources(this)
- val smallIconCompat = IconCompat.createFromIcon(smallIcon)
- ?: IconCompat.createWithResource(this, R.drawable.ic_info)
+ val smallIconCompat =
+ IconCompat.createFromIcon(smallIcon)
+ ?: IconCompat.createWithResource(this, R.drawable.ic_info)
val title = context.getString(R.string.safety_label_changes_notification_title)
val text = context.getString(R.string.safety_label_changes_notification_desc)
var notificationBuilder =
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/Category.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/Category.kt
index 61336cdce..5daf26883 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/Category.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/Category.kt
@@ -24,5 +24,6 @@ enum class Category(val categoryName: String) {
ALLOWED("allowed"),
ALLOWED_FOREGROUND("allowed_foreground"),
ASK("ask"),
- DENIED("denied")
+ DENIED("denied"),
+ STORAGE_FOOTER("storage_footer_category"),
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
index ff63cdae5..ddcdf1319 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
@@ -20,7 +20,7 @@ import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission_group.LOCATION;
import static android.Manifest.permission_group.READ_MEDIA_VISUAL;
-import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.CANCELED;
@@ -53,9 +53,10 @@ import android.text.Annotation;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ClickableSpan;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-import android.view.MotionEvent;
+import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.Window;
@@ -66,26 +67,32 @@ import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
-import androidx.core.util.Consumer;
import androidx.core.util.Preconditions;
import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.ui.auto.GrantPermissionsAutoViewHandler;
+import com.android.permissioncontroller.permission.ui.model.DenyButton;
import com.android.permissioncontroller.permission.ui.model.GrantPermissionsViewModel;
import com.android.permissioncontroller.permission.ui.model.GrantPermissionsViewModel.RequestInfo;
-import com.android.permissioncontroller.permission.ui.model.GrantPermissionsViewModelFactory;
+import com.android.permissioncontroller.permission.ui.model.NewGrantPermissionsViewModelFactory;
+import com.android.permissioncontroller.permission.ui.model.Prompt;
import com.android.permissioncontroller.permission.ui.wear.GrantPermissionsWearViewHandler;
+import com.android.permissioncontroller.permission.utils.ContextCompat;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
+import com.android.permissioncontroller.permission.utils.MultiDeviceUtils;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.Utils;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
+import java.util.Set;
/**
* An activity which displays runtime permission prompts on behalf of an app.
@@ -125,9 +132,10 @@ public class GrantPermissionsActivity extends SettingsActivity
public static final int DIALOG_WITH_FINE_LOCATION_ONLY = 4;
public static final int DIALOG_WITH_COARSE_LOCATION_ONLY = 5;
- public static final Map<String, Integer> PERMISSION_TO_BIT_SHIFT = Map.of(
- ACCESS_COARSE_LOCATION, 0,
- ACCESS_FINE_LOCATION, 1);
+ public static final Map<String, Integer> PERMISSION_TO_BIT_SHIFT =
+ Map.of(
+ ACCESS_COARSE_LOCATION, 0,
+ ACCESS_FINE_LOCATION, 1);
public static final String INTENT_PHOTOS_SELECTED = "intent_extra_result";
@@ -135,8 +143,8 @@ public class GrantPermissionsActivity extends SettingsActivity
* A map of the currently shown GrantPermissionsActivity for this user, per package and task ID
*/
@GuardedBy("sCurrentGrantRequests")
- public static final Map<Pair<String, Integer>, GrantPermissionsActivity>
- sCurrentGrantRequests = new HashMap<>();
+ public static final Map<Pair<String, Integer>, GrantPermissionsActivity> sCurrentGrantRequests =
+ new HashMap<>();
/** Unique Id of a request */
private long mSessionId;
@@ -149,6 +157,11 @@ public class GrantPermissionsActivity extends SettingsActivity
/** The current list of permissions requested, across all current requests for this app */
private List<String> mRequestedPermissions = new ArrayList<>();
+
+ /** A list of permissions requested on an app's behalf by the system. Usually Implicitly
+ * requested, although this isn't necessarily always the case.
+ */
+ private List<String> mSystemRequestedPermissions = new ArrayList<>();
/** A copy of the list of permissions originally requested in the intent to this activity */
private String[] mOriginalRequestedPermissions = new String[0];
@@ -157,26 +170,35 @@ public class GrantPermissionsActivity extends SettingsActivity
private List<RequestInfo> mRequestInfos = new ArrayList<>();
private GrantPermissionsViewHandler mViewHandler;
private GrantPermissionsViewModel mViewModel;
+
/**
* A list of other GrantPermissionActivities for the same package which passed their list of
* permissions to this one. They need to be informed when this activity finishes.
*/
private List<GrantPermissionsActivity> mFollowerActivities = new ArrayList<>();
+
/** Whether this activity has asked another GrantPermissionsActivity to show on its behalf */
private boolean mDelegated;
+
/** Whether this activity has been triggered by the system */
private boolean mIsSystemTriggered = false;
+
/** The set result code, or MAX_VALUE if it hasn't been set yet */
private int mResultCode = Integer.MAX_VALUE;
+
/** Package that shall have permissions granted */
private String mTargetPackage;
+
/** A key representing this activity, defined by the target package and task ID */
private Pair<String, Integer> mKey;
- private int mCurrentRequestIdx = 0;
+
private float mOriginalDimAmount;
private View mRootView;
private int mStoragePermGroupIcon = R.drawable.ic_empty_icon;
+ /** Which device the permission will affect. Default is the primary device. */
+ private int mTargetDeviceId = ContextCompat.DEVICE_ID_DEFAULT;
+
@Override
public void onCreate(Bundle icicle) {
if (DeviceUtils.isAuto(this)) {
@@ -191,6 +213,10 @@ public class GrantPermissionsActivity extends SettingsActivity
}
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ if (DeviceUtils.isWear(this)) {
+ // Do not grab input focus and hide keyboard.
+ getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM);
+ }
int permissionsSdkLevel;
if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(getIntent().getAction())) {
@@ -224,20 +250,51 @@ public class GrantPermissionsActivity extends SettingsActivity
}
}
- String[] requestedPermissionsArray = getIntent().getStringArrayExtra(
- PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
+ String[] requestedPermissionsArray =
+ getIntent().getStringArrayExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
if (requestedPermissionsArray == null) {
setResultAndFinish();
return;
}
- mRequestedPermissions = GrantPermissionsViewModel.Companion.getSanitizedPermissionsList(
- requestedPermissionsArray, permissionsSdkLevel);
+ mRequestedPermissions = removeNullOrEmptyPermissions(requestedPermissionsArray);
+ if (mIsSystemTriggered) {
+ mSystemRequestedPermissions.addAll(mRequestedPermissions);
+ }
+
if (mRequestedPermissions.isEmpty()) {
setResultAndFinish();
return;
}
+ if (MultiDeviceUtils.isDeviceAwareGrantFlowEnabled()) {
+ mTargetDeviceId =
+ getIntent()
+ .getIntExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID,
+ ContextCompat.DEVICE_ID_DEFAULT);
+ }
+
+ // If the permissions requested are for a remote device, check if each permission is device
+ // aware.
+ if (mTargetDeviceId != ContextCompat.DEVICE_ID_DEFAULT) {
+ if (!MultiDeviceUtils.isDeviceAwareGrantFlowEnabled()) {
+ Log.e(LOG_TAG, "targetDeviceId should be the default device if device aware grant"
+ + " flow is not enabled");
+ finishAfterTransition();
+ return;
+ }
+
+ for (String permission : mRequestedPermissions) {
+ if (!MultiDeviceUtils.isPermissionDeviceAware(permission)) {
+ Log.e(LOG_TAG, "When target device is external, permission " + permission
+ + " needs to be device aware.");
+ finishAfterTransition();
+ return;
+ }
+ }
+ }
+
mOriginalRequestedPermissions = mRequestedPermissions.toArray(new String[0]);
synchronized (sCurrentGrantRequests) {
@@ -247,8 +304,7 @@ public class GrantPermissionsActivity extends SettingsActivity
finishSystemStartedDialogsOnOtherTasksLocked();
} else if (mIsSystemTriggered) {
// The system triggered dialog doesn't require results. Delegate, and finish.
- sCurrentGrantRequests.get(mKey).onNewFollowerActivity(null,
- mRequestedPermissions);
+ sCurrentGrantRequests.get(mKey).onNewFollowerActivity(null, mRequestedPermissions);
finishAfterTransition();
return;
} else if (sCurrentGrantRequests.get(mKey).mIsSystemTriggered) {
@@ -277,9 +333,16 @@ public class GrantPermissionsActivity extends SettingsActivity
.GrantPermissionsViewHandlerImpl(this, this);
}
- GrantPermissionsViewModelFactory factory = new GrantPermissionsViewModelFactory(
- getApplication(), mTargetPackage, mRequestedPermissions, mSessionId, icicle);
if (!mDelegated) {
+ NewGrantPermissionsViewModelFactory factory =
+ new NewGrantPermissionsViewModelFactory(
+ getApplication(),
+ mTargetPackage,
+ mTargetDeviceId,
+ mRequestedPermissions,
+ mSystemRequestedPermissions,
+ mSessionId,
+ icicle);
mViewModel = factory.create(GrantPermissionsViewModel.class);
mViewModel.getRequestInfosLiveData().observe(this, this::onRequestInfoLoad);
}
@@ -364,9 +427,15 @@ public class GrantPermissionsActivity extends SettingsActivity
Bundle oldState = new Bundle();
mViewModel.getRequestInfosLiveData().removeObservers(this);
mViewModel.saveInstanceState(oldState);
- GrantPermissionsViewModelFactory factory = new GrantPermissionsViewModelFactory(
- getApplication(), mTargetPackage, mRequestedPermissions,
- mSessionId, oldState);
+ NewGrantPermissionsViewModelFactory factory =
+ new NewGrantPermissionsViewModelFactory(
+ getApplication(),
+ mTargetPackage,
+ mTargetDeviceId,
+ mRequestedPermissions,
+ mSystemRequestedPermissions,
+ mSessionId,
+ oldState);
mViewModel = factory.create(GrantPermissionsViewModel.class);
mViewModel.getRequestInfosLiveData().observe(this, this::onRequestInfoLoad);
if (follower != null) {
@@ -414,75 +483,54 @@ public class GrantPermissionsActivity extends SettingsActivity
// Only the top activity can receive activity results
Activity top = mFollowerActivities.isEmpty() ? this : mFollowerActivities.get(0);
- if (info.getSendToSettingsImmediately()) {
+ if (info.getPrompt() == Prompt.NO_UI_SETTINGS_REDIRECT) {
mViewModel.sendDirectlyToSettings(top, info.getGroupName());
return;
- } else if (info.getOpenPhotoPicker()) {
- mViewModel.openPhotoPicker(top, GRANTED_USER_SELECTED);
+ } else if (info.getPrompt() == Prompt.NO_UI_PHOTO_PICKER_REDIRECT) {
+ mViewModel.openPhotoPicker(top);
return;
- }
-
- if (Utils.isHealthPermissionUiEnabled() && HEALTH_PERMISSION_GROUP.equals(
- info.getGroupName())) {
+ } else if (info.getPrompt() == Prompt.NO_UI_FILTER_THIS_GROUP) {
+ // Filtered permissions should be removed from the requested permissions list entirely,
+ // and not have status returned to the app
+ List<String> permissionsToFilter =
+ PermissionMapping.getPlatformPermissionNamesOfGroup(info.getGroupName());
+ mRequestedPermissions.removeAll(permissionsToFilter);
+ mRequestInfos.remove(info);
+ onRequestInfoLoad(mRequestInfos);
+ return;
+ } else if (info.getPrompt() == Prompt.NO_UI_HEALTH_REDIRECT) {
mViewModel.handleHealthConnectPermissions(top);
return;
}
- CharSequence appLabel = KotlinUtils.INSTANCE.getPackageLabel(getApplication(),
- mTargetPackage, Process.myUserHandle());
-
- Icon icon = null;
- int messageId = 0;
- switch(info.getMessage()) {
- case FG_MESSAGE:
- messageId = Utils.getRequest(info.getGroupName());
- break;
- case FG_FINE_LOCATION_MESSAGE:
- messageId = R.string.permgrouprequest_fineupgrade;
- break;
- case FG_COARSE_LOCATION_MESSAGE:
- messageId = R.string.permgrouprequest_coarselocation;
- break;
- case BG_MESSAGE:
- messageId = Utils.getBackgroundRequest(info.getGroupName());
- break;
- case UPGRADE_MESSAGE:
- messageId = Utils.getUpgradeRequest(info.getGroupName());
- break;
- case STORAGE_SUPERGROUP_MESSAGE_Q_TO_S:
- icon = Icon.createWithResource(getPackageName(), mStoragePermGroupIcon);
- messageId = R.string.permgrouprequest_storage_q_to_s;
- break;
- case STORAGE_SUPERGROUP_MESSAGE_PRE_Q:
- icon = Icon.createWithResource(getPackageName(), mStoragePermGroupIcon);
- messageId = R.string.permgrouprequest_storage_pre_q;
- break;
- case MORE_PHOTOS_MESSAGE:
- messageId = R.string.permgrouprequest_more_photos;
- break;
- }
-
- CharSequence message = getRequestMessage(appLabel, mTargetPackage,
- info.getGroupName(), this, messageId);
-
- int detailMessageId = 0;
- switch(info.getDetailMessage()) {
- case FG_MESSAGE:
- detailMessageId = Utils.getRequestDetail(info.getGroupName());
- break;
- case BG_MESSAGE:
- detailMessageId = Utils.getBackgroundRequestDetail(info.getGroupName());
- break;
- case UPGRADE_MESSAGE:
- detailMessageId = Utils.getUpgradeRequestDetail(info.getGroupName());
- }
-
+ String appLabel =
+ KotlinUtils.INSTANCE.getPackageLabel(
+ getApplication(), mTargetPackage, Process.myUserHandle());
+
+ // Show device name in the dialog when the dialog is streamed to a remote device OR
+ // target device is different from streamed device.
+ int dialogDisplayDeviceId = ContextCompat.getDeviceId(this);
+ boolean isMessageDeviceAware =
+ dialogDisplayDeviceId != ContextCompat.DEVICE_ID_DEFAULT
+ || dialogDisplayDeviceId != mTargetDeviceId;
+
+ int messageId = getMessageId(info.getGroupName(), info.getPrompt(), isMessageDeviceAware);
+ CharSequence message =
+ getRequestMessage(
+ appLabel,
+ mTargetPackage,
+ info.getGroupName(),
+ MultiDeviceUtils.getDeviceName(getApplicationContext(), info.getDeviceId()),
+ this,
+ isMessageDeviceAware,
+ messageId);
+
+ int detailMessageId = getDetailMessageId(info.getGroupName(), info.getPrompt());
Spanned detailMessage = null;
if (detailMessageId != 0) {
- detailMessage =
- new SpannableString(getText(detailMessageId));
- Annotation[] annotations = detailMessage.getSpans(
- 0, detailMessage.length(), Annotation.class);
+ detailMessage = new SpannableString(getText(detailMessageId));
+ Annotation[] annotations =
+ detailMessage.getSpans(0, detailMessage.length(), Annotation.class);
int numAnnotations = annotations.length;
for (int i = 0; i < numAnnotations; i++) {
Annotation annotation = annotations[i];
@@ -490,8 +538,7 @@ public class GrantPermissionsActivity extends SettingsActivity
int start = detailMessage.getSpanStart(annotation);
int end = detailMessage.getSpanEnd(annotation);
ClickableSpan clickableSpan = getLinkToAppPermissions(info);
- SpannableString spannableString =
- new SpannableString(detailMessage);
+ SpannableString spannableString = new SpannableString(detailMessage);
spannableString.setSpan(clickableSpan, start, end, 0);
detailMessage = spannableString;
break;
@@ -499,16 +546,20 @@ public class GrantPermissionsActivity extends SettingsActivity
}
}
+ Icon icon = null;
try {
- icon = icon != null ? icon : Icon.createWithResource(
- info.getGroupInfo().getPackageName(),
- info.getGroupInfo().getIcon());
+ if (info.getPrompt() == Prompt.STORAGE_SUPERGROUP_Q_TO_S
+ || info.getPrompt() == Prompt.STORAGE_SUPERGROUP_PRE_Q) {
+ icon = Icon.createWithResource(getPackageName(), mStoragePermGroupIcon);
+ } else {
+ icon = Icon.createWithResource(
+ info.getGroupInfo().getPackageName(),
+ info.getGroupInfo().getIcon());
+ }
} catch (Resources.NotFoundException e) {
Log.e(LOG_TAG, "Cannot load icon for group" + info.getGroupName(), e);
}
- boolean showingNewGroup = message == null || !message.equals(getTitle());
-
// Set the permission message as the title so it can be announced. Skip on Wear
// because the dialog title is already announced, as is the default selection which
// is a text view containing the title.
@@ -516,14 +567,8 @@ public class GrantPermissionsActivity extends SettingsActivity
setTitle(message);
}
- ArrayList<Integer> idxs = new ArrayList<>();
- mButtonVisibilities = new boolean[info.getButtonVisibilities().size()];
- for (int i = 0; i < info.getButtonVisibilities().size(); i++) {
- mButtonVisibilities[i] = info.getButtonVisibilities().get(i);
- if (mButtonVisibilities[i]) {
- idxs.add(i);
- }
- }
+ mButtonVisibilities = getButtonsForPrompt(info.getPrompt(), info.getDeny(),
+ info.getShowRationale());
CharSequence permissionRationaleMessage = null;
if (isPermissionRationaleVisible()) {
@@ -533,49 +578,136 @@ public class GrantPermissionsActivity extends SettingsActivity
info.getGroupName()));
}
- boolean[] locationVisibilities = new boolean[info.getLocationVisibilities().size()];
- for (int i = 0; i < info.getLocationVisibilities().size(); i++) {
- locationVisibilities[i] = info.getLocationVisibilities().get(i);
- }
+ boolean[] locationVisibilities = getLocationButtonsForPrompt(info.getPrompt());
if (mRequestCounts < mRequestInfos.size()) {
mRequestCounts = mRequestInfos.size();
}
- mViewHandler.updateUi(info.getGroupName(), mRequestCounts, mCurrentRequestIdx, icon,
+ int pageIdx = mRequestCounts - mRequestInfos.size();
+ mViewHandler.updateUi(info.getGroupName(), mRequestCounts, pageIdx, icon,
message, detailMessage, permissionRationaleMessage, mButtonVisibilities,
locationVisibilities);
- if (showingNewGroup) {
- mCurrentRequestIdx++;
- }
getWindow().setDimAmount(mOriginalDimAmount);
if (mRootView.getVisibility() == View.GONE) {
- InputMethodManager manager = getSystemService(InputMethodManager.class);
- manager.hideSoftInputFromWindow(mRootView.getWindowToken(), 0);
+ if (mIsSystemTriggered) {
+ // We don't want the keyboard obscuring system-triggered dialogs
+ InputMethodManager manager = getSystemService(InputMethodManager.class);
+ manager.hideSoftInputFromWindow(mRootView.getWindowToken(), 0);
+ }
mRootView.setVisibility(View.VISIBLE);
}
}
- // LINT.IfChange(dispatchTouchEvent)
+ private int getMessageId(String permGroupName, Prompt prompt, Boolean isDeviceAware) {
+ return switch (prompt) {
+ case UPGRADE_SETTINGS_LINK, OT_UPGRADE_SETTINGS_LINK -> Utils.getUpgradeRequest(
+ permGroupName, isDeviceAware);
+ case SETTINGS_LINK_FOR_BG, SETTINGS_LINK_WITH_OT -> Utils.getBackgroundRequest(
+ permGroupName, isDeviceAware);
+ case LOCATION_FINE_UPGRADE -> Utils.getFineLocationRequest(isDeviceAware);
+ case LOCATION_COARSE_ONLY -> Utils.getCoarseLocationRequest(isDeviceAware);
+ case STORAGE_SUPERGROUP_PRE_Q -> R.string.permgrouprequest_storage_pre_q;
+ case STORAGE_SUPERGROUP_Q_TO_S -> R.string.permgrouprequest_storage_q_to_s;
+ case SELECT_MORE_PHOTOS -> Utils.getMorePhotosRequest(isDeviceAware);
+ default -> Utils.getRequest(permGroupName, isDeviceAware);
+ };
+ }
+
+ private int getDetailMessageId(String permGroupName, Prompt prompt) {
+ return switch (prompt) {
+ case UPGRADE_SETTINGS_LINK, OT_UPGRADE_SETTINGS_LINK ->
+ Utils.getUpgradeRequestDetail(permGroupName);
+ case SETTINGS_LINK_FOR_BG, SETTINGS_LINK_WITH_OT ->
+ Utils.getBackgroundRequestDetail(permGroupName);
+ default -> 0;
+ };
+ }
+
+ private boolean[] getButtonsForPrompt(Prompt prompt, DenyButton denyButton,
+ boolean shouldShowRationale) {
+ ArraySet<Integer> buttons = new ArraySet<>();
+ switch (prompt) {
+ case BASIC, STORAGE_SUPERGROUP_PRE_Q, STORAGE_SUPERGROUP_Q_TO_S ->
+ buttons.add(ALLOW_BUTTON);
+ case FG_ONLY, SETTINGS_LINK_FOR_BG -> buttons.add(ALLOW_FOREGROUND_BUTTON);
+ case ONE_TIME_FG, SETTINGS_LINK_WITH_OT, LOCATION_TWO_BUTTON_COARSE_HIGHLIGHT,
+ LOCATION_TWO_BUTTON_FINE_HIGHLIGHT, LOCATION_COARSE_ONLY,
+ LOCATION_FINE_UPGRADE ->
+ buttons.addAll(Arrays.asList(ALLOW_FOREGROUND_BUTTON, ALLOW_ONE_TIME_BUTTON));
+ case SELECT_PHOTOS, SELECT_MORE_PHOTOS ->
+ buttons.addAll(Arrays.asList(ALLOW_ALL_BUTTON, ALLOW_SELECTED_BUTTON));
+ }
+
+ switch (denyButton) {
+ case DENY -> buttons.add(DENY_BUTTON);
+ case DENY_DONT_ASK_AGAIN -> buttons.add(DENY_AND_DONT_ASK_AGAIN_BUTTON);
+ case DONT_SELECT_MORE -> buttons.add(DONT_ALLOW_MORE_SELECTED_BUTTON);
+ case NO_UPGRADE -> buttons.add(NO_UPGRADE_BUTTON);
+ case NO_UPGRADE_OT -> buttons.add(NO_UPGRADE_OT_BUTTON);
+ case NO_UPGRADE_AND_DONT_ASK_AGAIN ->
+ buttons.add(NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON);
+ case NO_UPGRADE_AND_DONT_ASK_AGAIN_OT ->
+ buttons.add(NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON);
+ }
+
+ if (shouldShowRationale) {
+ buttons.add(LINK_TO_PERMISSION_RATIONALE);
+ }
+ return convertSetToBoolList(buttons, NEXT_BUTTON);
+ }
+
+ private boolean[] getLocationButtonsForPrompt(Prompt prompt) {
+ ArraySet<Integer> locationButtons = new ArraySet<>();
+ switch (prompt) {
+ case LOCATION_TWO_BUTTON_COARSE_HIGHLIGHT ->
+ locationButtons.addAll(Arrays.asList(LOCATION_ACCURACY_LAYOUT,
+ DIALOG_WITH_BOTH_LOCATIONS, COARSE_RADIO_BUTTON));
+ case LOCATION_TWO_BUTTON_FINE_HIGHLIGHT ->
+ locationButtons.addAll(Arrays.asList(LOCATION_ACCURACY_LAYOUT,
+ DIALOG_WITH_BOTH_LOCATIONS, FINE_RADIO_BUTTON));
+ case LOCATION_COARSE_ONLY ->
+ locationButtons.addAll(Arrays.asList(LOCATION_ACCURACY_LAYOUT,
+ DIALOG_WITH_COARSE_LOCATION_ONLY));
+ case LOCATION_FINE_UPGRADE ->
+ locationButtons.addAll(Arrays.asList(LOCATION_ACCURACY_LAYOUT,
+ DIALOG_WITH_FINE_LOCATION_ONLY));
+ }
+ return convertSetToBoolList(locationButtons, NEXT_LOCATION_DIALOG);
+ }
+
+ private boolean[] convertSetToBoolList(Set<Integer> buttonSet, int size) {
+ boolean[] buttonArray = new boolean[size];
+ for (int button: buttonSet) {
+ buttonArray[button] = true;
+ }
+ return buttonArray;
+ }
+
@Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- View rootView = getWindow().getDecorView();
- if (rootView.getTop() != 0) {
- // We are animating the top view, need to compensate for that in motion events.
- ev.setLocation(ev.getX(), ev.getY() - rootView.getTop());
- }
- final int x = (int) ev.getX();
- final int y = (int) ev.getY();
- if ((x < 0) || (y < 0) || (x > (rootView.getWidth())) || (y > (rootView.getHeight()))) {
- if (MotionEvent.ACTION_DOWN == ev.getAction()) {
- mViewHandler.onCancelled();
- }
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE
+ && event.getRepeatCount() == 0
+ && event.hasNoModifiers()) {
+ event.startTracking();
+ mViewHandler.onCancelled();
finishAfterTransition();
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE
+ && event.isTracking()
+ && !event.isCanceled()) {
+ // Mark it as handled since we did handle the down event
+ return true;
}
- return super.dispatchTouchEvent(ev);
+ return super.onKeyUp(keyCode, event);
}
- // LINT.ThenChange(PermissionRationaleActivity.java:dispatchTouchEvent)
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
@@ -606,16 +738,14 @@ public class GrantPermissionsActivity extends SettingsActivity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- Consumer<Intent> callback = mViewModel.getActivityResultCallback();
- if (callback == null || (requestCode != APP_PERMISSION_REQUEST_CODE
- && requestCode != PHOTO_PICKER_REQUEST_CODE)) {
+ if (requestCode != APP_PERMISSION_REQUEST_CODE
+ && requestCode != PHOTO_PICKER_REQUEST_CODE) {
return;
}
if (requestCode == PHOTO_PICKER_REQUEST_CODE) {
data = new Intent("").putExtra(INTENT_PHOTOS_SELECTED, resultCode == RESULT_OK);
}
- callback.accept(data);
- mViewModel.setActivityResultCallback(null);
+ mViewModel.handleCallback(data, requestCode);
}
@Override
@@ -635,18 +765,16 @@ public class GrantPermissionsActivity extends SettingsActivity
mPreMergeShownGroupName = null;
}
- if (Objects.equals(READ_MEDIA_VISUAL, name)
- && result == GrantPermissionsViewHandler.GRANTED_USER_SELECTED) {
+ if (Objects.equals(READ_MEDIA_VISUAL, name) && result == GRANTED_USER_SELECTED) {
// Only the top activity can receive activity results
Activity top = mFollowerActivities.isEmpty() ? this : mFollowerActivities.get(0);
- mViewModel.openPhotoPicker(top, result);
+ mViewModel.openPhotoPicker(top);
logGrantPermissionActivityButtons(name, affectedForegroundPermissions, result);
return;
}
logGrantPermissionActivityButtons(name, affectedForegroundPermissions, result);
mViewModel.onPermissionGrantResult(name, affectedForegroundPermissions, result);
- showNextRequest();
if (result == CANCELED) {
setResultAndFinish();
}
@@ -877,6 +1005,18 @@ public class GrantPermissionsActivity extends SettingsActivity
return mResultCode != Integer.MAX_VALUE;
}
+ // Remove null and empty permissions from an array, return a list
+ private List<String> removeNullOrEmptyPermissions(String[] perms) {
+ ArrayList<String> sanitized = new ArrayList<>();
+ for (String perm : perms) {
+ if (perm == null || perm.isEmpty()) {
+ continue;
+ }
+ sanitized.add(perm);
+ }
+ return sanitized;
+ }
+
/**
* If there is another system-shown dialog on another task, that is not being relied upon by an
* app-defined dialogs, these other dialogs should be finished.
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
index afeb19aa9..4cd595b55 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
@@ -31,7 +31,7 @@ import static com.android.permissioncontroller.PermissionControllerStatsLog.PERM
import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__OPEN;
import android.Manifest;
-import android.app.ActionBar;
+import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -71,14 +71,16 @@ import com.android.permissioncontroller.permission.ui.auto.dashboard.AutoPermiss
import com.android.permissioncontroller.permission.ui.auto.dashboard.AutoPermissionUsageFragment;
import com.android.permissioncontroller.permission.ui.handheld.AppPermissionFragment;
import com.android.permissioncontroller.permission.ui.handheld.AppPermissionGroupsFragment;
-import com.android.permissioncontroller.permission.ui.handheld.HandheldUnusedAppsWrapperFragment;
import com.android.permissioncontroller.permission.ui.handheld.PermissionAppsFragment;
import com.android.permissioncontroller.permission.ui.handheld.v31.PermissionDetailsWrapperFragment;
import com.android.permissioncontroller.permission.ui.handheld.v31.PermissionUsageWrapperFragment;
import com.android.permissioncontroller.permission.ui.handheld.v34.AppDataSharingUpdatesFragment;
import com.android.permissioncontroller.permission.ui.legacy.AppPermissionActivity;
import com.android.permissioncontroller.permission.ui.television.TvUnusedAppsFragment;
-import com.android.permissioncontroller.permission.ui.wear.AppPermissionsFragmentWear;
+import com.android.permissioncontroller.permission.ui.wear.WearAppPermissionFragment;
+import com.android.permissioncontroller.permission.ui.wear.WearPermissionUsageDetailsFragment;
+import com.android.permissioncontroller.permission.ui.wear.WearPermissionUsageFragment;
+import com.android.permissioncontroller.permission.ui.wear.WearUnusedAppsFragment;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.Utils;
@@ -138,11 +140,12 @@ public final class ManagePermissionsActivity extends SettingsActivity {
*/
private static final int PROXY_ACTIVITY_REQUEST_CODE = 5;
+ @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
private static final String LAUNCH_PERMISSION_SETTINGS =
- "android.permission.LAUNCH_PERMISSION_SETTINGS";
+ Manifest.permission.LAUNCH_PERMISSION_SETTINGS;
- private static final String APP_PERMISSIONS_SETTINGS =
- "android.settings.APP_PERMISSIONS_SETTINGS";
+ @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static final String APP_PERMISSIONS_SETTINGS = Settings.ACTION_APP_PERMISSIONS_SETTINGS;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -153,10 +156,10 @@ public final class ManagePermissionsActivity extends SettingsActivity {
}
super.onCreate(savedInstanceState);
- // If this is not a phone (which uses the Navigation component), and there is a previous
- // instance, re-use its Fragment instead of making a new one.
- if ((DeviceUtils.isTelevision(this) || DeviceUtils.isAuto(this)
- || DeviceUtils.isWear(this)) && savedInstanceState != null) {
+ // If this is not a phone or a watch (which uses the Navigation component), and there
+ // is a previous instance, re-use its Fragment instead of making a new one.
+ if ((DeviceUtils.isTelevision(this) || DeviceUtils.isAuto(this))
+ && savedInstanceState != null) {
return;
}
@@ -228,6 +231,8 @@ public final class ManagePermissionsActivity extends SettingsActivity {
PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__OPEN);
if (DeviceUtils.isAuto(this)) {
androidXFragment = new AutoPermissionUsageFragment();
+ } else if (DeviceUtils.isWear(this)) {
+ androidXFragment = WearPermissionUsageFragment.newInstance(sessionId);
} else {
androidXFragment = PermissionUsageWrapperFragment.newInstance(
Long.MAX_VALUE, sessionId);
@@ -249,6 +254,9 @@ public final class ManagePermissionsActivity extends SettingsActivity {
if (DeviceUtils.isAuto(this)) {
androidXFragment = AutoPermissionUsageDetailsFragment.Companion.newInstance(
groupName, showSystem, sessionId);
+ } else if (DeviceUtils.isWear(this)) {
+ androidXFragment = WearPermissionUsageDetailsFragment
+ .newInstance(groupName, showSystem, show7Days);
} else {
androidXFragment = PermissionDetailsWrapperFragment
.newInstance(groupName, Long.MAX_VALUE, showSystem, sessionId,
@@ -258,8 +266,7 @@ public final class ManagePermissionsActivity extends SettingsActivity {
}
case Intent.ACTION_MANAGE_APP_PERMISSION: {
- if (DeviceUtils.isAuto(this) || DeviceUtils.isTelevision(this)
- || DeviceUtils.isWear(this)) {
+ if (DeviceUtils.isAuto(this) || DeviceUtils.isTelevision(this)) {
Intent compatIntent = new Intent(this, AppPermissionActivity.class);
compatIntent.putExtras(getIntent().getExtras());
startActivityForResult(compatIntent, PROXY_ACTIVITY_REQUEST_CODE);
@@ -297,15 +304,22 @@ public final class ManagePermissionsActivity extends SettingsActivity {
return;
}
- Bundle args = AppPermissionFragment.createArgs(packageName, permissionName,
- groupName, userHandle, caller, sessionId, null);
+ Bundle args;
+ if (DeviceUtils.isWear(this)) {
+ args = WearAppPermissionFragment.createArgs(packageName, permissionName,
+ groupName, userHandle, caller, sessionId, null);
+ } else {
+ args = AppPermissionFragment.createArgs(packageName, permissionName,
+ groupName, userHandle, caller, sessionId, null);
+ }
setNavGraph(args, R.id.app_permission);
return;
}
case Intent.ACTION_MANAGE_APP_PERMISSIONS:
case APP_PERMISSIONS_SETTINGS: {
- if (Objects.equals(action, APP_PERMISSIONS_SETTINGS)) {
+ if (!SdkLevel.isAtLeastV()
+ && Objects.equals(action, APP_PERMISSIONS_SETTINGS)) {
PermissionInfo permissionInfo;
try {
permissionInfo = getPackageManager()
@@ -374,8 +388,6 @@ public final class ManagePermissionsActivity extends SettingsActivity {
androidXFragment = AutoAppPermissionsFragment.newInstance(packageName,
userHandle, sessionId, /* isSystemPermsScreen= */ true);
}
- } else if (DeviceUtils.isWear(this)) {
- androidXFragment = AppPermissionsFragmentWear.newInstance(packageName);
} else if (DeviceUtils.isTelevision(this)) {
androidXFragment = com.android.permissioncontroller.permission.ui.television
.AppPermissionsFragment.newInstance(packageName, userHandle);
@@ -473,8 +485,8 @@ public final class ManagePermissionsActivity extends SettingsActivity {
androidXFragment = TvUnusedAppsFragment.newInstance();
androidXFragment.setArguments(UnusedAppsFragment.createArgs(sessionId));
} else if (DeviceUtils.isWear(this)) {
- androidXFragment = HandheldUnusedAppsWrapperFragment.newInstance();
- androidXFragment.setArguments(UnusedAppsFragment.createArgs(sessionId));
+ setNavGraph(WearUnusedAppsFragment.createArgs(sessionId), R.id.auto_revoke);
+ return;
} else {
setNavGraph(UnusedAppsFragment.createArgs(sessionId), R.id.auto_revoke);
return;
@@ -549,15 +561,6 @@ public final class ManagePermissionsActivity extends SettingsActivity {
}
@Override
- public ActionBar getActionBar() {
- ActionBar ab = super.getActionBar();
- if (ab != null) {
- ab.setHomeActionContentDescription(R.string.back);
- }
- return ab;
- }
-
- @Override
public boolean onOptionsItemSelected(MenuItem item) {
// in automotive mode, there's no system wide back button, so need to add that
if (DeviceUtils.isAuto(this)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/RemovablePref.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/RemovablePref.kt
index 2525c191c..df4e7947a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/RemovablePref.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/RemovablePref.kt
@@ -16,17 +16,11 @@
package com.android.permissioncontroller.permission.ui
-/**
- * Preference with a clickable UI component for removal.
- */
+/** Preference with a clickable UI component for removal. */
interface RemovablePref {
- /**
- * Sets the action to run when the remove UI component is clicked.
- */
+ /** Sets the action to run when the remove UI component is clicked. */
fun setRemoveClickRunnable(runnable: Runnable)
- /**
- * Set whether the UI component for removal should be enabled or not.
- */
+ /** Set whether the UI component for removal should be enabled or not. */
fun setRemoveComponentEnabled(enabled: Boolean)
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/permission/ui/TEST_MAPPING
index de4c3a2b9..2a4953f51 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/TEST_MAPPING
@@ -5,6 +5,9 @@
"options": [
{
"include-filter": "android.permission.cts.OneTimePermissionTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
@@ -17,14 +20,22 @@
"include-annotation": "com.android.cts.devicepolicy.annotations.PermissionsTest"
},
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
],
"postsubmit": [
{
- "name": "CtsPermission3TestCases"
+ "name": "CtsPermissionUiTestCases"
+ },
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.OneTimePermissionTest"
+ }
+ ]
}
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
index 68fb493eb..69aef1a4f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
@@ -52,12 +52,14 @@ import com.android.permissioncontroller.permission.utils.KotlinUtils
import java.text.Collator
/**
- * A fragment displaying all applications that are unused as well as the option to remove them
- * and to open them.
+ * A fragment displaying all applications that are unused as well as the option to remove them and
+ * to open them.
*/
-class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
- where PF : PreferenceFragmentCompat, PF : UnusedAppsFragment.Parent<UnusedAppPref>,
- UnusedAppPref : Preference, UnusedAppPref : RemovablePref {
+class UnusedAppsFragment<PF, UnusedAppPref> : Fragment() where
+PF : PreferenceFragmentCompat,
+PF : UnusedAppsFragment.Parent<UnusedAppPref>,
+UnusedAppPref : Preference,
+UnusedAppPref : RemovablePref {
private lateinit var viewModel: UnusedAppsViewModel
private lateinit var collator: Collator
@@ -72,9 +74,11 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
private val LOG_TAG = UnusedAppsFragment::class.java.simpleName
@JvmStatic
- fun <PF, UnusedAppPref> newInstance(): UnusedAppsFragment<PF, UnusedAppPref>
- where PF : PreferenceFragmentCompat, PF : UnusedAppsFragment.Parent<UnusedAppPref>,
- UnusedAppPref : Preference, UnusedAppPref : RemovablePref {
+ fun <PF, UnusedAppPref> newInstance(): UnusedAppsFragment<PF, UnusedAppPref> where
+ PF : PreferenceFragmentCompat,
+ PF : UnusedAppsFragment.Parent<UnusedAppPref>,
+ UnusedAppPref : Preference,
+ UnusedAppPref : RemovablePref {
return UnusedAppsFragment()
}
@@ -82,7 +86,6 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
* Create the args needed for this fragment
*
* @param sessionId The current session Id
- *
* @return A bundle containing the session Id
*/
@JvmStatic
@@ -101,29 +104,35 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
val preferenceFragment: PF = requirePreferenceFragment()
isFirstLoad = true
- collator = Collator.getInstance(
- context!!.getResources().getConfiguration().getLocales().get(0))
+ collator =
+ Collator.getInstance(context!!.getResources().getConfiguration().getLocales().get(0))
sessionId = arguments!!.getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID)
val factory = UnusedAppsViewModelFactory(activity!!.application, sessionId)
viewModel = ViewModelProvider(this, factory).get(UnusedAppsViewModel::class.java)
- viewModel.unusedPackageCategoriesLiveData.observe(this, Observer {
- it?.let { pkgs ->
- updatePackages(pkgs)
- preferenceFragment.setLoadingState(loading = false, animate = true)
+ viewModel.unusedPackageCategoriesLiveData.observe(
+ this,
+ Observer {
+ it?.let { pkgs ->
+ updatePackages(pkgs)
+ preferenceFragment.setLoadingState(loading = false, animate = true)
+ }
}
- })
+ )
activity?.getActionBar()?.setDisplayHomeAsUpEnabled(true)
if (!viewModel.unusedPackageCategoriesLiveData.isInitialized) {
val handler = Handler(Looper.getMainLooper())
- handler.postDelayed({
- if (!viewModel.unusedPackageCategoriesLiveData.isInitialized) {
- preferenceFragment.setLoadingState(loading = true, animate = true)
- } else {
- updatePackages(viewModel.unusedPackageCategoriesLiveData.value!!)
- }
- }, SHOW_LOAD_DELAY_MS)
+ handler.postDelayed(
+ {
+ if (!viewModel.unusedPackageCategoriesLiveData.isInitialized) {
+ preferenceFragment.setLoadingState(loading = true, animate = true)
+ } else {
+ updatePackages(viewModel.unusedPackageCategoriesLiveData.value!!)
+ }
+ },
+ SHOW_LOAD_DELAY_MS
+ )
} else {
updatePackages(viewModel.unusedPackageCategoriesLiveData.value!!)
}
@@ -150,15 +159,15 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
return requireParentFragment() as PF
}
- /**
- * Create [PreferenceScreen] in the parent fragment.
- */
+ /** Create [PreferenceScreen] in the parent fragment. */
private fun createPreferenceScreen() {
val preferenceFragment: PF = requirePreferenceFragment()
- val preferenceScreen = preferenceFragment.preferenceManager.inflateFromResource(
- context!!,
- R.xml.unused_app_categories,
- /* rootPreferences= */ null)
+ val preferenceScreen =
+ preferenceFragment.preferenceManager.inflateFromResource(
+ context!!,
+ R.xml.unused_app_categories,
+ /* rootPreferences= */ null
+ )
for (period in allPeriods) {
val periodCat = PreferenceCategory(context!!)
@@ -208,8 +217,10 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
val category = preferenceScreen.findPreference<PreferenceCategory>(period.name)!!
val months = period.months
category.title =
- MessageFormat.format(getString(R.string.last_opened_category_title),
- mapOf("count" to months))
+ MessageFormat.format(
+ getString(R.string.last_opened_category_title),
+ mapOf("count" to months)
+ )
category.isVisible = packages.isNotEmpty()
if (packages.isNotEmpty()) {
allCategoriesEmpty = false
@@ -221,39 +232,53 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
var pref = category.findPreference<UnusedAppPref>(key)
if (pref == null) {
- pref = removedPrefs[key] ?: preferenceFragment.createUnusedAppPref(
- activity!!.application, pkgName, user)
+ pref =
+ removedPrefs[key]
+ ?: preferenceFragment.createUnusedAppPref(
+ activity!!.application,
+ pkgName,
+ user
+ )
pref.key = key
pref.title = KotlinUtils.getPackageLabel(activity!!.application, pkgName, user)
}
- pref.setRemoveClickRunnable {
- viewModel.requestUninstallApp(this, pkgName, user)
- }
+ pref.setRemoveClickRunnable { viewModel.requestUninstallApp(this, pkgName, user) }
pref.setRemoveComponentEnabled(!isSystemApp)
- pref.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
- viewModel.navigateToAppInfo(pkgName, user, sessionId)
- true
- }
+ pref.onPreferenceClickListener =
+ Preference.OnPreferenceClickListener { _ ->
+ viewModel.navigateToAppInfo(pkgName, user, sessionId)
+ true
+ }
val mostImportant = getMostImportantGroup(revokedPerms)
val importantLabel = KotlinUtils.getPermGroupLabel(context!!, mostImportant)
- pref.summary = when {
- revokedPerms.isEmpty() -> null
- revokedPerms.size == 1 -> getString(R.string.auto_revoked_app_summary_one,
- importantLabel)
- revokedPerms.size == 2 -> {
- val otherLabel = if (revokedPerms[0] == mostImportant) {
- KotlinUtils.getPermGroupLabel(context!!, revokedPerms[1])
- } else {
- KotlinUtils.getPermGroupLabel(context!!, revokedPerms[0])
+ pref.summary =
+ when {
+ revokedPerms.isEmpty() -> null
+ revokedPerms.size == 1 ->
+ getString(R.string.auto_revoked_app_summary_one, importantLabel)
+ revokedPerms.size == 2 -> {
+ val otherLabel =
+ if (revokedPerms[0] == mostImportant) {
+ KotlinUtils.getPermGroupLabel(context!!, revokedPerms[1])
+ } else {
+ KotlinUtils.getPermGroupLabel(context!!, revokedPerms[0])
+ }
+ getString(
+ R.string.auto_revoked_app_summary_two,
+ importantLabel,
+ otherLabel
+ )
}
- getString(R.string.auto_revoked_app_summary_two, importantLabel, otherLabel)
+ else ->
+ getString(
+ R.string.auto_revoked_app_summary_many,
+ importantLabel,
+ "${revokedPerms.size - 1}"
+ )
}
- else -> getString(R.string.auto_revoked_app_summary_many, importantLabel,
- "${revokedPerms.size - 1}")
- }
category.addPreference(pref)
KotlinUtils.sortPreferenceGroup(category, this::comparePreference, false)
}
@@ -267,13 +292,19 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
}
Log.i(LOG_TAG, "sessionId: $sessionId Showed Auto Revoke Page")
for (period in allPeriods) {
- Log.i(LOG_TAG, "sessionId: $sessionId $period unused: " +
- "${categorizedPackages[period]}")
+ Log.i(
+ LOG_TAG,
+ "sessionId: $sessionId $period unused: " + "${categorizedPackages[period]}"
+ )
for (revokedPackageInfo in categorizedPackages[period]!!) {
for (groupName in revokedPackageInfo.revokedGroups) {
val isNewlyRevoked = period.isNewlyUnused()
- viewModel.logAppView(revokedPackageInfo.packageName,
- revokedPackageInfo.user, groupName, isNewlyRevoked)
+ viewModel.logAppView(
+ revokedPackageInfo.packageName,
+ revokedPackageInfo.user,
+ groupName,
+ isNewlyRevoked
+ )
}
}
}
@@ -281,8 +312,7 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
}
private fun comparePreference(lhs: Preference, rhs: Preference): Int {
- var result = collator.compare(lhs.title.toString(),
- rhs.title.toString())
+ var result = collator.compare(lhs.title.toString(), rhs.title.toString())
if (result == 0) {
result = lhs.key.compareTo(rhs.key)
}
@@ -324,23 +354,23 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
val fragment = parentFragment as UnusedAppsFragment<*, *>
val packageName = arguments!!.getString(Intent.EXTRA_PACKAGE_NAME)!!
val user = arguments!!.getParcelable<UserHandle>(Intent.EXTRA_USER)!!
- val b = AlertDialog.Builder(context!!)
- .setMessage(R.string.app_disable_dlg_text)
- .setPositiveButton(R.string.app_disable_dlg_positive) { _, _ ->
- fragment.viewModel.disableApp(packageName, user)
- }
- .setNegativeButton(R.string.cancel, null)
+ val b =
+ AlertDialog.Builder(context!!)
+ .setMessage(R.string.app_disable_dlg_text)
+ .setPositiveButton(R.string.app_disable_dlg_positive) { _, _ ->
+ fragment.viewModel.disableApp(packageName, user)
+ }
+ .setNegativeButton(R.string.cancel, null)
val d: Dialog = b.create()
d.setCanceledOnTouchOutside(true)
return d
}
}
- /**
- * Interface that the parent fragment must implement.
- */
- interface Parent<UnusedAppPref> where UnusedAppPref : Preference,
- UnusedAppPref : RemovablePref {
+ /** Interface that the parent fragment must implement. */
+ interface Parent<UnusedAppPref> where
+ UnusedAppPref : Preference,
+ UnusedAppPref : RemovablePref {
/**
* Set the title of the current settings page.
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
index 2de936469..496d36dc9 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
@@ -382,8 +382,9 @@ public class AutoAppPermissionFragment extends AutoSettingsFrameFragment
private static class SelectedPermissionPreference extends TwoStatePreference {
SelectedPermissionPreference(Context context) {
- super(context, null, TypedArrayUtils.getAttr(context, R.attr.preferenceStyle,
- android.R.attr.preferenceStyle));
+ super(context, null,
+ TypedArrayUtils.getAttr(context, androidx.preference.R.attr.preferenceStyle,
+ android.R.attr.preferenceStyle));
setPersistent(false);
setLayoutResource(R.layout.car_radio_button_preference);
setWidgetLayoutResource(R.layout.radio_button_preference_widget);
@@ -418,7 +419,7 @@ public class AutoAppPermissionFragment extends AutoSettingsFrameFragment
// TODO(b/229024576): This code is duplicated, refactor ConfirmDialog for easier
// NFF sharing
boolean isGrantFileAccess = getArguments().getSerializable(CHANGE_REQUEST)
- == ChangeRequest.GRANT_All_FILE_ACCESS;
+ == ChangeRequest.GRANT_ALL_FILE_ACCESS;
boolean isGrantStorageSupergroup = getArguments().getSerializable(CHANGE_REQUEST)
== ChangeRequest.GRANT_STORAGE_SUPERGROUP;
int positiveButtonStringResId = R.string.grant_dialog_button_deny_anyway;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java
index cf58f1e17..446d97c3e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java
@@ -400,7 +400,7 @@ public class AutoAppPermissionsFragment extends AutoSettingsFrameFragment implem
}
PermissionControllerStatsLog.write(APP_PERMISSIONS_FRAGMENT_VIEWED, sessionId, viewId,
permissionGroupName, uid, mPackageName, category);
- Log.v(LOG_TAG, "AutoAppPermissionFragment view logged with sessionId=" + sessionId
+ Log.i(LOG_TAG, "AutoAppPermissionFragment view logged with sessionId=" + sessionId
+ " viewId=" + viewId + " permissionGroupName=" + permissionGroupName + " uid="
+ uid + " packageName="
+ mPackageName + " category=" + category);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoDividerPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoDividerPreference.kt
index aa3c7ffd7..7bb4ccb05 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoDividerPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoDividerPreference.kt
@@ -20,9 +20,7 @@ import android.util.AttributeSet
import androidx.preference.Preference
import com.android.permissioncontroller.R
-/**
- * Non-interactive preference that displays a horizontal divider.
- */
+/** Non-interactive preference that displays a horizontal divider. */
class AutoDividerPreference : Preference {
constructor(
context: Context?,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java
index 29fcb43b2..3b8419bcf 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java
@@ -22,6 +22,7 @@ import static com.android.permissioncontroller.permission.ui.Category.ALLOWED;
import static com.android.permissioncontroller.permission.ui.Category.ALLOWED_FOREGROUND;
import static com.android.permissioncontroller.permission.ui.Category.ASK;
import static com.android.permissioncontroller.permission.ui.Category.DENIED;
+import static com.android.permissioncontroller.permission.ui.Category.STORAGE_FOOTER;
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME;
import android.content.Context;
@@ -52,15 +53,15 @@ import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.settingslib.utils.applications.AppUtils;
+import kotlin.Pair;
+import kotlin.Triple;
+
import java.text.Collator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
-import kotlin.Pair;
-import kotlin.Triple;
-
/** Shows the list of applications which have (or do not have) the given permission. */
public class AutoPermissionAppsFragment extends AutoSettingsFrameFragment implements
PermissionUsages.PermissionsUsagesChangeCallback {
@@ -172,6 +173,10 @@ public class AutoPermissionAppsFragment extends AutoSettingsFrameFragment implem
}
// Hide allowed foreground label by default, to avoid briefly showing it before updating
findPreference(ALLOWED_FOREGROUND.getCategoryName()).setVisible(false);
+
+ // Hide storage footer category
+ findPreference(STORAGE_FOOTER.getCategoryName()).setVisible(false);
+
Context context = getPreferenceManager().getContext();
if (context == null || getActivity() == null || categories == null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsFragment.kt
index 92917a342..99f5c85e4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsFragment.kt
@@ -53,20 +53,19 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
private const val LOG_TAG = "AutoReviewPermissionDecisionsFragment"
private const val MAX_DECISIONS = 3
- /**
- * Creates a new instance of [AutoReviewPermissionDecisionsFragment].
- */
+ /** Creates a new instance of [AutoReviewPermissionDecisionsFragment]. */
fun newInstance(
sessionId: Long,
userHandle: UserHandle,
source: String?
): AutoReviewPermissionDecisionsFragment {
return AutoReviewPermissionDecisionsFragment().apply {
- arguments = Bundle().apply {
- putLong(Constants.EXTRA_SESSION_ID, sessionId)
- putParcelable(Intent.EXTRA_USER, userHandle)
- putString(EXTRA_SOURCE, source)
- }
+ arguments =
+ Bundle().apply {
+ putLong(Constants.EXTRA_SESSION_ID, sessionId)
+ putParcelable(Intent.EXTRA_USER, userHandle)
+ putString(EXTRA_SOURCE, source)
+ }
}
}
}
@@ -95,21 +94,23 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
}
user = requireArguments().getParcelable<UserHandle>(Intent.EXTRA_USER)!!
sessionId = requireArguments().getLong(Constants.EXTRA_SESSION_ID)
- if (requireArguments().containsKey(EXTRA_SOURCE) &&
- (requireArguments().getString(EXTRA_SOURCE) == EXTRA_SOURCE_NOTIFICATION)) {
+ if (
+ requireArguments().containsKey(EXTRA_SOURCE) &&
+ (requireArguments().getString(EXTRA_SOURCE) == EXTRA_SOURCE_NOTIFICATION)
+ ) {
logDecisionReminderNotificationClicked()
}
- val factory = ReviewPermissionDecisionsViewModelFactory(
- requireActivity().getApplication()!!, user)
- viewModel = ViewModelProvider(this,
- factory)[ReviewPermissionDecisionsViewModel::class.java]
+ val factory =
+ ReviewPermissionDecisionsViewModelFactory(requireActivity().getApplication()!!, user)
+ viewModel = ViewModelProvider(this, factory)[ReviewPermissionDecisionsViewModel::class.java]
addPrivacyDashboardPreference()
addPermissionManagerPreference()
preferenceScreen.addPreference(AutoDividerPreference(context))
- recentPermissionsGroup = PreferenceCategory(context!!).apply {
- title = getString(R.string.review_permission_decisions)
- }
+ recentPermissionsGroup =
+ PreferenceCategory(context!!).apply {
+ title = getString(R.string.review_permission_decisions)
+ }
preferenceScreen.addPreference(recentPermissionsGroup)
viewModel.recentPermissionDecisionsLiveData.observe(this) { recentDecisions ->
@@ -138,34 +139,43 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
}
private fun addPrivacyDashboardPreference() {
- val preference = CarUiPreference(context).apply {
- title = getString(R.string.permission_usage_title)
- summary = getString(R.string.auto_permission_usage_summary)
- onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
- val intent = Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
- putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- }
- startActivity(intent)
- true
+ val preference =
+ CarUiPreference(context).apply {
+ title = getString(R.string.permission_usage_title)
+ summary = getString(R.string.auto_permission_usage_summary)
+ onPreferenceClickListener =
+ Preference.OnPreferenceClickListener { _ ->
+ val intent =
+ Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ }
+ startActivity(intent)
+ true
+ }
}
- }
preferenceScreen.addPreference(preference)
}
private fun addPermissionManagerPreference() {
- val preference = CarUiPreference(context).apply {
- title = getString(R.string.app_permission_manager)
- summary = getString(R.string.auto_permission_manager_summary)
- onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
- val intent = Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
- putExtra(Intent.EXTRA_USER, user)
- putExtra(ManagePermissionsActivity.EXTRA_CALLER_NAME, javaClass.name)
- putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- }
- startActivity(intent)
- true
+ val preference =
+ CarUiPreference(context).apply {
+ title = getString(R.string.app_permission_manager)
+ summary = getString(R.string.auto_permission_manager_summary)
+ onPreferenceClickListener =
+ Preference.OnPreferenceClickListener { _ ->
+ val intent =
+ Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
+ putExtra(Intent.EXTRA_USER, user)
+ putExtra(
+ ManagePermissionsActivity.EXTRA_CALLER_NAME,
+ javaClass.name
+ )
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ }
+ startActivity(intent)
+ true
+ }
}
- }
preferenceScreen.addPreference(preference)
}
@@ -175,46 +185,57 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
) {
for (i in 0 until min(recentDecisions.size, MAX_DECISIONS)) {
val recentDecision = recentDecisions[i]
- val decisionPreference = CarUiPreference(context).apply {
- icon = viewModel.getAppIcon(recentDecision.packageName)
- title = viewModel.createPreferenceTitle(recentDecision)
- summary = viewModel.createSummaryText(recentDecision)
- onPreferenceClickListener = Preference.OnPreferenceClickListener {
- viewModel.createManageAppPermissionIntent(recentDecision).also {
- startActivity(it)
- }
- logPermissionDecisionClicked(recentDecision.packageName,
- recentDecision.permissionGroupName)
- true
+ val decisionPreference =
+ CarUiPreference(context).apply {
+ icon = viewModel.getAppIcon(recentDecision.packageName)
+ title = viewModel.createPreferenceTitle(recentDecision)
+ summary = viewModel.createSummaryText(recentDecision)
+ onPreferenceClickListener =
+ Preference.OnPreferenceClickListener {
+ viewModel.createManageAppPermissionIntent(recentDecision).also {
+ startActivity(it)
+ }
+ logPermissionDecisionClicked(
+ recentDecision.packageName,
+ recentDecision.permissionGroupName
+ )
+ true
+ }
}
- }
preferenceGroup.addPreference(decisionPreference)
}
}
private fun addViewAllPreference(preferenceGroup: PreferenceGroup) {
val viewAllIcon = requireContext().getDrawable(R.drawable.car_ic_apps)
- val preference = CarUiPreference(context).apply {
- icon = Utils.applyTint(context, viewAllIcon, android.R.attr.colorControlNormal)
- title = getString(R.string.review_permission_decisions_view_all)
- onPreferenceClickListener = Preference.OnPreferenceClickListener {
- val frag = AutoReviewPermissionDecisionsViewAllFragment.newInstance(sessionId,
- user)
- getParentFragmentManager().beginTransaction()
- .replace(android.R.id.content, frag)
- .addToBackStack(null)
- .commit()
- logViewAllClicked()
- true
+ val preference =
+ CarUiPreference(context).apply {
+ icon = Utils.applyTint(context, viewAllIcon, android.R.attr.colorControlNormal)
+ title = getString(R.string.review_permission_decisions_view_all)
+ onPreferenceClickListener =
+ Preference.OnPreferenceClickListener {
+ val frag =
+ AutoReviewPermissionDecisionsViewAllFragment.newInstance(
+ sessionId,
+ user
+ )
+ getParentFragmentManager()
+ .beginTransaction()
+ .replace(android.R.id.content, frag)
+ .addToBackStack(null)
+ .commit()
+ logViewAllClicked()
+ true
+ }
}
- }
preferenceGroup.addPreference(preference)
}
private fun addNoRecentDecisionsPreference(preferenceGroup: PreferenceGroup) {
- val preference = CarUiPreference(context).apply {
- title = getString(R.string.review_permission_decisions_empty)
- }
+ val preference =
+ CarUiPreference(context).apply {
+ title = getString(R.string.review_permission_decisions_empty)
+ }
preferenceGroup.addPreference(preference)
}
@@ -224,7 +245,8 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
sessionId,
RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__SCREEN_VIEWED,
0,
- null)
+ null
+ )
}
private fun logViewAllClicked() {
@@ -233,7 +255,8 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
sessionId,
RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__VIEW_ALL_CLICKED,
0,
- null)
+ null
+ )
}
private fun logPermissionDecisionClicked(packageName: String, permissionGroupName: String) {
@@ -243,12 +266,15 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
sessionId,
RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__REVIEW_DECISION,
uid,
- permissionGroupName)
+ permissionGroupName
+ )
}
private fun logDecisionReminderNotificationClicked() {
PermissionControllerStatsLog.write(
PermissionControllerStatsLog.PERMISSION_REMINDER_NOTIFICATION_INTERACTED,
- sessionId, PERMISSION_REMINDER_NOTIFICATION_INTERACTED__RESULT__NOTIFICATION_CLICKED)
+ sessionId,
+ PERMISSION_REMINDER_NOTIFICATION_INTERACTED__RESULT__NOTIFICATION_CLICKED
+ )
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsViewAllFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsViewAllFragment.kt
index 9f9471fdf..11cca4693 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsViewAllFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsViewAllFragment.kt
@@ -39,18 +39,17 @@ class AutoReviewPermissionDecisionsViewAllFragment : AutoSettingsFrameFragment()
companion object {
private const val LOG_TAG = "AutoReviewPermissionDecisionsViewAllFragment"
- /**
- * Creates a new instance of [AutoReviewPermissionDecisionsViewAllFragment].
- */
+ /** Creates a new instance of [AutoReviewPermissionDecisionsViewAllFragment]. */
fun newInstance(
sessionId: Long,
userHandle: UserHandle
): AutoReviewPermissionDecisionsViewAllFragment {
return AutoReviewPermissionDecisionsViewAllFragment().apply {
- arguments = Bundle().apply {
- putLong(Constants.EXTRA_SESSION_ID, sessionId)
- putParcelable(Intent.EXTRA_USER, userHandle)
- }
+ arguments =
+ Bundle().apply {
+ putLong(Constants.EXTRA_SESSION_ID, sessionId)
+ putParcelable(Intent.EXTRA_USER, userHandle)
+ }
}
}
}
@@ -71,10 +70,9 @@ class AutoReviewPermissionDecisionsViewAllFragment : AutoSettingsFrameFragment()
return
}
user = requireArguments().getParcelable<UserHandle>(Intent.EXTRA_USER)!!
- val factory = ReviewPermissionDecisionsViewModelFactory(
- requireActivity().getApplication()!!, user)
- viewModel = ViewModelProvider(this,
- factory)[ReviewPermissionDecisionsViewModel::class.java]
+ val factory =
+ ReviewPermissionDecisionsViewModelFactory(requireActivity().getApplication()!!, user)
+ viewModel = ViewModelProvider(this, factory)[ReviewPermissionDecisionsViewModel::class.java]
viewModel.recentPermissionDecisionsLiveData.observe(this) { recentDecisions ->
onRecentDecisionsChanged(recentDecisions)
}
@@ -88,17 +86,19 @@ class AutoReviewPermissionDecisionsViewAllFragment : AutoSettingsFrameFragment()
private fun onRecentDecisionsChanged(recentDecisions: List<PermissionDecision>) {
preferenceScreen.removeAll()
for (recentDecision in recentDecisions) {
- val decisionPreference = CarUiPreference(context).apply {
- icon = viewModel.getAppIcon(recentDecision.packageName)
- title = viewModel.createPreferenceTitle(recentDecision)
- summary = viewModel.createSummaryText(recentDecision)
- onPreferenceClickListener = Preference.OnPreferenceClickListener {
- viewModel.createManageAppPermissionIntent(recentDecision).also {
- startActivity(it)
- }
- false
+ val decisionPreference =
+ CarUiPreference(context).apply {
+ icon = viewModel.getAppIcon(recentDecision.packageName)
+ title = viewModel.createPreferenceTitle(recentDecision)
+ summary = viewModel.createSummaryText(recentDecision)
+ onPreferenceClickListener =
+ Preference.OnPreferenceClickListener {
+ viewModel.createManageAppPermissionIntent(recentDecision).also {
+ startActivity(it)
+ }
+ false
+ }
}
- }
preferenceScreen.addPreference(decisionPreference)
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt
index 61f77c81a..d798291e0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt
@@ -30,16 +30,14 @@ import com.android.permissioncontroller.hibernation.isHibernationEnabled
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment.Companion.INFO_MSG_CATEGORY
-/**
- * Auto wrapper, with customizations, around [UnusedAppsFragment].
- */
-class AutoUnusedAppsFragment : AutoSettingsFrameFragment(),
- UnusedAppsFragment.Parent<AutoUnusedAppsPreference> {
+/** Auto wrapper, with customizations, around [UnusedAppsFragment]. */
+class AutoUnusedAppsFragment :
+ AutoSettingsFrameFragment(), UnusedAppsFragment.Parent<AutoUnusedAppsPreference> {
companion object {
private const val UNUSED_PREFERENCE_KEY = "unused_pref_row_key"
- /** Create a new instance of this fragment. */
+ /** Create a new instance of this fragment. */
@JvmStatic
fun newInstance(): AutoUnusedAppsFragment {
return AutoUnusedAppsFragment()
@@ -53,15 +51,12 @@ class AutoUnusedAppsFragment : AutoSettingsFrameFragment(),
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null) {
- val fragment:
- UnusedAppsFragment<AutoUnusedAppsFragment, AutoUnusedAppsPreference> =
+ val fragment: UnusedAppsFragment<AutoUnusedAppsFragment, AutoUnusedAppsPreference> =
UnusedAppsFragment.newInstance()
fragment.arguments = arguments
// child fragment does not have its own UI - it will add to the preferences of this
// parent fragment
- childFragmentManager.beginTransaction()
- .add(fragment, null)
- .commit()
+ childFragmentManager.beginTransaction().add(fragment, null).commit()
}
// initially focus on focus parking view and then shift focus to recyclerview once it has
@@ -76,10 +71,12 @@ class AutoUnusedAppsFragment : AutoSettingsFrameFragment(),
if (isHibernationEnabled()) {
preference.summary = getString(R.string.unused_apps_page_summary)
} else {
- preference.summary = """
+ preference.summary =
+ """
${getString(R.string.auto_revoked_apps_page_summary)}
${getString(R.string.auto_revoke_open_app_message)}
- """.trimIndent()
+ """
+ .trimIndent()
}
preference.setIcon(R.drawable.ic_info_outline)
preference.isSelectable = false
@@ -104,9 +101,9 @@ class AutoUnusedAppsFragment : AutoSettingsFrameFragment(),
override fun setEmptyState(empty: Boolean) {
val infoMsgCategory =
- preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
+ preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
val noUnusedAppsPreference: Preference? =
- infoMsgCategory.findPreference<Preference>(UNUSED_PREFERENCE_KEY)
+ infoMsgCategory.findPreference<Preference>(UNUSED_PREFERENCE_KEY)
if (empty && noUnusedAppsPreference == null) {
infoMsgCategory.addPreference(createNoUnusedAppsPreference())
} else if (noUnusedAppsPreference != null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsPreference.kt
index 9835a90f4..f1b65b38f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsPreference.kt
@@ -52,4 +52,4 @@ class AutoUnusedAppsPreference(
override fun setRemoveComponentEnabled(enabled: Boolean) {
setSecondaryActionEnabled(enabled)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java
index 6b09921cb..5a93a8e76 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java
@@ -102,7 +102,7 @@ public class GrantPermissionsAutoViewHandler implements GrantPermissionsViewHand
mGroupIcon = icon;
mGroupMessage = message;
mDetailMessage = detailMessage;
- mButtonVisibilities = buttonVisibilities;
+ setButtonVisibilities(buttonVisibilities);
update();
}
@@ -193,11 +193,19 @@ public class GrantPermissionsAutoViewHandler implements GrantPermissionsViewHand
mGroupCount = savedInstanceState.getInt(ARG_GROUP_COUNT);
mGroupIndex = savedInstanceState.getInt(ARG_GROUP_INDEX);
mDetailMessage = savedInstanceState.getCharSequence(ARG_GROUP_DETAIL_MESSAGE);
- mButtonVisibilities = savedInstanceState.getBooleanArray(ARG_BUTTON_VISIBILITIES);
+ setButtonVisibilities(savedInstanceState.getBooleanArray(ARG_BUTTON_VISIBILITIES));
update();
}
+ private void setButtonVisibilities(boolean[] visibilities) {
+ // If GrantPermissionsActivity sent the user directly to settings, button visibilities are
+ // not created. If the activity was then destroyed by the system, once the activity is
+ // recreated to perform onActivityResult, it will try to loadInstanceState in onCreate but
+ // the button visibilities were never set, so they will be null.
+ mButtonVisibilities = visibilities == null ? new boolean[0] : visibilities;
+ }
+
@Override
public void onBackPressed() {
if (mDialog != null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt
index 7ea400127..08460178c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt
@@ -23,8 +23,8 @@ import androidx.annotation.RequiresApi
import androidx.preference.Preference.OnPreferenceClickListener
import com.android.car.ui.preference.CarUiPreference
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelLegacy
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
/** Preference that displays a permission usage for an app. */
@RequiresApi(Build.VERSION_CODES.S)
@@ -40,7 +40,8 @@ class AutoPermissionHistoryPreference(
context.getString(
R.string.auto_permission_usage_timeline_summary,
DateFormat.getTimeFormat(context).format(historyPreferenceData.accessEndTime),
- historyPreferenceData.summaryText)
+ historyPreferenceData.summaryText
+ )
} else {
DateFormat.getTimeFormat(context).format(historyPreferenceData.accessEndTime)
}
@@ -60,7 +61,9 @@ class AutoPermissionHistoryPreference(
accessEndTime = historyPreferenceData.accessEndTime,
accessStartTime = historyPreferenceData.accessStartTime,
showingAttribution = historyPreferenceData.showingAttribution,
- attributionTags = historyPreferenceData.attributionTags))
+ attributionTags = historyPreferenceData.attributionTags
+ )
+ )
true
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt
index d4a2a073e..c11129514 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt
@@ -38,11 +38,11 @@ import com.android.permissioncontroller.permission.model.livedatatypes.PermGroup
import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
import com.android.permissioncontroller.permission.model.v31.PermissionUsages
import com.android.permissioncontroller.permission.model.v31.PermissionUsages.PermissionsUsagesChangeCallback
-import com.android.permissioncontroller.permission.ui.model.ManagePermissionsViewModel
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageControlPreferenceUtils
import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageViewModelFactoryLegacy
import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageViewModelLegacy
import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageViewModelLegacy.PermissionGroupWithUsageCount
+import com.android.permissioncontroller.permission.ui.model.ManagePermissionsViewModel
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageControlPreferenceUtils
import com.android.permissioncontroller.permission.utils.Utils
@RequiresApi(Build.VERSION_CODES.S)
@@ -95,7 +95,9 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
PermissionUsageViewModelLegacy::class.java]
managePermissionsViewModel.standardPermGroupsLiveData.observe(
- this, this::onPermissionGroupsChanged)
+ this,
+ this::onPermissionGroupsChanged
+ )
setLoading(true)
reloadData()
}
@@ -119,7 +121,8 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
PermissionControllerStatsLog.write(
PERMISSION_USAGE_FRAGMENT_INTERACTION,
sessionId,
- PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED)
+ PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED
+ )
}
showSystem = !showSystem
updateAction()
@@ -143,7 +146,10 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
/** Reloads the data to show. */
private fun reloadData() {
usageViewModel.loadPermissionUsages(
- requireActivity().getLoaderManager(), permissionUsages, this)
+ requireActivity().getLoaderManager(),
+ permissionUsages,
+ this
+ )
if (finishedInitialLoad) {
setLoading(false)
}
@@ -165,7 +171,11 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
val permissionUsagesUiData =
usageViewModel.buildPermissionUsagesUiData(
- appPermissionUsages, show7Days, showSystem, requireContext())
+ appPermissionUsages,
+ show7Days,
+ showSystem,
+ requireContext()
+ )
val permissionApps = permissionUsagesUiData.permissionApps
val displayShowSystemToggle = permissionUsagesUiData.displayShowSystemToggle
@@ -213,7 +223,8 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
count,
showSystem,
sessionId,
- show7Days)
+ show7Days
+ )
getPreferenceScreen().addPreference(permissionUsagePreference)
}
finishedInitialLoad = true
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java
index cab0de15e..7fa51dd8a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java
@@ -103,6 +103,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
implements AppPermissionViewModel.ConfirmDialogShowingFragment {
private static final String LOG_TAG = "AppPermissionFragment";
private static final long POST_DELAY_MS = 20;
+ private static final long EDIT_PHOTOS_BUTTON_ANIMATION_LENGTH_MS = 200L;
static final String GRANT_CATEGORY = "grant_category";
@@ -117,6 +118,9 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
private @NonNull RadioButton mSelectPhotosButton;
private @NonNull RadioButton mDenyButton;
private @NonNull RadioButton mDenyForegroundButton;
+ private @NonNull ImageView mEditPhotosButton;
+ private @NonNull View mSelectPhotosLayout;
+ private @NonNull View mEditPhotosDivider;
private @NonNull View mLocationAccuracy;
private @NonNull Switch mLocationAccuracySwitch;
private @NonNull View mDivider;
@@ -128,6 +132,8 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
private @NonNull UserHandle mUser;
private boolean mIsStorageGroup;
private boolean mIsInitialLoad;
+ // This prevents the user from clicking the photo picker button multiple times in succession
+ private boolean mPhotoPickerTriggered;
private long mSessionId;
private @NonNull String mPackageLabel;
@@ -209,7 +215,6 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
if (mIsStorageGroup) {
mViewModel.getFullStorageStateLiveData().observe(this, this::setSpecialStorageState);
}
- mViewModel.registerPhotoPickerResultIfNeeded(this);
mRoleManager = Utils.getSystemServiceSafe(getContext(), RoleManager.class);
}
@@ -261,12 +266,15 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
mSelectPhotosButton = root.requireViewById(R.id.select_radio_button);
mDenyButton = root.requireViewById(R.id.deny_radio_button);
mDenyForegroundButton = root.requireViewById(R.id.deny_foreground_radio_button);
+
mDivider = root.requireViewById(R.id.two_target_divider);
mWidgetFrame = root.requireViewById(R.id.widget_frame);
mPermissionDetails = root.requireViewById(R.id.permission_details);
mLocationAccuracy = root.requireViewById(R.id.location_accuracy);
mLocationAccuracySwitch = root.requireViewById(R.id.location_accuracy_switch);
-
+ mSelectPhotosLayout = root.requireViewById(R.id.radio_select_layout);
+ mEditPhotosButton = root.requireViewById(R.id.edit_selected_button);
+ mEditPhotosDivider = root.requireViewById(R.id.edit_photos_divider);
mNestedScrollView = root.requireViewById(R.id.nested_scroll_view);
if (mViewModel.getButtonStateLiveData().getValue() != null) {
@@ -280,6 +288,9 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
mDenyButton.setVisibility(View.GONE);
mDenyForegroundButton.setVisibility(View.GONE);
mLocationAccuracy.setVisibility(View.GONE);
+ mSelectPhotosLayout.setVisibility(View.GONE);
+ mEditPhotosDivider.setAlpha(0f);
+ mEditPhotosButton.setAlpha(0f);
}
if (mViewModel.getFullStorageStateLiveData().isInitialized() && mIsStorageGroup) {
@@ -302,6 +313,12 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
return root;
}
+ public void onResume() {
+ super.onResume();
+ // If we're returning to the fragment, photo picker hasn't been triggered
+ mPhotoPickerTriggered = false;
+ }
+
private void showPermissionRationaleDialog(boolean showPermissionRationale) {
if (!showPermissionRationale) {
mAppPermissionRationaleContainer.setVisibility(View.GONE);
@@ -380,7 +397,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
});
mAllowAlwaysButton.setOnClickListener((v) -> {
if (mIsStorageGroup) {
- showConfirmDialog(ChangeRequest.GRANT_All_FILE_ACCESS,
+ showConfirmDialog(ChangeRequest.GRANT_ALL_FILE_ACCESS,
R.string.special_file_access_dialog, -1, false);
} else {
mViewModel.requestChange(false, this, this, ChangeRequest.GRANT_BOTH,
@@ -412,6 +429,13 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
mViewModel.requestChange(false, this, this, ChangeRequest.PHOTOS_SELECTED,
buttonPressed);
});
+ mEditPhotosButton.setOnClickListener((v) -> {
+ ButtonState selectState = states.get(ButtonType.SELECT_PHOTOS);
+ if (selectState != null && selectState.isChecked() && !mPhotoPickerTriggered) {
+ mPhotoPickerTriggered = true;
+ mViewModel.openPhotoPicker(this);
+ }
+ });
mDenyButton.setOnClickListener((v) -> {
if (mViewModel.getFullStorageStateLiveData().getValue() != null
&& !mViewModel.getFullStorageStateLiveData().getValue().isLegacy()) {
@@ -485,6 +509,21 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
if (mIsInitialLoad) {
button.jumpDrawablesToCurrentState();
}
+
+ if (button == mSelectPhotosButton) {
+ mSelectPhotosLayout.setVisibility(visible);
+ float endOpacity = state.isChecked() ? 1f : 0f;
+ // On initial load, do not show the fade in/out animation
+ if (mIsInitialLoad) {
+ mEditPhotosDivider.setAlpha(endOpacity);
+ mEditPhotosButton.setAlpha(endOpacity);
+ return;
+ }
+ mEditPhotosButton.animate().alpha(endOpacity)
+ .setDuration(EDIT_PHOTOS_BUTTON_ANIMATION_LENGTH_MS);
+ mEditPhotosDivider.animate().alpha(endOpacity)
+ .setDuration(EDIT_PHOTOS_BUTTON_ANIMATION_LENGTH_MS);
+ }
}
private void setSpecialStorageState(FullStoragePackageState storageState, View v) {
@@ -630,7 +669,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
// NFF sharing
AppPermissionFragment fragment = (AppPermissionFragment) getParentFragment();
boolean isGrantFileAccess = getArguments().getSerializable(CHANGE_REQUEST)
- == ChangeRequest.GRANT_All_FILE_ACCESS;
+ == ChangeRequest.GRANT_ALL_FILE_ACCESS;
int positiveButtonStringResId = R.string.grant_dialog_button_deny_anyway;
if (isGrantFileAccess) {
positiveButtonStringResId = R.string.grant_dialog_button_allow;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
index a8b79bfde..84d019bad 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
@@ -23,6 +23,7 @@ import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__DENIED;
import static com.android.permissioncontroller.hibernation.HibernationPolicyKt.isHibernationEnabled;
+import static com.android.permissioncontroller.permission.ui.Category.STORAGE_FOOTER;
import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
import static java.util.concurrent.TimeUnit.DAYS;
@@ -63,6 +64,7 @@ import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
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.model.livedatatypes.HibernationSettingState;
@@ -318,6 +320,9 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
findPreference(Category.ALLOWED_FOREGROUND.getCategoryName()).setVisible(false);
+ // Hide storage footer category
+ findPreference(STORAGE_FOOTER.getCategoryName()).setVisible(false);
+
long sessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
for (Category grantCategory : groupMap.keySet()) {
@@ -427,8 +432,10 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
int switchTitleId;
if (isHibernationEnabled()) {
if (SdkLevel.isAtLeastT()) {
- switchTitleId = R.string.unused_apps_label_v2;
- autoRevokeSwitch.setSummary(R.string.unused_apps_summary);
+ switchTitleId = isArchivingEnabled() ? R.string.unused_apps_label_v3
+ : R.string.unused_apps_label_v2;
+ autoRevokeSwitch.setSummary(isArchivingEnabled() ? R.string.unused_apps_summary_v2
+ : R.string.unused_apps_summary);
} else {
switchTitleId = R.string.unused_apps_label;
}
@@ -452,6 +459,10 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
autoRevokeCategory.addPreference(autoRevokeSummary);
}
+ private boolean isArchivingEnabled() {
+ return SdkLevel.isAtLeastV() && Flags.archiving();
+ }
+
private void setAutoRevokeToggleState(HibernationSettingState state) {
if (state == null || !mViewModel.getPackagePermGroupsLiveData().isInitialized()
|| getPreferenceScreen() == null || getListView() == null || getView() == null) {
@@ -580,7 +591,7 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
}
PermissionControllerStatsLog.write(APP_PERMISSIONS_FRAGMENT_VIEWED, sessionId, viewId,
permissionGroupName, uid, mPackageName, category);
- Log.v(LOG_TAG, "AppPermissionFragment view logged with sessionId=" + sessionId + " viewId="
+ Log.i(LOG_TAG, "AppPermissionFragment view logged with sessionId=" + sessionId + " viewId="
+ viewId + " permissionGroupName=" + permissionGroupName + " uid="
+ uid + " packageName="
+ mPackageName + " category=" + category);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/FooterPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/FooterPreference.kt
index 7864abbb2..278243f09 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/FooterPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/FooterPreference.kt
@@ -28,10 +28,10 @@ import com.android.permissioncontroller.R
* placement.
*/
class FooterPreference : Preference {
- constructor(c: Context): super(c)
- constructor(c: Context, a: AttributeSet): super(c, a)
- constructor(c: Context, a: AttributeSet, attr: Int): super(c, a, attr)
- constructor(c: Context, a: AttributeSet, attr: Int, res: Int): super(c, a, attr, res)
+ constructor(c: Context) : super(c)
+ constructor(c: Context, a: AttributeSet) : super(c, a)
+ constructor(c: Context, a: AttributeSet, attr: Int) : super(c, a, attr)
+ constructor(c: Context, a: AttributeSet, attr: Int, res: Int) : super(c, a, attr, res)
init {
layoutResource = R.layout.footer_preference
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.kt
index decbfe590..bb698b49a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.kt
@@ -83,10 +83,14 @@ class GrantPermissionsViewHandlerImpl(
private val resultListener: ResultListener
) : GrantPermissionsViewHandler, OnClickListener {
- private val LOCATION_ACCURACY_DIALOGS = listOf(DIALOG_WITH_BOTH_LOCATIONS,
- DIALOG_WITH_FINE_LOCATION_ONLY, DIALOG_WITH_COARSE_LOCATION_ONLY)
- private val LOCATION_ACCURACY_IMAGE_DIAMETER = mActivity.resources.getDimension(
- R.dimen.location_accuracy_image_size)
+ private val LOCATION_ACCURACY_DIALOGS =
+ listOf(
+ DIALOG_WITH_BOTH_LOCATIONS,
+ DIALOG_WITH_FINE_LOCATION_ONLY,
+ DIALOG_WITH_COARSE_LOCATION_ONLY
+ )
+ private val LOCATION_ACCURACY_IMAGE_DIAMETER =
+ mActivity.resources.getDimension(R.dimen.location_accuracy_image_size)
// Configuration of the current dialog
private var groupName: String? = null
@@ -124,8 +128,10 @@ class GrantPermissionsViewHandlerImpl(
arguments.putParcelable(ARG_GROUP_ICON, groupIcon)
arguments.putCharSequence(ARG_GROUP_MESSAGE, groupMessage)
arguments.putCharSequence(ARG_GROUP_DETAIL_MESSAGE, detailMessage)
- arguments.putCharSequence(ARG_GROUP_PERMISSION_RATIONALE_MESSAGE,
- permissionRationaleMessage)
+ arguments.putCharSequence(
+ ARG_GROUP_PERMISSION_RATIONALE_MESSAGE,
+ permissionRationaleMessage
+ )
arguments.putBooleanArray(ARG_DIALOG_BUTTON_VISIBILITIES, buttonVisibilities)
arguments.putBooleanArray(ARG_DIALOG_LOCATION_VISIBILITIES, locationVisibilities)
arguments.putInt(ARG_DIALOG_SELECTED_PRECISION, selectedPrecision)
@@ -141,8 +147,9 @@ class GrantPermissionsViewHandlerImpl(
permissionRationaleMessage =
savedInstanceState.getCharSequence(ARG_GROUP_PERMISSION_RATIONALE_MESSAGE)
setButtonVisibilities(savedInstanceState.getBooleanArray(ARG_DIALOG_BUTTON_VISIBILITIES))
- setLocationVisibilities(savedInstanceState.getBooleanArray(
- ARG_DIALOG_LOCATION_VISIBILITIES))
+ setLocationVisibilities(
+ savedInstanceState.getBooleanArray(ARG_DIALOG_LOCATION_VISIBILITIES)
+ )
selectedPrecision = savedInstanceState.getInt(ARG_DIALOG_SELECTED_PRECISION)
updateAll()
@@ -159,7 +166,6 @@ class GrantPermissionsViewHandlerImpl(
buttonVisibilities: BooleanArray?,
locationVisibilities: BooleanArray?
) {
-
this.groupName = groupName
this.groupCount = groupCount
this.groupIndex = groupIndex
@@ -187,21 +193,22 @@ class GrantPermissionsViewHandlerImpl(
// Grow or shrink the content container to size of new content
val growShrinkToNewContentSize = ChangeBounds()
growShrinkToNewContentSize.duration = ANIMATION_DURATION_MILLIS
- growShrinkToNewContentSize.interpolator = AnimationUtils.loadInterpolator(mActivity,
- android.R.interpolator.fast_out_slow_in)
+ growShrinkToNewContentSize.interpolator =
+ AnimationUtils.loadInterpolator(mActivity, android.R.interpolator.fast_out_slow_in)
TransitionManager.beginDelayedTransition(rootView, growShrinkToNewContentSize)
}
override fun createView(): View {
- val useMaterial3PermissionGrantDialog = mActivity.resources
- .getBoolean(R.bool.config_useMaterial3PermissionGrantDialog)
- val rootView = if (useMaterial3PermissionGrantDialog || SdkLevel.isAtLeastT()) {
- LayoutInflater.from(mActivity)
- .inflate(R.layout.grant_permissions_material3, null) as ViewGroup
- } else {
- LayoutInflater.from(mActivity)
- .inflate(R.layout.grant_permissions, null) as ViewGroup
- }
+ val useMaterial3PermissionGrantDialog =
+ mActivity.resources.getBoolean(R.bool.config_useMaterial3PermissionGrantDialog)
+ val rootView =
+ if (useMaterial3PermissionGrantDialog || SdkLevel.isAtLeastT()) {
+ LayoutInflater.from(mActivity).inflate(R.layout.grant_permissions_material3, null)
+ as ViewGroup
+ } else {
+ LayoutInflater.from(mActivity).inflate(R.layout.grant_permissions, null)
+ as ViewGroup
+ }
this.rootView = rootView
// Uses the vertical gravity of the PermissionGrantSingleton style to position the window
@@ -257,14 +264,15 @@ class GrantPermissionsViewHandlerImpl(
private fun getLottieDrawable(@RawRes rawResId: Int): LottieDrawable {
val composition = LottieCompositionFactory.fromRawResSync(mActivity, rawResId).value!!
val scale = LOCATION_ACCURACY_IMAGE_DIAMETER / composition.bounds.width()
- val drawable = object : LottieDrawable() {
- override fun getIntrinsicHeight(): Int {
- return (super.getIntrinsicHeight() * scale).toInt()
- }
- override fun getIntrinsicWidth(): Int {
- return (super.getIntrinsicWidth() * scale).toInt()
+ val drawable =
+ object : LottieDrawable() {
+ override fun getIntrinsicHeight(): Int {
+ return (super.getIntrinsicHeight() * scale).toInt()
+ }
+ override fun getIntrinsicWidth(): Int {
+ return (super.getIntrinsicWidth() * scale).toInt()
+ }
}
- }
drawable.composition = composition
return drawable
}
@@ -282,21 +290,23 @@ class GrantPermissionsViewHandlerImpl(
private fun setButtonVisibilities(visibilities: BooleanArray?) {
for (i in buttonVisibilities.indices) {
- buttonVisibilities[i] = if (visibilities != null && i < visibilities.size) {
- visibilities[i]
- } else {
- false
- }
+ buttonVisibilities[i] =
+ if (visibilities != null && i < visibilities.size) {
+ visibilities[i]
+ } else {
+ false
+ }
}
}
private fun setLocationVisibilities(visibilities: BooleanArray?) {
for (i in locationVisibilities.indices) {
- locationVisibilities[i] = if (visibilities != null && i < visibilities.size) {
- visibilities[i]
- } else {
- false
- }
+ locationVisibilities[i] =
+ if (visibilities != null && i < visibilities.size) {
+ visibilities[i]
+ } else {
+ false
+ }
}
}
@@ -329,29 +339,38 @@ class GrantPermissionsViewHandlerImpl(
private fun updateButtons() {
for (i in 0 until BUTTON_RES_ID_TO_NUM.size()) {
val pos = BUTTON_RES_ID_TO_NUM.valueAt(i)
- buttons[pos]?.visibility = if (buttonVisibilities[pos]) {
- View.VISIBLE
- } else {
- View.GONE
- }
+ buttons[pos]?.visibility =
+ if (buttonVisibilities[pos]) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
if (pos == ALLOW_FOREGROUND_BUTTON && buttonVisibilities[pos]) {
- if (locationVisibilities[LOCATION_ACCURACY_LAYOUT] &&
- locationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]) {
- buttons[pos]?.text = mActivity.resources.getString(
- R.string.grant_dialog_button_change_to_precise_location)
+ if (
+ locationVisibilities[LOCATION_ACCURACY_LAYOUT] &&
+ locationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]
+ ) {
+ buttons[pos]?.text =
+ mActivity.resources.getString(
+ R.string.grant_dialog_button_change_to_precise_location
+ )
} else {
- buttons[pos]?.text = mActivity.resources.getString(
- R.string.grant_dialog_button_allow_foreground)
+ buttons[pos]?.text =
+ mActivity.resources.getString(R.string.grant_dialog_button_allow_foreground)
}
}
if ((pos == DENY_BUTTON || pos == DENY_AND_DONT_ASK_AGAIN_BUTTON)) {
- if (locationVisibilities[LOCATION_ACCURACY_LAYOUT] &&
- locationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]) {
- buttons[pos]?.text = mActivity.resources.getString(
- R.string.grant_dialog_button_keey_approximate_location)
+ if (
+ locationVisibilities[LOCATION_ACCURACY_LAYOUT] &&
+ locationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]
+ ) {
+ buttons[pos]?.text =
+ mActivity.resources.getString(
+ R.string.grant_dialog_button_keey_approximate_location
+ )
} else {
- buttons[pos]?.text = mActivity.resources.getString(
- R.string.grant_dialog_button_deny)
+ buttons[pos]?.text =
+ mActivity.resources.getString(R.string.grant_dialog_button_deny)
}
}
buttons[pos]?.requestLayout()
@@ -365,11 +384,12 @@ class GrantPermissionsViewHandlerImpl(
}
locationViews[LOCATION_ACCURACY_LAYOUT]?.visibility = View.VISIBLE
for (i in LOCATION_ACCURACY_DIALOGS) {
- locationViews[i]?.visibility = if (locationVisibilities[i]) {
- View.VISIBLE
- } else {
- View.GONE
- }
+ locationViews[i]?.visibility =
+ if (locationVisibilities[i]) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
}
if (locationVisibilities[DIALOG_WITH_BOTH_LOCATIONS]) {
coarseRadioButton?.visibility = View.VISIBLE
@@ -388,11 +408,13 @@ class GrantPermissionsViewHandlerImpl(
}
} else if (locationVisibilities[DIALOG_WITH_COARSE_LOCATION_ONLY]) {
(locationViews[DIALOG_WITH_COARSE_LOCATION_ONLY] as ImageView).setImageDrawable(
- coarseOnDrawable)
+ coarseOnDrawable
+ )
coarseOnDrawable?.start()
} else if (locationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]) {
(locationViews[DIALOG_WITH_FINE_LOCATION_ONLY] as ImageView).setImageDrawable(
- fineOnDrawable)
+ fineOnDrawable
+ )
fineOnDrawable?.start()
}
} else {
@@ -408,10 +430,18 @@ class GrantPermissionsViewHandlerImpl(
if (isFineSelected) {
coarseOnDrawable?.stop()
fineOffDrawable?.stop()
- coarseRadioButton?.setCompoundDrawablesWithIntrinsicBounds(null, coarseOffDrawable,
- null, null)
- fineRadioButton?.setCompoundDrawablesWithIntrinsicBounds(null, fineOnDrawable,
- null, null)
+ coarseRadioButton?.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ coarseOffDrawable,
+ null,
+ null
+ )
+ fineRadioButton?.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ fineOnDrawable,
+ null,
+ null
+ )
coarseOffDrawable?.start()
fineOnDrawable?.start()
fineRadioButton?.setTypeface(null, Typeface.BOLD)
@@ -419,10 +449,18 @@ class GrantPermissionsViewHandlerImpl(
} else {
coarseOffDrawable?.stop()
fineOnDrawable?.stop()
- coarseRadioButton?.setCompoundDrawablesWithIntrinsicBounds(null, coarseOnDrawable,
- null, null)
- fineRadioButton?.setCompoundDrawablesWithIntrinsicBounds(null, fineOffDrawable,
- null, null)
+ coarseRadioButton?.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ coarseOnDrawable,
+ null,
+ null
+ )
+ fineRadioButton?.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ fineOffDrawable,
+ null,
+ null
+ )
fineOffDrawable?.start()
coarseOnDrawable?.start()
coarseRadioButton?.setTypeface(null, Typeface.BOLD)
@@ -471,8 +509,8 @@ class GrantPermissionsViewHandlerImpl(
R.id.permission_location_accuracy_radio_coarse ->
affectedForegroundPermissions = listOf(ACCESS_COARSE_LOCATION)
R.id.permission_location_accuracy_radio_fine ->
- affectedForegroundPermissions = listOf(ACCESS_FINE_LOCATION,
- ACCESS_COARSE_LOCATION)
+ affectedForegroundPermissions =
+ listOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)
}
} else if (locationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]) {
affectedForegroundPermissions = listOf(ACCESS_FINE_LOCATION)
@@ -481,52 +519,94 @@ class GrantPermissionsViewHandlerImpl(
}
when (BUTTON_RES_ID_TO_NUM.get(id, -1)) {
- ALLOW_ALL_BUTTON, ALLOW_BUTTON -> {
+ ALLOW_ALL_BUTTON,
+ ALLOW_BUTTON -> {
view.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
- GRANTED_ALWAYS)
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
+ null
+ )
+ resultListener.onPermissionGrantResult(
+ groupName,
+ affectedForegroundPermissions,
+ GRANTED_ALWAYS
+ )
}
ALLOW_FOREGROUND_BUTTON -> {
view.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
- GRANTED_FOREGROUND_ONLY)
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
+ null
+ )
+ resultListener.onPermissionGrantResult(
+ groupName,
+ affectedForegroundPermissions,
+ GRANTED_FOREGROUND_ONLY
+ )
}
ALLOW_ALWAYS_BUTTON -> {
view.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
- GRANTED_ALWAYS)
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
+ null
+ )
+ resultListener.onPermissionGrantResult(
+ groupName,
+ affectedForegroundPermissions,
+ GRANTED_ALWAYS
+ )
}
ALLOW_ONE_TIME_BUTTON -> {
view.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
- GRANTED_ONE_TIME)
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
+ null
+ )
+ resultListener.onPermissionGrantResult(
+ groupName,
+ affectedForegroundPermissions,
+ GRANTED_ONE_TIME
+ )
}
ALLOW_SELECTED_BUTTON -> {
view.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
- GRANTED_USER_SELECTED)
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
+ null
+ )
+ resultListener.onPermissionGrantResult(
+ groupName,
+ affectedForegroundPermissions,
+ GRANTED_USER_SELECTED
+ )
}
DONT_ALLOW_MORE_SELECTED_BUTTON -> {
- resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
- DENIED_MORE)
+ resultListener.onPermissionGrantResult(
+ groupName,
+ affectedForegroundPermissions,
+ DENIED_MORE
+ )
}
- DENY_BUTTON, NO_UPGRADE_BUTTON, NO_UPGRADE_OT_BUTTON -> {
+ DENY_BUTTON,
+ NO_UPGRADE_BUTTON,
+ NO_UPGRADE_OT_BUTTON -> {
view.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
- DENIED)
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
+ null
+ )
+ resultListener.onPermissionGrantResult(
+ groupName,
+ affectedForegroundPermissions,
+ DENIED
+ )
}
- DENY_AND_DONT_ASK_AGAIN_BUTTON, NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON,
+ DENY_AND_DONT_ASK_AGAIN_BUTTON,
+ NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON,
NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON -> {
view.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
- DENIED_DO_NOT_ASK_AGAIN)
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
+ null
+ )
+ resultListener.onPermissionGrantResult(
+ groupName,
+ affectedForegroundPermissions,
+ DENIED_DO_NOT_ASK_AGAIN
+ )
}
}
}
@@ -567,39 +647,57 @@ class GrantPermissionsViewHandlerImpl(
init {
BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_button, ALLOW_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_foreground_only_button,
- ALLOW_FOREGROUND_BUTTON)
+ BUTTON_RES_ID_TO_NUM.put(
+ R.id.permission_allow_foreground_only_button,
+ ALLOW_FOREGROUND_BUTTON
+ )
BUTTON_RES_ID_TO_NUM.put(R.id.permission_deny_button, DENY_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_deny_and_dont_ask_again_button,
- DENY_AND_DONT_ASK_AGAIN_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_one_time_button,
- ALLOW_ONE_TIME_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_button,
- NO_UPGRADE_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_and_dont_ask_again_button,
- NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_one_time_button,
- NO_UPGRADE_OT_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_one_time_and_dont_ask_again_button,
- NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_all_button,
- ALLOW_ALL_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_selected_button,
- ALLOW_SELECTED_BUTTON)
- BUTTON_RES_ID_TO_NUM.put(R.id.permission_dont_allow_more_selected_button,
- DONT_ALLOW_MORE_SELECTED_BUTTON)
+ BUTTON_RES_ID_TO_NUM.put(
+ R.id.permission_deny_and_dont_ask_again_button,
+ DENY_AND_DONT_ASK_AGAIN_BUTTON
+ )
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_one_time_button, ALLOW_ONE_TIME_BUTTON)
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_button, NO_UPGRADE_BUTTON)
+ BUTTON_RES_ID_TO_NUM.put(
+ R.id.permission_no_upgrade_and_dont_ask_again_button,
+ NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON
+ )
+ BUTTON_RES_ID_TO_NUM.put(
+ R.id.permission_no_upgrade_one_time_button,
+ NO_UPGRADE_OT_BUTTON
+ )
+ BUTTON_RES_ID_TO_NUM.put(
+ R.id.permission_no_upgrade_one_time_and_dont_ask_again_button,
+ NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON
+ )
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_all_button, ALLOW_ALL_BUTTON)
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_selected_button, ALLOW_SELECTED_BUTTON)
+ BUTTON_RES_ID_TO_NUM.put(
+ R.id.permission_dont_allow_more_selected_button,
+ DONT_ALLOW_MORE_SELECTED_BUTTON
+ )
LOCATION_RES_ID_TO_NUM.put(R.id.permission_location_accuracy, LOCATION_ACCURACY_LAYOUT)
- LOCATION_RES_ID_TO_NUM.put(R.id.permission_location_accuracy_radio_fine,
- FINE_RADIO_BUTTON)
- LOCATION_RES_ID_TO_NUM.put(R.id.permission_location_accuracy_radio_coarse,
- COARSE_RADIO_BUTTON)
- LOCATION_RES_ID_TO_NUM.put(R.id.permission_location_accuracy_radio_group,
- DIALOG_WITH_BOTH_LOCATIONS)
- LOCATION_RES_ID_TO_NUM.put(R.id.permission_location_accuracy_fine_only,
- DIALOG_WITH_FINE_LOCATION_ONLY)
- LOCATION_RES_ID_TO_NUM.put(R.id.permission_location_accuracy_coarse_only,
- DIALOG_WITH_COARSE_LOCATION_ONLY)
+ LOCATION_RES_ID_TO_NUM.put(
+ R.id.permission_location_accuracy_radio_fine,
+ FINE_RADIO_BUTTON
+ )
+ LOCATION_RES_ID_TO_NUM.put(
+ R.id.permission_location_accuracy_radio_coarse,
+ COARSE_RADIO_BUTTON
+ )
+ LOCATION_RES_ID_TO_NUM.put(
+ R.id.permission_location_accuracy_radio_group,
+ DIALOG_WITH_BOTH_LOCATIONS
+ )
+ LOCATION_RES_ID_TO_NUM.put(
+ R.id.permission_location_accuracy_fine_only,
+ DIALOG_WITH_FINE_LOCATION_ONLY
+ )
+ LOCATION_RES_ID_TO_NUM.put(
+ R.id.permission_location_accuracy_coarse_only,
+ DIALOG_WITH_COARSE_LOCATION_ONLY
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt
index e2fdfc86e..37ac50bb8 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt
@@ -28,14 +28,12 @@ import com.android.permissioncontroller.hibernation.isHibernationEnabled
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment.Companion.INFO_MSG_CATEGORY
-/**
- * Handheld wrapper, with customizations, around [UnusedAppsFragment].
- */
-class HandheldUnusedAppsFragment : PermissionsFrameFragment(),
- UnusedAppsFragment.Parent<UnusedAppPreference> {
+/** Handheld wrapper, with customizations, around [UnusedAppsFragment]. */
+class HandheldUnusedAppsFragment :
+ PermissionsFrameFragment(), UnusedAppsFragment.Parent<UnusedAppPreference> {
companion object {
- /** Create a new instance of this fragment. */
+ /** Create a new instance of this fragment. */
@JvmStatic
fun newInstance(): HandheldUnusedAppsFragment {
return HandheldUnusedAppsFragment()
@@ -55,15 +53,12 @@ class HandheldUnusedAppsFragment : PermissionsFrameFragment(),
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null) {
- val fragment:
- UnusedAppsFragment<HandheldUnusedAppsFragment, UnusedAppPreference> =
+ val fragment: UnusedAppsFragment<HandheldUnusedAppsFragment, UnusedAppPreference> =
UnusedAppsFragment.newInstance()
fragment.arguments = arguments
// child fragment does not have its own UI - it will add to the preferences of this
// parent fragment
- childFragmentManager.beginTransaction()
- .add(fragment, null)
- .commit()
+ childFragmentManager.beginTransaction().add(fragment, null).commit()
}
}
@@ -113,7 +108,7 @@ class HandheldUnusedAppsFragment : PermissionsFrameFragment(),
override fun setEmptyState(empty: Boolean) {
val infoMsgCategory =
- preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
+ preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
infoMsgCategory.isVisible = !empty
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsWrapperFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsWrapperFragment.kt
index 44a9f3d08..7565e6d17 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsWrapperFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsWrapperFragment.kt
@@ -24,12 +24,10 @@ import android.view.ViewGroup
import com.android.permissioncontroller.R
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseFragment
-/**
- * Wrapper over HandheldUnusedAppsFragment
- */
+/** Wrapper over HandheldUnusedAppsFragment */
class HandheldUnusedAppsWrapperFragment : CollapsingToolbarBaseFragment() {
companion object {
- /** Create a new instance of this fragment. */
+ /** Create a new instance of this fragment. */
@JvmStatic
fun newInstance(): HandheldUnusedAppsWrapperFragment {
return HandheldUnusedAppsWrapperFragment()
@@ -48,15 +46,16 @@ class HandheldUnusedAppsWrapperFragment : CollapsingToolbarBaseFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
- var preferenceFragment = childFragmentManager
- .findFragmentById(R.id.preference_fragment_container)
+ var preferenceFragment =
+ childFragmentManager.findFragmentById(R.id.preference_fragment_container)
as HandheldUnusedAppsFragment?
if (preferenceFragment == null) {
preferenceFragment = HandheldUnusedAppsFragment.newInstance()
preferenceFragment.arguments = arguments
- childFragmentManager.beginTransaction()
- .add(R.id.preference_fragment_container, preferenceFragment)
- .commit()
+ childFragmentManager
+ .beginTransaction()
+ .add(R.id.preference_fragment_container, preferenceFragment)
+ .commit()
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java
index 8e3192eee..86fcf2c27 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java
@@ -22,11 +22,8 @@ import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
import android.app.Application;
-import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
import androidx.lifecycle.ViewModelProvider;
@@ -35,10 +32,8 @@ import androidx.preference.PreferenceScreen;
import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment;
import com.android.permissioncontroller.permission.ui.model.ManageStandardPermissionsViewModel;
-import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.StringUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.settingslib.widget.FooterPreference;
@@ -50,9 +45,6 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
private static final String EXTRA_PREFS_KEY = "extra_prefs_key";
private static final String AUTO_REVOKE_KEY = "auto_revoke_key";
private static final String LOG_TAG = ManageStandardPermissionsFragment.class.getSimpleName();
-
- private static final int MENU_PERMISSION_USAGE = MENU_HIDE_SYSTEM + 1;
-
private ManageStandardPermissionsViewModel mViewModel;
/**
@@ -111,24 +103,11 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
case android.R.id.home:
pressBack(this);
return true;
- case MENU_PERMISSION_USAGE:
- getActivity().startActivity(new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE)
- .setClass(getContext(), ManagePermissionsActivity.class));
- return true;
}
return super.onOptionsItemSelected(item);
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
-
- if (KotlinUtils.INSTANCE.shouldShowPermissionsDashboard()) {
- menu.add(Menu.NONE, MENU_PERMISSION_USAGE, Menu.NONE, R.string.permission_usage_title);
- }
- }
-
- @Override
protected PreferenceScreen updatePermissionsUi() {
PreferenceScreen screen = super.updatePermissionsUi();
if (screen == null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
index 220507426..20dc50130 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
@@ -21,6 +21,7 @@ import static com.android.permissioncontroller.permission.ui.Category.ALLOWED;
import static com.android.permissioncontroller.permission.ui.Category.ALLOWED_FOREGROUND;
import static com.android.permissioncontroller.permission.ui.Category.ASK;
import static com.android.permissioncontroller.permission.ui.Category.DENIED;
+import static com.android.permissioncontroller.permission.ui.Category.STORAGE_FOOTER;
import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
import android.Manifest;
@@ -34,6 +35,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
+import android.safetycenter.SafetyCenterManager;
import android.util.ArrayMap;
import android.view.Menu;
import android.view.MenuInflater;
@@ -52,7 +54,6 @@ import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage;
import com.android.permissioncontroller.permission.model.v31.PermissionUsages;
import com.android.permissioncontroller.permission.ui.Category;
-import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
import com.android.permissioncontroller.permission.ui.handheld.v31.CardViewPreference;
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel;
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory;
@@ -62,15 +63,15 @@ import com.android.settingslib.HelpUtils;
import com.android.settingslib.utils.applications.AppUtils;
import com.android.settingslib.widget.FooterPreference;
+import kotlin.Pair;
+import kotlin.Triple;
+
import java.text.Collator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
-import kotlin.Pair;
-import kotlin.Triple;
-
/**
* Show and manage apps which request a single permission group.
*
@@ -87,11 +88,10 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
private static final String STORAGE_ALLOWED_FULL = "allowed_storage_full";
private static final String STORAGE_ALLOWED_SCOPED = "allowed_storage_scoped";
private static final String BLOCKED_SENSOR_PREF_KEY = "sensor_card";
- private static final String STORAGE_FOOTER_CATEGORY_KEY = "storage_footer_category";
private static final String STORAGE_FOOTER_PREFERENCE_KEY = "storage_footer_preference";
private static final int SHOW_LOAD_DELAY_MS = 200;
- private static final int MENU_PERMISSION_USAGE = MENU_HIDE_SYSTEM + 1;
+ private static final String PRIVACY_CONTROLS_ACTION = "android.settings.PRIVACY_CONTROLS";
/**
* Create a bundle with the arguments needed by this fragment
@@ -197,10 +197,6 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
updateMenu(mViewModel.getShouldShowSystemLiveData().getValue());
}
- if (KotlinUtils.INSTANCE.shouldShowPermissionsDashboard()) {
- menu.add(Menu.NONE, MENU_PERMISSION_USAGE, Menu.NONE, R.string.permission_usage_title);
- }
-
if (!SdkLevel.isAtLeastS()) {
HelpUtils.prepareHelpMenuItem(getActivity(), menu, R.string.help_app_permissions,
getClass().getName());
@@ -218,11 +214,6 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
case MENU_HIDE_SYSTEM:
mViewModel.updateShowSystem(item.getItemId() == MENU_SHOW_SYSTEM);
break;
- case MENU_PERMISSION_USAGE:
- getActivity().startActivity(new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE)
- .setClass(getContext(), ManagePermissionsActivity.class)
- .putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, mPermGroupName));
- return true;
}
return super.onOptionsItemSelected(item);
}
@@ -281,12 +272,31 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
findPreference(ALLOWED_FOREGROUND.getCategoryName()).setVisible(false);
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private String getPrivacyControlsIntent() {
+ Context context = getPreferenceManager().getContext();
+ SafetyCenterManager safetyCenterManager =
+ context.getSystemService(SafetyCenterManager.class);
+ if (safetyCenterManager.isSafetyCenterEnabled()) {
+ return PRIVACY_CONTROLS_ACTION;
+ } else {
+ return Settings.ACTION_PRIVACY_SETTINGS;
+ }
+ }
+
@RequiresApi(Build.VERSION_CODES.S)
private CardViewPreference createSensorCard() {
boolean isLocation = Manifest.permission_group.LOCATION.equals(mPermGroupName);
Context context = getPreferenceManager().getContext();
- String action = isLocation ? Settings.ACTION_LOCATION_SOURCE_SETTINGS
- : Settings.ACTION_PRIVACY_SETTINGS;
+
+ String action;
+ if (isLocation) {
+ action = Settings.ACTION_LOCATION_SOURCE_SETTINGS;
+ } else if (SdkLevel.isAtLeastT()) {
+ action = getPrivacyControlsIntent();
+ } else {
+ action = Settings.ACTION_PRIVACY_SETTINGS;
+ }
CardViewPreference sensorCard = new CardViewPreference(context, action);
sensorCard.setKey(BLOCKED_SENSOR_PREF_KEY);
sensorCard.setIcon(Utils.getBlockedIcon(mPermGroupName));
@@ -303,7 +313,7 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
private void addStorageFooterSeeAllFilesAccess() {
PreferenceScreen screen = getPreferenceScreen();
Context context = screen.getPreferenceManager().getContext();
- PreferenceCategory preferenceCategory = findPreference(STORAGE_FOOTER_CATEGORY_KEY);
+ PreferenceCategory preferenceCategory = findPreference(STORAGE_FOOTER.getCategoryName());
Preference existingPreference = findPreference(STORAGE_FOOTER_PREFERENCE_KEY);
if (preferenceCategory == null || existingPreference != null) {
@@ -502,6 +512,13 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
if (SdkLevel.isAtLeastT() && Manifest.permission_group.STORAGE.equals(mPermGroupName)) {
addStorageFooterSeeAllFilesAccess();
+ } else {
+ // Hide storage footer category
+ PreferenceCategory storageFooterPreferenceCategory =
+ findPreference(STORAGE_FOOTER.getCategoryName());
+ if (storageFooterPreferenceCategory != null) {
+ storageFooterPreferenceCategory.setVisible(false);
+ }
}
mViewModel.setCreationLogged(true);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionControlPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionControlPreference.java
index 318ebea06..3d47909e8 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionControlPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionControlPreference.java
@@ -177,9 +177,11 @@ public class PermissionControlPreference extends Preference {
if (mUseSmallerIcon) {
ImageView icon = ((ImageView) holder.findViewById(android.R.id.icon));
icon.setMaxWidth(
- mContext.getResources().getDimensionPixelSize(R.dimen.secondary_app_icon_size));
+ mContext.getResources().getDimensionPixelSize(
+ com.android.settingslib.widget.theme.R.dimen.secondary_app_icon_size));
icon.setMaxHeight(
- mContext.getResources().getDimensionPixelSize(R.dimen.secondary_app_icon_size));
+ mContext.getResources().getDimensionPixelSize(
+ com.android.settingslib.widget.theme.R.dimen.secondary_app_icon_size));
}
super.onBindViewHolder(holder);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.java
index 658a82af5..1089fcac2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.java
@@ -162,7 +162,8 @@ class PermissionPreference extends MultiTargetSwitchPreference {
if (mViewModel.isFixedOrForegroundDisabled(mGroup)) {
if (admin != null) {
- setWidgetLayoutResource(R.layout.restricted_icon);
+ setWidgetLayoutResource(
+ com.android.settingslib.widget.restricted.R.layout.restricted_icon);
setOnPreferenceClickListener((v) -> {
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), admin);
@@ -303,9 +304,9 @@ class PermissionPreference extends MultiTargetSwitchPreference {
int getResource(SummaryMessage summary) {
switch (summary) {
case DISABLED_BY_ADMIN:
- return R.string.disabled_by_admin;
+ return com.android.settingslib.widget.restricted.R.string.disabled_by_admin;
case ENABLED_BY_ADMIN:
- return R.string.enabled_by_admin;
+ return com.android.settingslib.widget.restricted.R.string.enabled_by_admin;
case ENABLED_SYSTEM_FIXED:
return R.string.permission_summary_enabled_system_fixed;
case ENFORCED_BY_POLICY:
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsCollapsingToolbarBaseFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsCollapsingToolbarBaseFragment.java
index 2e9a99bb9..fde134b4d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsCollapsingToolbarBaseFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsCollapsingToolbarBaseFragment.java
@@ -23,7 +23,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceFragmentCompat;
-import com.android.permissioncontroller.R;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseFragment;
/**
@@ -43,13 +42,15 @@ public abstract class PermissionsCollapsingToolbarBaseFragment
PreferenceFragmentCompat preferenceFragment =
(PreferenceFragmentCompat) getChildFragmentManager()
- .findFragmentById(R.id.content_frame);
+ .findFragmentById(
+ com.android.settingslib.collapsingtoolbar.R.id.content_frame);
if (preferenceFragment == null) {
preferenceFragment = createPreferenceFragment();
preferenceFragment.setArguments(getArguments());
getChildFragmentManager().beginTransaction()
- .add(R.id.content_frame, preferenceFragment)
+ .add(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
+ preferenceFragment)
.commit();
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java
index ce7c5cfb9..17e72b413 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionsFrameFragment.java
@@ -87,8 +87,10 @@ public abstract class PermissionsFrameFragment extends PreferenceFragmentCompat
inflater, mPrefsView, savedInstanceState);
setLoading(mIsLoading, false, true /* force */);
mPrefsView.addView(mPreferencesContainer);
- mProgressHeader = rootView.requireViewById(R.id.progress_bar_animation);
- mProgressView = rootView.requireViewById(R.id.progress_bar_background);
+ mProgressHeader = rootView.requireViewById(
+ com.android.settingslib.widget.progressbar.R.id.progress_bar_animation);
+ mProgressView = rootView.requireViewById(
+ com.android.settingslib.widget.progressbar.R.id.progress_bar_background);
setProgressBarVisible(false);
getListView().setFocusable(false);
return rootView;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java
index 5e5c221ae..36d8cce76 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java
@@ -258,7 +258,7 @@ public final class ReviewPermissionsFragment extends PreferenceFragmentCompat
changeId, mViewModel.getPackageInfo().applicationInfo.uid,
group.getPackageName(),
permission.getName(), permission.isGrantedIncludingAppOp());
- Log.v(LOG_TAG, "Permission grant via permission review changeId=" + changeId + " uid="
+ Log.i(LOG_TAG, "Permission grant via permission review changeId=" + changeId + " uid="
+ mViewModel.getPackageInfo().applicationInfo.uid + " packageName="
+ group.getPackageName() + " permission="
+ permission.getName() + " granted=" + permission.isGrantedIncludingAppOp());
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SettingsWithLargeHeader.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SettingsWithLargeHeader.java
index cbd4a0ce0..8745ac8f7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SettingsWithLargeHeader.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SettingsWithLargeHeader.java
@@ -107,7 +107,8 @@ public abstract class SettingsWithLargeHeader extends PermissionsFrameFragment
if (header != null) {
header.setVisibility(View.VISIBLE);
- ImageView appIcon = header.requireViewById(R.id.entity_header_icon);
+ ImageView appIcon = header.requireViewById(
+ com.android.settingslib.widget.preference.layout.R.id.entity_header_icon);
appIcon.setImageDrawable(mIcon);
if (mSmallIcon) {
int size = getContext().getResources().getDimensionPixelSize(
@@ -121,11 +122,18 @@ public abstract class SettingsWithLargeHeader extends PermissionsFrameFragment
appIcon.setContentDescription(mLabel);
}
- TextView appName = header.requireViewById(R.id.entity_header_title);
+ TextView appName = header.requireViewById(
+ com.android.settingslib.widget.preference.layout.R.id.entity_header_title);
appName.setText(mLabel);
- header.requireViewById(R.id.entity_header_summary).setVisibility(View.GONE);
- header.requireViewById(R.id.entity_header_second_summary).setVisibility(View.GONE);
+
+ header.requireViewById(
+ com.android.settingslib.widget.preference.layout.R.id.entity_header_summary)
+ .setVisibility(View.GONE);
+
+ header.requireViewById(
+ com.android.settingslib.widget.preference.layout.R.id.entity_header_second_summary)
+ .setVisibility(View.GONE);
header.requireViewById(R.id.header_link).setVisibility(View.GONE);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SmartIconLoadPackagePermissionPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SmartIconLoadPackagePermissionPreference.kt
index 27cbd8c15..b31b3e484 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SmartIconLoadPackagePermissionPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SmartIconLoadPackagePermissionPreference.kt
@@ -30,16 +30,17 @@ import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.utils.KotlinUtils
/**
- * A Preference representing a package for a user, which loads and displays its icon only upon
- * being bound to a viewHolder. This lets us synchronously load package icons and labels, while
- * still displaying the PermissionAppsFragment instantly.
+ * A Preference representing a package for a user, which loads and displays its icon only upon being
+ * bound to a viewHolder. This lets us synchronously load package icons and labels, while still
+ * displaying the PermissionAppsFragment instantly.
*
* @param app The current application
* @param packageName The name of the package whose icon this preference will retrieve
* @param user The user whose package icon will be retrieved
* @param context The current context
*/
-open class SmartIconLoadPackagePermissionPreference constructor(
+open class SmartIconLoadPackagePermissionPreference
+constructor(
private val app: Application,
private val packageName: String,
private val user: UserHandle,
@@ -62,9 +63,13 @@ open class SmartIconLoadPackagePermissionPreference constructor(
val imageView = holder.findViewById(android.R.id.icon) as ImageView
imageView.maxWidth =
- context.resources.getDimensionPixelSize(R.dimen.secondary_app_icon_size)
+ context.resources.getDimensionPixelSize(
+ com.android.settingslib.widget.theme.R.dimen.secondary_app_icon_size
+ )
imageView.maxHeight =
- context.resources.getDimensionPixelSize(R.dimen.secondary_app_icon_size)
+ context.resources.getDimensionPixelSize(
+ com.android.settingslib.widget.theme.R.dimen.secondary_app_icon_size
+ )
imageView.setImageDrawable(KotlinUtils.getBadgedPackageIcon(app, packageName, user))
imageView.visibility = View.VISIBLE
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/UnusedAppPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/UnusedAppPreference.kt
index dfab55ed7..02eb6c090 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/UnusedAppPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/UnusedAppPreference.kt
@@ -50,9 +50,7 @@ class UnusedAppPreference(
super.onBindViewHolder(holder)
val removeButton = holder.findViewById(R.id.uninstall_button) as ImageButton
- removeButton.setOnClickListener {
- removeRunnable?.run()
- }
+ removeButton.setOnClickListener { removeRunnable?.run() }
removeButton.isEnabled = removeButtonEnabled
}
@@ -63,4 +61,4 @@ class UnusedAppPreference(
override fun setRemoveComponentEnabled(enabled: Boolean) {
removeButtonEnabled = enabled
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/Utils.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/Utils.kt
index e2acb498c..f6a387e9d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/Utils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/Utils.kt
@@ -19,12 +19,10 @@ package com.android.permissioncontroller.permission.ui.handheld
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
-/**
- * Press back and close the activity if this is the last fragment.
- */
+/** Press back and close the activity if this is the last fragment. */
fun Fragment.pressBack() {
val wasBackExecuted = findNavController().popBackStack()
if (!wasBackExecuted) {
activity?.let { it.finishAfterTransition() }
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/DashboardUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/DashboardUtils.kt
index 5b92dd36d..b36d5174c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/DashboardUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/DashboardUtils.kt
@@ -49,7 +49,6 @@ fun shouldShowSubattributionInPermissionsDashboard(): Boolean {
*
* @param context the context.
* @param lastAccessTime the time in milliseconds.
- *
* @return a string representing the time or date of the given time or null if the time is 0.
*/
fun getAbsoluteTimeString(context: Context, lastAccessTime: Long): String? {
@@ -64,14 +63,13 @@ fun getAbsoluteTimeString(context: Context, lastAccessTime: Long): String? {
}
/**
- * Build a string representing the time of the most recent permission usage if it happened on
- * the current day and the date otherwise.
+ * Build a string representing the time of the most recent permission usage if it happened on the
+ * current day and the date otherwise.
*
* @param context the context.
* @param groupUsage the permission usage.
- *
- * @return a string representing the time or date of the most recent usage or null if there are
- * no usages.
+ * @return a string representing the time or date of the most recent usage or null if there are no
+ * usages.
*/
@RequiresApi(Build.VERSION_CODES.S)
fun getAbsoluteLastUsageString(context: Context, groupUsage: GroupUsage?): String? {
@@ -83,8 +81,7 @@ fun getAbsoluteLastUsageString(context: Context, groupUsage: GroupUsage?): Strin
/**
* Build a string representing the duration of a permission usage.
*
- * @return a string representing the duration of this app's usage or null if there are no
- * usages.
+ * @return a string representing the duration of this app's usage or null if there are no usages.
*/
@RequiresApi(Build.VERSION_CODES.S)
fun getUsageDurationString(context: Context, groupUsage: GroupUsage?): String? {
@@ -94,9 +91,9 @@ fun getUsageDurationString(context: Context, groupUsage: GroupUsage?): String? {
}
/**
- * Build a string representing the number of milliseconds passed in. It rounds to the nearest
- * unit. For example, given a duration of 3500 and an English locale, this can return
- * "3 seconds".
+ * Build a string representing the number of milliseconds passed in. It rounds to the nearest unit.
+ * For example, given a duration of 3500 and an English locale, this can return "3 seconds".
+ *
* @param context The context.
* @param duration The number of milliseconds.
* @return a string representing the given number of milliseconds.
@@ -104,37 +101,63 @@ fun getUsageDurationString(context: Context, groupUsage: GroupUsage?): String? {
fun getTimeDiffStr(context: Context, duration: Long): String {
val timeDiffAndUnit = calculateTimeDiffAndUnit(duration)
return when (timeDiffAndUnit.second) {
- SECONDS -> StringUtils.getIcuPluralsString(context,
- R.string.seconds, timeDiffAndUnit.first.toInt())
- MINUTES -> StringUtils.getIcuPluralsString(context,
- R.string.minutes, timeDiffAndUnit.first.toInt())
- HOURS -> StringUtils.getIcuPluralsString(context,
- R.string.hours, timeDiffAndUnit.first.toInt())
- else -> StringUtils.getIcuPluralsString(context,
- R.string.days, timeDiffAndUnit.first.toInt())
+ SECONDS ->
+ StringUtils.getIcuPluralsString(
+ context,
+ R.string.seconds,
+ timeDiffAndUnit.first.toInt()
+ )
+ MINUTES ->
+ StringUtils.getIcuPluralsString(
+ context,
+ R.string.minutes,
+ timeDiffAndUnit.first.toInt()
+ )
+ HOURS ->
+ StringUtils.getIcuPluralsString(context, R.string.hours, timeDiffAndUnit.first.toInt())
+ else ->
+ StringUtils.getIcuPluralsString(context, R.string.days, timeDiffAndUnit.first.toInt())
}
}
/**
* Build a string representing the duration used of milliseconds passed in.
+ *
* @return a string representing the duration used in the nearest unit. ex: Used for 3 mins
*/
fun getDurationUsedStr(context: Context, duration: Long): String {
val timeDiffAndUnit = calculateTimeDiffAndUnit(duration)
return when (timeDiffAndUnit.second) {
- SECONDS -> StringUtils.getIcuPluralsString(context,
- R.string.duration_used_seconds, timeDiffAndUnit.first.toInt())
- MINUTES -> StringUtils.getIcuPluralsString(context,
- R.string.duration_used_minutes, timeDiffAndUnit.first.toInt())
- HOURS -> StringUtils.getIcuPluralsString(context,
- R.string.duration_used_hours, timeDiffAndUnit.first.toInt())
- else -> StringUtils.getIcuPluralsString(context,
- R.string.duration_used_days, timeDiffAndUnit.first.toInt())
+ SECONDS ->
+ StringUtils.getIcuPluralsString(
+ context,
+ R.string.duration_used_seconds,
+ timeDiffAndUnit.first.toInt()
+ )
+ MINUTES ->
+ StringUtils.getIcuPluralsString(
+ context,
+ R.string.duration_used_minutes,
+ timeDiffAndUnit.first.toInt()
+ )
+ HOURS ->
+ StringUtils.getIcuPluralsString(
+ context,
+ R.string.duration_used_hours,
+ timeDiffAndUnit.first.toInt()
+ )
+ else ->
+ StringUtils.getIcuPluralsString(
+ context,
+ R.string.duration_used_days,
+ timeDiffAndUnit.first.toInt()
+ )
}
}
/**
* Given the duration in milliseconds, calculate the time of that duration in the nearest unit.
+ *
* @return a Pair of the <duration in the nearest unit, the nearest unit>
*/
fun calculateTimeDiffAndUnit(duration: Long): Pair<Long, Int> {
@@ -159,7 +182,6 @@ fun calculateTimeDiffAndUnit(duration: Long): Pair<Long, Int> {
* Check whether the given time (in milliseconds) is in the current day.
*
* @param time the time in milliseconds
- *
* @return whether the given time is in the current day.
*/
private fun isToday(time: Long): Boolean {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionHistoryPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionHistoryPreference.java
index bcca75fcc..5c20ef9df 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionHistoryPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionHistoryPreference.java
@@ -77,7 +77,7 @@ public class PermissionHistoryPreference extends Preference {
public PermissionHistoryPreference(@NonNull Context context,
@NonNull UserHandle userHandle, @NonNull String pkgName,
- @NonNull Drawable appIcon,
+ @Nullable Drawable appIcon,
@NonNull String preferenceTitle,
@NonNull String permissionGroup,
@NonNull long accessStartTime,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java
index 15ee31a54..5d4343639 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java
@@ -368,15 +368,9 @@ public class PermissionUsageDetailsFragment extends SettingsWithLargeHeader {
new PermissionHistoryPreference(
getContext(),
appPermissionAccessUiInfo.getUserHandle(),
- appPermissionAccessUiInfo.getPkgName(),
- KotlinUtils.INSTANCE.getBadgedPackageIcon(
- mViewModel.getApplication(),
- appPermissionAccessUiInfo.getPkgName(),
- appPermissionAccessUiInfo.getUserHandle()),
- KotlinUtils.INSTANCE.getPackageLabel(
- mViewModel.getApplication(),
- appPermissionAccessUiInfo.getPkgName(),
- appPermissionAccessUiInfo.getUserHandle()),
+ appPermissionAccessUiInfo.getPackageName(),
+ appPermissionAccessUiInfo.getBadgedPackageIcon(),
+ appPermissionAccessUiInfo.getPackageLabel(),
appPermissionAccessUiInfo.getPermissionGroup(),
appPermissionAccessUiInfo.getAccessStartTime(),
appPermissionAccessUiInfo.getAccessEndTime(),
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt
index 88b5ebe87..3ef11a4d7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt
@@ -22,10 +22,10 @@ import android.text.style.ClickableSpan
import android.util.AttributeSet
import android.view.View
import android.widget.TextView
+import androidx.core.text.method.LinkMovementMethodCompat
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.compat.LinkMovementMethodCompat
/** A preference for a footer with an icon and a link. */
class AppDataSharingUpdatesFooterPreference : Preference {
@@ -76,7 +76,8 @@ class AppDataSharingUpdatesFooterPreference : Preference {
},
0,
footerLink.length,
- 0)
+ 0
+ )
footerLinkView?.let {
it.visibility = if (onFooterLinkClick == null) View.GONE else View.VISIBLE
it.text = footerLinkText
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFragment.kt
index 2db9bc4b4..1da058141 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFragment.kt
@@ -98,7 +98,8 @@ class AppDataSharingUpdatesFragment : PermissionsFrameFragment() {
val updatesCategory =
preferenceScreen.findPreference<PreferenceCategory>(
LAST_PERIOD_UPDATES_PREFERENCE_CATEGORY_ID
- ) ?: return
+ )
+ ?: return
val preferencesToRemove = mutableSetOf<Preference>()
for (i in 0 until (updatesCategory.preferenceCount)) {
@@ -192,11 +193,12 @@ class AppDataSharingUpdatesFragment : PermissionsFrameFragment() {
it.isVisible = true
}
- val onFooterLinkClick = if (viewModel.canLinkToHelpCenter(requireActivity())) {
- View.OnClickListener { viewModel.openSafetyLabelsHelpCenterPage(requireActivity()) }
- } else {
- null
- }
+ val onFooterLinkClick =
+ if (viewModel.canLinkToHelpCenter(requireActivity())) {
+ View.OnClickListener { viewModel.openSafetyLabelsHelpCenterPage(requireActivity()) }
+ } else {
+ null
+ }
footerPreference?.let {
it.footerMessage = getString(R.string.data_sharing_updates_footer_message)
it.footerLink = getString(R.string.learn_about_data_sharing)
@@ -231,11 +233,14 @@ class AppDataSharingUpdatesFragment : PermissionsFrameFragment() {
footerPreference?.let {
it.footerMessage = getString(R.string.data_sharing_updates_footer_message)
it.footerLink = getString(R.string.learn_about_data_sharing)
- it.onFooterLinkClick = if (viewModel.canLinkToHelpCenter(requireActivity())) {
- View.OnClickListener { viewModel.openSafetyLabelsHelpCenterPage(requireActivity()) }
- } else {
- null
- }
+ it.onFooterLinkClick =
+ if (viewModel.canLinkToHelpCenter(requireActivity())) {
+ View.OnClickListener {
+ viewModel.openSafetyLabelsHelpCenterPage(requireActivity())
+ }
+ } else {
+ null
+ }
it.isVisible = true
}
}
@@ -282,7 +287,7 @@ class AppDataSharingUpdatesFragment : PermissionsFrameFragment() {
sessionId,
numberOfAppUpdates
)
- Log.v(
+ Log.i(
LOG_TAG,
"AppDataSharingUpdatesFragment viewed with" +
" sessionId=$sessionId" +
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt
index 3998ca141..9eb7a0fa4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt
@@ -33,8 +33,8 @@ import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.RequiresApi
+import androidx.core.text.method.LinkMovementMethodCompat
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.compat.LinkMovementMethodCompat
import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleViewHandler
import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleViewHandler.Result.Companion.CANCELLED
@@ -122,14 +122,14 @@ class PermissionRationaleViewHandlerImpl(
// Grow or shrink the content container to size of new content
val growShrinkToNewContentSize = ChangeBounds()
growShrinkToNewContentSize.duration = ANIMATION_DURATION_MILLIS
- growShrinkToNewContentSize.interpolator = AnimationUtils.loadInterpolator(mActivity,
- android.R.interpolator.fast_out_slow_in)
+ growShrinkToNewContentSize.interpolator =
+ AnimationUtils.loadInterpolator(mActivity, android.R.interpolator.fast_out_slow_in)
TransitionManager.beginDelayedTransition(rootView, growShrinkToNewContentSize)
}
override fun createView(): View {
- val rootView = LayoutInflater.from(mActivity)
- .inflate(R.layout.permission_rationale, null) as ViewGroup
+ val rootView =
+ LayoutInflater.from(mActivity).inflate(R.layout.permission_rationale, null) as ViewGroup
// Uses the vertical gravity of the PermissionGrantSingleton style to position the window
val gravity =
@@ -160,13 +160,15 @@ class PermissionRationaleViewHandlerImpl(
val settingsSectionView: ViewGroup? = rootView.findViewById(R.id.settings_section)
settingsSectionView?.visibility = View.GONE
}
- backButton = rootView.findViewById<Button>(R.id.back_button)!!.apply {
- setOnClickListener(this@PermissionRationaleViewHandlerImpl)
-
- // Load the text color from the activity theme rather than the Material Design theme
- val textColor = getColorStateListForAttr(mActivity, android.R.attr.textColorPrimary)!!
- setTextColor(textColor)
- }
+ backButton =
+ rootView.findViewById<Button>(R.id.back_button)!!.apply {
+ setOnClickListener(this@PermissionRationaleViewHandlerImpl)
+
+ // Load the text color from the activity theme rather than the Material Design theme
+ val textColor =
+ getColorStateListForAttr(mActivity, android.R.attr.textColorPrimary)!!
+ setTextColor(textColor)
+ }
this.rootView = rootView
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
index e219153f3..14aff67ba 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
@@ -44,8 +44,8 @@ import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPackageLabel
import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.StringUtils
-import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
import java.time.Instant
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.DAYS
@@ -93,7 +93,8 @@ class PermissionUsageDetailsViewModelLegacy(
/* getUiInfo= */ false,
/* getNonPlatformPermissions= */ false,
/* callback= */ callback,
- /* sync= */ false)
+ /* sync= */ false
+ )
}
/**
@@ -116,19 +117,26 @@ class PermissionUsageDetailsViewModelLegacy(
}
val startTime =
(System.currentTimeMillis() - showPermissionUsagesDuration).coerceAtLeast(
- Instant.EPOCH.toEpochMilli())
+ Instant.EPOCH.toEpochMilli()
+ )
val appPermissionTimelineUsages: List<AppPermissionTimelineUsage> =
extractAppPermissionTimelineUsagesForGroup(appPermissionUsages, permissionGroup)
val shouldDisplayShowSystemToggle =
shouldDisplayShowSystemToggle(appPermissionTimelineUsages)
val permissionApps: List<PermissionApp> =
getPermissionAppsWithRecentDiscreteUsage(
- appPermissionTimelineUsages, showSystem, startTime)
+ appPermissionTimelineUsages,
+ showSystem,
+ startTime
+ )
val appPermissionUsageEntries =
buildDiscreteAccessClusterData(appPermissionTimelineUsages, showSystem, startTime)
return PermissionUsageDetailsUiData(
- permissionApps, shouldDisplayShowSystemToggle, appPermissionUsageEntries)
+ permissionApps,
+ shouldDisplayShowSystemToggle,
+ appPermissionUsageEntries
+ )
}
private fun getHistoryPreferenceData(
@@ -141,14 +149,14 @@ class PermissionUsageDetailsViewModelLegacy(
getDurationSummary(discreteAccessClusterData, accessTimeList, context)
val proxyLabel = getProxyPackageLabel(discreteAccessClusterData)
val subattributionLabel = getSubattributionLabel(discreteAccessClusterData)
- val showingSubattribution =
- subattributionLabel != null && subattributionLabel.isNotEmpty()
+ val showingSubattribution = subattributionLabel != null && subattributionLabel.isNotEmpty()
val summary =
buildUsageSummary(durationSummaryLabel, proxyLabel, subattributionLabel, context)
return HistoryPreferenceData(
UserHandle.getUserHandleForUid(
- discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.uid),
+ discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.uid
+ ),
discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.packageName,
discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.icon,
discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.label,
@@ -158,7 +166,8 @@ class PermissionUsageDetailsViewModelLegacy(
summary,
showingSubattribution,
discreteAccessClusterData.appPermissionTimelineUsage.attributionTags,
- sessionId)
+ sessionId
+ )
}
/**
@@ -180,7 +189,8 @@ class PermissionUsageDetailsViewModelLegacy(
.map { appPermissionUsage ->
getAppPermissionTimelineUsages(
appPermissionUsage.app,
- appPermissionUsage.groupUsages.firstOrNull { it.group.name == group })
+ appPermissionUsage.groupUsages.firstOrNull { it.group.name == group }
+ )
}
.flatten()
@@ -221,7 +231,10 @@ class PermissionUsageDetailsViewModelLegacy(
.map { appPermissionTimelineUsages ->
val accessDataList =
extractRecentDiscreteAccessData(
- appPermissionTimelineUsages.timelineUsage, showSystem, startTime)
+ appPermissionTimelineUsages.timelineUsage,
+ showSystem,
+ startTime
+ )
if (accessDataList.size <= 1) {
return@map accessDataList.map {
@@ -235,7 +248,9 @@ class PermissionUsageDetailsViewModelLegacy(
.sortedWith(
compareBy(
{ -it.discreteAccessDataList.first().accessTimeMs },
- { it.appPermissionTimelineUsage.permissionApp.label }))
+ { it.appPermissionTimelineUsage.permissionApp.label }
+ )
+ )
.toList()
/**
@@ -253,11 +268,15 @@ class PermissionUsageDetailsViewModelLegacy(
for (discreteAccessData in discreteAccessDataList) {
if (currentDiscreteAccessDataList.isEmpty()) {
currentDiscreteAccessDataList.add(discreteAccessData)
- } else if (!canAccessBeAddedToCluster(
- discreteAccessData, currentDiscreteAccessDataList)) {
+ } else if (
+ !canAccessBeAddedToCluster(discreteAccessData, currentDiscreteAccessDataList)
+ ) {
clusterDataList.add(
DiscreteAccessClusterData(
- appPermissionTimelineUsage, currentDiscreteAccessDataList.toMutableList()))
+ appPermissionTimelineUsage,
+ currentDiscreteAccessDataList.toMutableList()
+ )
+ )
currentDiscreteAccessDataList.clear()
currentDiscreteAccessDataList.add(discreteAccessData)
} else {
@@ -266,8 +285,8 @@ class PermissionUsageDetailsViewModelLegacy(
}
if (currentDiscreteAccessDataList.isNotEmpty()) {
clusterDataList.add(
- DiscreteAccessClusterData(
- appPermissionTimelineUsage, currentDiscreteAccessDataList))
+ DiscreteAccessClusterData(appPermissionTimelineUsage, currentDiscreteAccessDataList)
+ )
}
return clusterDataList
}
@@ -282,8 +301,9 @@ class PermissionUsageDetailsViewModelLegacy(
showSystem: Boolean,
startTime: Long
): List<DiscreteAccessData> {
- return if (timelineUsages.hasDiscreteData() &&
- (showSystem || !timelineUsages.group.isSystem())) {
+ return if (
+ timelineUsages.hasDiscreteData() && (showSystem || !timelineUsages.group.isSystem())
+ ) {
getRecentDiscreteAccessData(timelineUsages, startTime)
.sortedWith(compareBy { -it.accessTimeMs })
.toList()
@@ -377,7 +397,8 @@ class PermissionUsageDetailsViewModelLegacy(
getPackageLabel(
PermissionControllerApplication.get(),
it.proxy!!.packageName!!,
- UserHandle.getUserHandleForUid(it.proxy.uid))
+ UserHandle.getUserHandleForUid(it.proxy.uid)
+ )
}
/** Returns the attribution label for the permission access, if any. */
@@ -406,10 +427,14 @@ class PermissionUsageDetailsViewModelLegacy(
R.string.history_preference_subtext_3,
subTextStrings[0],
subTextStrings[1],
- subTextStrings[2])
+ subTextStrings[2]
+ )
2 ->
context.getString(
- R.string.history_preference_subtext_2, subTextStrings[0], subTextStrings[1])
+ R.string.history_preference_subtext_2,
+ subTextStrings[0],
+ subTextStrings[1]
+ )
1 -> subTextStrings[0]
else -> null
}
@@ -434,7 +459,8 @@ class PermissionUsageDetailsViewModelLegacy(
}
return listOf(
- AppPermissionTimelineUsage(permissionGroup, app, groupUsage, Resources.ID_NULL))
+ AppPermissionTimelineUsage(permissionGroup, app, groupUsage, Resources.ID_NULL)
+ )
}
/** Extracts to a set all the permission groups declared by the platform. */
@@ -448,15 +474,20 @@ class PermissionUsageDetailsViewModelLegacy(
/** Initialize all relevant [TimeFilterItemMs] values. */
private fun initializeTimeFilterItems(context: Context) {
mTimeFilterItemMs.add(
- TimeFilterItemMs(Long.MAX_VALUE, context.getString(R.string.permission_usage_any_time)))
+ TimeFilterItemMs(Long.MAX_VALUE, context.getString(R.string.permission_usage_any_time))
+ )
mTimeFilterItemMs.add(
TimeFilterItemMs(
DAYS.toMillis(7),
- StringUtils.getIcuPluralsString(context, R.string.permission_usage_last_n_days, 7)))
+ StringUtils.getIcuPluralsString(context, R.string.permission_usage_last_n_days, 7)
+ )
+ )
mTimeFilterItemMs.add(
TimeFilterItemMs(
DAYS.toMillis(1),
- StringUtils.getIcuPluralsString(context, R.string.permission_usage_last_n_days, 1)))
+ StringUtils.getIcuPluralsString(context, R.string.permission_usage_last_n_days, 1)
+ )
+ )
// TODO: theianchen add code for filtering by time here.
}
@@ -554,7 +585,11 @@ class PermissionUsageDetailsViewModelFactoryLegacy(
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return PermissionUsageDetailsViewModelLegacy(
- application, roleManager, filterGroup, sessionId)
+ application,
+ roleManager,
+ filterGroup,
+ sessionId
+ )
as T
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt
index d0e751f7d..3032dece5 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt
@@ -57,7 +57,8 @@ class PermissionUsageViewModelLegacy(val roleManager: RoleManager) : ViewModel()
mapOf(
Manifest.permission_group.LOCATION to 0,
Manifest.permission_group.CAMERA to 1,
- Manifest.permission_group.MICROPHONE to 2)
+ Manifest.permission_group.MICROPHONE to 2
+ )
private const val DEFAULT_ORDER = 3
}
@@ -79,7 +80,8 @@ class PermissionUsageViewModelLegacy(val roleManager: RoleManager) : ViewModel()
false /*getUiInfo*/,
false /*getNonPlatformPermissions*/,
callback /*callback*/,
- false /*sync*/)
+ false /*sync*/
+ )
}
/**
@@ -108,10 +110,16 @@ class PermissionUsageViewModelLegacy(val roleManager: RoleManager) : ViewModel()
val permissionApps = filteredAppPermissionUsages.getRecentPermissionApps(startTime)
val orderedPermissionGroupsWithUsage =
filteredAppPermissionUsages.buildOrderedPermissionGroupsWithUsageCount(
- context, startTime, showSystem)
+ context,
+ startTime,
+ showSystem
+ )
return PermissionUsagesUiData(
- permissionApps, displayShowSystemToggle, orderedPermissionGroupsWithUsage)
+ permissionApps,
+ displayShowSystemToggle,
+ orderedPermissionGroupsWithUsage
+ )
}
/**
@@ -150,7 +158,9 @@ class PermissionUsageViewModelLegacy(val roleManager: RoleManager) : ViewModel()
.sortedWith(
compareBy(
{ PERMISSION_GROUP_ORDER.getOrDefault(it.permGroup, DEFAULT_ORDER) },
- { getPermGroupLabel(context, it.permGroup).toString() }))
+ { getPermGroupLabel(context, it.permGroup).toString() }
+ )
+ )
}
/** Extracts [PermissionApp] where there has been recent permission usage. */
@@ -163,7 +173,8 @@ class PermissionUsageViewModelLegacy(val roleManager: RoleManager) : ViewModel()
.filter { !EXEMPTED_PERMISSION_GROUPS.contains(it.group.name) }
.any { it.lastAccessTime >= startTime || it.lastAccessTime == 0L }
}
- .map { it.app })
+ .map { it.app }
+ )
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AllAppPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AllAppPermissionsViewModel.kt
index d789f4e1e..3e651dd9f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AllAppPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AllAppPermissionsViewModel.kt
@@ -33,41 +33,34 @@ import com.android.permissioncontroller.permission.utils.Utils
*
* @param packageName The name of the package this viewModel is representing
* @param user The user of the package this viewModel is representing
- * @param filterGroup An optional single group that should be shown, no other groups will be
- * shown
+ * @param filterGroup An optional single group that should be shown, no other groups will be shown
*/
-class AllAppPermissionsViewModel(
- packageName: String,
- user: UserHandle,
- filterGroup: String?
-) : ViewModel() {
+class AllAppPermissionsViewModel(packageName: String, user: UserHandle, filterGroup: String?) :
+ ViewModel() {
- val allPackagePermissionsLiveData = AllPackagePermissionsLiveData(packageName, user,
- filterGroup)
+ val allPackagePermissionsLiveData =
+ AllPackagePermissionsLiveData(packageName, user, filterGroup)
class AllPackagePermissionsLiveData(
packageName: String,
user: UserHandle,
private val filterGroup: String?
- ) : SmartUpdateMediatorLiveData<@kotlin.jvm.JvmSuppressWildcards
- Map<String, List<String>>>() {
+ ) : SmartUpdateMediatorLiveData<@kotlin.jvm.JvmSuppressWildcards Map<String, List<String>>>() {
- private val packagePermsLiveData =
- PackagePermissionsLiveData[packageName, user]
+ private val packagePermsLiveData = PackagePermissionsLiveData[packageName, user]
private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
init {
- addSource(packagePermsLiveData) {
- update()
- }
- addSource(packageInfoLiveData) {
- update()
- }
+ addSource(packagePermsLiveData) { update() }
+ addSource(packageInfoLiveData) { update() }
}
override fun onUpdate() {
- if (!packagePermsLiveData.isInitialized || packagePermsLiveData.isStale ||
- !packageInfoLiveData.isInitialized) {
+ if (
+ !packagePermsLiveData.isInitialized ||
+ packagePermsLiveData.isStale ||
+ !packageInfoLiveData.isInitialized
+ ) {
return
}
val permissions = packagePermsLiveData.value
@@ -77,10 +70,17 @@ class AllAppPermissionsViewModel(
return
}
- value = permissions
- .filter { filterGroup == null || it.key == filterGroup }
- .filter { (it.key != Manifest.permission_group.STORAGE ||
- Utils.shouldShowStorage(packageInfo)) }
+ value =
+ permissions
+ .filter { filterGroup == null || it.key == filterGroup }
+ .filter {
+ (it.key != Manifest.permission_group.STORAGE ||
+ Utils.shouldShowStorage(packageInfo))
+ }
+ .filter {
+ (!Utils.isHealthPermissionGroup(it.key) ||
+ Utils.shouldShowHealthPermission(packageInfo, it.key))
+ }
}
}
}
@@ -91,8 +91,7 @@ class AllAppPermissionsViewModel(
* @param app The current application
* @param packageName The name of the package this viewModel is representing
* @param user The user of the package this viewModel is representing
- * @param filterGroup An optional single group that should be shown, no other groups will be
- * shown
+ * @param filterGroup An optional single group that should be shown, no other groups will be shown
*/
class AllAppPermissionsViewModelFactory(
private val packageName: String,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
index 741c93aab..5ecab1527 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
@@ -95,135 +95,165 @@ class AppPermissionGroupsViewModel(
val isSystem: Boolean = false,
val subtitle: PermSubtitle
) {
- constructor(groupName: String, isSystem: Boolean) :
- this(groupName, isSystem, PermSubtitle.NONE)
+ constructor(
+ groupName: String,
+ isSystem: Boolean
+ ) : this(groupName, isSystem, PermSubtitle.NONE)
}
// Auto-revoke and hibernation share the same settings
val autoRevokeLiveData = HibernationSettingStateLiveData[packageName, user]
- private val packagePermsLiveData =
- PackagePermissionsLiveData[packageName, user]
+ private val packagePermsLiveData = PackagePermissionsLiveData[packageName, user]
private val appPermGroupUiInfoLiveDatas = mutableMapOf<String, AppPermGroupUiInfoLiveData>()
private val fullStoragePermsLiveData = FullStoragePermissionAppsLiveData
/**
- * LiveData whose data is a map of grant category (either allowed or denied) to a list
- * of permission group names that match the key, and two booleans representing if this is a
- * system group, and a subtitle resource ID, if applicable.
+ * LiveData whose data is a map of grant category (either allowed or denied) to a list of
+ * permission group names that match the key, and two booleans representing if this is a system
+ * group, and a subtitle resource ID, if applicable.
*/
- val packagePermGroupsLiveData = object : SmartUpdateMediatorLiveData<@JvmSuppressWildcards
- Map<Category, List<GroupUiInfo>>>() {
-
- init {
- addSource(packagePermsLiveData) {
- update()
- }
- addSource(fullStoragePermsLiveData) {
- update()
- }
- addSource(autoRevokeLiveData) {
- removeSource(autoRevokeLiveData)
+ val packagePermGroupsLiveData =
+ object :
+ SmartUpdateMediatorLiveData<@JvmSuppressWildcards Map<Category, List<GroupUiInfo>>>() {
+
+ init {
+ addSource(packagePermsLiveData) { update() }
+ addSource(fullStoragePermsLiveData) { update() }
+ addSource(autoRevokeLiveData) {
+ removeSource(autoRevokeLiveData)
+ update()
+ }
update()
}
- update()
- }
- override fun onUpdate() {
- val groups = packagePermsLiveData.value?.keys?.filter { it != NON_RUNTIME_NORMAL_PERMS }
- if (groups == null && packagePermsLiveData.isInitialized) {
- value = null
- return
- } else if (groups == null || (Manifest.permission_group.STORAGE in groups &&
- !fullStoragePermsLiveData.isInitialized) || !autoRevokeLiveData.isInitialized) {
- return
- }
-
- val getLiveData = { groupName: String ->
- AppPermGroupUiInfoLiveData[packageName, groupName, user]
- }
- setSourcesToDifference(groups, appPermGroupUiInfoLiveDatas, getLiveData)
+ override fun onUpdate() {
+ val groups =
+ packagePermsLiveData.value?.keys?.filter { it != NON_RUNTIME_NORMAL_PERMS }
+ if (groups == null && packagePermsLiveData.isInitialized) {
+ value = null
+ return
+ } else if (
+ groups == null ||
+ (Manifest.permission_group.STORAGE in groups &&
+ !fullStoragePermsLiveData.isInitialized) ||
+ !autoRevokeLiveData.isInitialized
+ ) {
+ return
+ }
- if (!appPermGroupUiInfoLiveDatas.all { it.value.isInitialized }) {
- return
- }
+ val getLiveData = { groupName: String ->
+ AppPermGroupUiInfoLiveData[packageName, groupName, user]
+ }
+ setSourcesToDifference(groups, appPermGroupUiInfoLiveDatas, getLiveData)
- val groupGrantStates = mutableMapOf<Category,
- MutableList<GroupUiInfo>>()
- groupGrantStates[Category.ALLOWED] = mutableListOf()
- groupGrantStates[Category.ASK] = mutableListOf()
- groupGrantStates[Category.DENIED] = mutableListOf()
+ if (!appPermGroupUiInfoLiveDatas.all { it.value.isInitialized }) {
+ return
+ }
- val fullStorageState = fullStoragePermsLiveData.value?.find { pkg ->
- pkg.packageName == packageName && pkg.user == user
- }
+ val groupGrantStates = mutableMapOf<Category, MutableList<GroupUiInfo>>()
+ groupGrantStates[Category.ALLOWED] = mutableListOf()
+ groupGrantStates[Category.ASK] = mutableListOf()
+ groupGrantStates[Category.DENIED] = mutableListOf()
- for (groupName in groups) {
- val isSystem = PermissionMapping.getPlatformPermissionGroups().contains(groupName)
- appPermGroupUiInfoLiveDatas[groupName]?.value?.let { uiInfo ->
- if (SdkLevel.isAtLeastT() && !uiInfo.shouldShow) {
- return@let
+ val fullStorageState =
+ fullStoragePermsLiveData.value?.find { pkg ->
+ pkg.packageName == packageName && pkg.user == user
}
- if (groupName == Manifest.permission_group.STORAGE &&
- (fullStorageState?.isGranted == true && !fullStorageState.isLegacy)) {
- groupGrantStates[Category.ALLOWED]!!.add(
- GroupUiInfo(groupName, isSystem, PermSubtitle.ALL_FILES))
- return@let
- }
- when (uiInfo.permGrantState) {
- PermGrantState.PERMS_ALLOWED -> {
- val subtitle = if (groupName == Manifest.permission_group.STORAGE) {
- if (SdkLevel.isAtLeastT()) {
- PermSubtitle.NONE
- } else {
- if (fullStorageState?.isLegacy == true) {
- PermSubtitle.ALL_FILES
+
+ for (groupName in groups) {
+ val isSystem =
+ PermissionMapping.getPlatformPermissionGroups().contains(groupName)
+ appPermGroupUiInfoLiveDatas[groupName]?.value?.let { uiInfo ->
+ if (SdkLevel.isAtLeastT() && !uiInfo.shouldShow) {
+ return@let
+ }
+ if (
+ groupName == Manifest.permission_group.STORAGE &&
+ (fullStorageState?.isGranted == true && !fullStorageState.isLegacy)
+ ) {
+ groupGrantStates[Category.ALLOWED]!!.add(
+ GroupUiInfo(groupName, isSystem, PermSubtitle.ALL_FILES)
+ )
+ return@let
+ }
+ when (uiInfo.permGrantState) {
+ PermGrantState.PERMS_ALLOWED -> {
+ val subtitle =
+ if (groupName == Manifest.permission_group.STORAGE) {
+ if (SdkLevel.isAtLeastT()) {
+ PermSubtitle.NONE
+ } else {
+ if (fullStorageState?.isLegacy == true) {
+ PermSubtitle.ALL_FILES
+ } else {
+ PermSubtitle.MEDIA_ONLY
+ }
+ }
} else {
- PermSubtitle.MEDIA_ONLY
+ PermSubtitle.NONE
}
- }
- } else {
- PermSubtitle.NONE
+ groupGrantStates[Category.ALLOWED]!!.add(
+ GroupUiInfo(groupName, isSystem, subtitle)
+ )
}
- groupGrantStates[Category.ALLOWED]!!.add(
- GroupUiInfo(groupName, isSystem, subtitle))
+ PermGrantState.PERMS_ALLOWED_ALWAYS ->
+ groupGrantStates[Category.ALLOWED]!!.add(
+ GroupUiInfo(groupName, isSystem, PermSubtitle.BACKGROUND)
+ )
+ PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY ->
+ groupGrantStates[Category.ALLOWED]!!.add(
+ GroupUiInfo(groupName, isSystem, PermSubtitle.FOREGROUND_ONLY)
+ )
+ PermGrantState.PERMS_DENIED ->
+ groupGrantStates[Category.DENIED]!!.add(
+ GroupUiInfo(groupName, isSystem)
+ )
+ PermGrantState.PERMS_ASK ->
+ groupGrantStates[Category.ASK]!!.add(
+ GroupUiInfo(groupName, isSystem)
+ )
}
- PermGrantState.PERMS_ALLOWED_ALWAYS -> groupGrantStates[
- Category.ALLOWED]!!.add(GroupUiInfo(groupName, isSystem,
- PermSubtitle.BACKGROUND))
- PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY -> groupGrantStates[
- Category.ALLOWED]!!.add(GroupUiInfo(groupName, isSystem,
- PermSubtitle.FOREGROUND_ONLY))
- PermGrantState.PERMS_DENIED -> groupGrantStates[Category.DENIED]!!.add(
- GroupUiInfo(groupName, isSystem))
- PermGrantState.PERMS_ASK -> groupGrantStates[Category.ASK]!!.add(
- GroupUiInfo(groupName, isSystem))
}
}
- }
- value = groupGrantStates
+ value = groupGrantStates
+ }
}
- }
// TODO 206455664: remove once issue is identified
fun logLiveDataState() {
- Log.i(LOG_TAG, "Overall liveData isStale: ${packagePermGroupsLiveData.isStale}, " +
+ Log.i(
+ LOG_TAG,
+ "Overall liveData isStale: ${packagePermGroupsLiveData.isStale}, " +
"isInitialized: ${packagePermGroupsLiveData.isInitialized}, " +
- "value: ${packagePermGroupsLiveData.value}")
- Log.i(LOG_TAG, "AutoRevoke liveData isStale: ${autoRevokeLiveData.isStale}, " +
+ "value: ${packagePermGroupsLiveData.value}"
+ )
+ Log.i(
+ LOG_TAG,
+ "AutoRevoke liveData isStale: ${autoRevokeLiveData.isStale}, " +
"isInitialized: ${autoRevokeLiveData.isInitialized}, " +
- "value: ${autoRevokeLiveData.value}")
- Log.i(LOG_TAG, "PackagePerms liveData isStale: ${packagePermsLiveData.isStale}, " +
+ "value: ${autoRevokeLiveData.value}"
+ )
+ Log.i(
+ LOG_TAG,
+ "PackagePerms liveData isStale: ${packagePermsLiveData.isStale}, " +
"isInitialized: ${packagePermsLiveData.isInitialized}, " +
- "value: ${packagePermsLiveData.value}")
- Log.i(LOG_TAG, "FullStorage liveData isStale: ${fullStoragePermsLiveData.isStale}, " +
+ "value: ${packagePermsLiveData.value}"
+ )
+ Log.i(
+ LOG_TAG,
+ "FullStorage liveData isStale: ${fullStoragePermsLiveData.isStale}, " +
"isInitialized: ${fullStoragePermsLiveData.isInitialized}, " +
- "value size: ${fullStoragePermsLiveData.value?.size}")
+ "value size: ${fullStoragePermsLiveData.value?.size}"
+ )
for ((group, liveData) in appPermGroupUiInfoLiveDatas) {
- Log.i(LOG_TAG, "$group ui liveData isStale: ${liveData.isStale}, " +
+ Log.i(
+ LOG_TAG,
+ "$group ui liveData isStale: ${liveData.isStale}, " +
"isInitialized: ${liveData.isInitialized}, " +
- "value size: ${liveData.value}")
+ "value size: ${liveData.value}"
+ )
}
}
@@ -233,26 +263,33 @@ class AppPermissionGroupsViewModel(
val lightPackageInfo = LightPackageInfoLiveData[packageName, user].getInitializedValue()
if (lightPackageInfo != null) {
- Log.i(LOG_TAG, "sessionId $sessionId setting auto revoke enabled to $enabled for" +
- "$packageName $user")
- val tag = if (enabled) {
- APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__SWITCH_ENABLED
- } else {
- APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__SWITCH_DISABLED
- }
+ Log.i(
+ LOG_TAG,
+ "sessionId $sessionId setting auto revoke enabled to $enabled for" +
+ "$packageName $user"
+ )
+ val tag =
+ if (enabled) {
+ APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__SWITCH_ENABLED
+ } else {
+ APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__SWITCH_DISABLED
+ }
PermissionControllerStatsLog.write(
- APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION, sessionId,
- lightPackageInfo.uid, packageName, tag)
-
- val mode = if (enabled) {
- MODE_ALLOWED
- } else {
- MODE_IGNORED
- }
+ APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION,
+ sessionId,
+ lightPackageInfo.uid,
+ packageName,
+ tag
+ )
+
+ val mode =
+ if (enabled) {
+ MODE_ALLOWED
+ } else {
+ MODE_IGNORED
+ }
aom.setUidMode(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, lightPackageInfo.uid, mode)
- if (isHibernationEnabled() &&
- SdkLevel.isAtLeastSv2() &&
- !enabled) {
+ if (isHibernationEnabled() && SdkLevel.isAtLeastSv2() && !enabled) {
// Only unhibernate on S_V2+ to have consistent toggle behavior w/ Settings
val ahm = app.getSystemService(AppHibernationManager::class.java)!!
ahm.setHibernatingForUser(packageName, false)
@@ -281,13 +318,17 @@ class AppPermissionGroupsViewModel(
return
}
- val aggregateDataFilterBeginDays = if (KotlinUtils.is7DayToggleEnabled())
- AGGREGATE_DATA_FILTER_BEGIN_DAYS_7 else AGGREGATE_DATA_FILTER_BEGIN_DAYS_1
+ val aggregateDataFilterBeginDays =
+ if (KotlinUtils.is7DayToggleEnabled()) AGGREGATE_DATA_FILTER_BEGIN_DAYS_7
+ else AGGREGATE_DATA_FILTER_BEGIN_DAYS_1
accessTime.clear()
- val filterTimeBeginMillis = max(System.currentTimeMillis() -
- TimeUnit.DAYS.toMillis(aggregateDataFilterBeginDays.toLong()),
- Instant.EPOCH.toEpochMilli())
+ val filterTimeBeginMillis =
+ max(
+ System.currentTimeMillis() -
+ TimeUnit.DAYS.toMillis(aggregateDataFilterBeginDays.toLong()),
+ Instant.EPOCH.toEpochMilli()
+ )
val numApps: Int = appPermissionUsages.size
for (appIndex in 0 until numApps) {
val appUsage: AppPermissionUsage = appPermissionUsages[appIndex]
@@ -307,96 +348,128 @@ class AppPermissionGroupsViewModel(
// We might have another AppPermissionUsage entry that's of the same packageName
// but with a different uid. In that case, we want to grab the max lastAccessTime
// as the last usage to show.
- lastAccessTime = Math.max(
+ lastAccessTime =
+ Math.max(
accessTime.getOrDefault(groupName, Instant.EPOCH.toEpochMilli()),
- lastAccessTime)
+ lastAccessTime
+ )
accessTime[groupName] = lastAccessTime
}
}
}
- fun getPreferenceSummary(groupInfo: GroupUiInfo, context: Context, lastAccessTime: Long?):
- String {
- val summaryTimestamp = Utils
- .getPermissionLastAccessSummaryTimestamp(
- lastAccessTime, context, groupInfo.groupName)
+ fun getPreferenceSummary(
+ groupInfo: GroupUiInfo,
+ context: Context,
+ lastAccessTime: Long?
+ ): String {
+ val summaryTimestamp =
+ Utils.getPermissionLastAccessSummaryTimestamp(
+ lastAccessTime,
+ context,
+ groupInfo.groupName
+ )
@AppPermsLastAccessType val lastAccessType: Int = summaryTimestamp.second
return when (groupInfo.subtitle) {
PermSubtitle.BACKGROUND ->
when (lastAccessType) {
- Utils.LAST_24H_CONTENT_PROVIDER -> context.getString(
- R.string.app_perms_content_provider_24h_background)
- Utils.LAST_7D_CONTENT_PROVIDER -> context.getString(
- R.string.app_perms_content_provider_7d_background)
- Utils.LAST_24H_SENSOR_TODAY -> context.getString(
+ Utils.LAST_24H_CONTENT_PROVIDER ->
+ context.getString(R.string.app_perms_content_provider_24h_background)
+ Utils.LAST_7D_CONTENT_PROVIDER ->
+ context.getString(R.string.app_perms_content_provider_7d_background)
+ Utils.LAST_24H_SENSOR_TODAY ->
+ context.getString(
R.string.app_perms_24h_access_background,
- summaryTimestamp.first)
- Utils.LAST_24H_SENSOR_YESTERDAY -> context.getString(
+ summaryTimestamp.first
+ )
+ Utils.LAST_24H_SENSOR_YESTERDAY ->
+ context.getString(
R.string.app_perms_24h_access_yest_background,
- summaryTimestamp.first)
- Utils.LAST_7D_SENSOR -> context.getString(
+ summaryTimestamp.first
+ )
+ Utils.LAST_7D_SENSOR ->
+ context.getString(
R.string.app_perms_7d_access_background,
- summaryTimestamp.third, summaryTimestamp.first)
- Utils.NOT_IN_LAST_7D -> context.getString(
- R.string.permission_subtitle_background)
- else -> context.getString(
- R.string.permission_subtitle_background)
+ summaryTimestamp.third,
+ summaryTimestamp.first
+ )
+ Utils.NOT_IN_LAST_7D ->
+ context.getString(R.string.permission_subtitle_background)
+ else -> context.getString(R.string.permission_subtitle_background)
}
PermSubtitle.MEDIA_ONLY ->
when (lastAccessType) {
- Utils.LAST_24H_CONTENT_PROVIDER -> context.getString(
- R.string.app_perms_content_provider_24h_media_only)
- Utils.LAST_7D_CONTENT_PROVIDER -> context.getString(
- R.string.app_perms_content_provider_7d_media_only)
- Utils.LAST_24H_SENSOR_TODAY -> context.getString(
+ Utils.LAST_24H_CONTENT_PROVIDER ->
+ context.getString(R.string.app_perms_content_provider_24h_media_only)
+ Utils.LAST_7D_CONTENT_PROVIDER ->
+ context.getString(R.string.app_perms_content_provider_7d_media_only)
+ Utils.LAST_24H_SENSOR_TODAY ->
+ context.getString(
R.string.app_perms_24h_access_media_only,
- summaryTimestamp.first)
- Utils.LAST_24H_SENSOR_YESTERDAY -> context.getString(
+ summaryTimestamp.first
+ )
+ Utils.LAST_24H_SENSOR_YESTERDAY ->
+ context.getString(
R.string.app_perms_24h_access_yest_media_only,
- summaryTimestamp.first)
- Utils.LAST_7D_SENSOR -> context.getString(
+ summaryTimestamp.first
+ )
+ Utils.LAST_7D_SENSOR ->
+ context.getString(
R.string.app_perms_7d_access_media_only,
- summaryTimestamp.third, summaryTimestamp.first)
- Utils.NOT_IN_LAST_7D -> context.getString(
- R.string.permission_subtitle_media_only)
+ summaryTimestamp.third,
+ summaryTimestamp.first
+ )
+ Utils.NOT_IN_LAST_7D ->
+ context.getString(R.string.permission_subtitle_media_only)
else -> context.getString(R.string.permission_subtitle_media_only)
}
PermSubtitle.ALL_FILES ->
when (lastAccessType) {
- Utils.LAST_24H_CONTENT_PROVIDER -> context.getString(
- R.string.app_perms_content_provider_24h_all_files)
- Utils.LAST_7D_CONTENT_PROVIDER -> context.getString(
- R.string.app_perms_content_provider_7d_all_files)
- Utils.LAST_24H_SENSOR_TODAY -> context.getString(
+ Utils.LAST_24H_CONTENT_PROVIDER ->
+ context.getString(R.string.app_perms_content_provider_24h_all_files)
+ Utils.LAST_7D_CONTENT_PROVIDER ->
+ context.getString(R.string.app_perms_content_provider_7d_all_files)
+ Utils.LAST_24H_SENSOR_TODAY ->
+ context.getString(
R.string.app_perms_24h_access_all_files,
- summaryTimestamp.first)
- Utils.LAST_24H_SENSOR_YESTERDAY -> context.getString(
+ summaryTimestamp.first
+ )
+ Utils.LAST_24H_SENSOR_YESTERDAY ->
+ context.getString(
R.string.app_perms_24h_access_yest_all_files,
- summaryTimestamp.first)
- Utils.LAST_7D_SENSOR -> context.getString(
+ summaryTimestamp.first
+ )
+ Utils.LAST_7D_SENSOR ->
+ context.getString(
R.string.app_perms_7d_access_all_files,
- summaryTimestamp.third, summaryTimestamp.first)
- Utils.NOT_IN_LAST_7D -> context.getString(
- R.string.permission_subtitle_all_files)
+ summaryTimestamp.third,
+ summaryTimestamp.first
+ )
+ Utils.NOT_IN_LAST_7D ->
+ context.getString(R.string.permission_subtitle_all_files)
else -> context.getString(R.string.permission_subtitle_all_files)
}
else ->
// PermSubtitle.FOREGROUND_ONLY should fall into this as well
when (lastAccessType) {
- Utils.LAST_24H_CONTENT_PROVIDER -> context.getString(
- R.string.app_perms_content_provider_24h)
- Utils.LAST_7D_CONTENT_PROVIDER -> context.getString(
- R.string.app_perms_content_provider_7d)
- Utils.LAST_24H_SENSOR_TODAY -> context.getString(
- R.string.app_perms_24h_access,
- summaryTimestamp.first)
- Utils.LAST_24H_SENSOR_YESTERDAY -> context.getString(
+ Utils.LAST_24H_CONTENT_PROVIDER ->
+ context.getString(R.string.app_perms_content_provider_24h)
+ Utils.LAST_7D_CONTENT_PROVIDER ->
+ context.getString(R.string.app_perms_content_provider_7d)
+ Utils.LAST_24H_SENSOR_TODAY ->
+ context.getString(R.string.app_perms_24h_access, summaryTimestamp.first)
+ Utils.LAST_24H_SENSOR_YESTERDAY ->
+ context.getString(
R.string.app_perms_24h_access_yest,
- summaryTimestamp.first)
- Utils.LAST_7D_SENSOR -> context.getString(
+ summaryTimestamp.first
+ )
+ Utils.LAST_7D_SENSOR ->
+ context.getString(
R.string.app_perms_7d_access,
- summaryTimestamp.third, summaryTimestamp.first)
+ summaryTimestamp.third,
+ summaryTimestamp.first
+ )
Utils.NOT_IN_LAST_7D -> ""
else -> ""
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
index 99b40d8a7..971542e2b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
@@ -20,6 +20,7 @@ package com.android.permissioncontroller.permission.ui.model
import android.Manifest
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
import android.Manifest.permission_group.READ_MEDIA_VISUAL
import android.annotation.SuppressLint
import android.app.Activity
@@ -28,19 +29,14 @@ import android.app.AppOpsManager.MODE_ALLOWED
import android.app.AppOpsManager.MODE_ERRORED
import android.app.AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE
import android.app.Application
-import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.UserHandle
-import android.provider.MediaStore
import android.util.Log
-import androidx.activity.result.ActivityResultLauncher
-import androidx.activity.result.contract.ActivityResultContract
import androidx.annotation.ChecksSdkIntAtLeast
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
-import androidx.core.util.Consumer
import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
@@ -56,14 +52,13 @@ import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState
import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData
-import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
import com.android.permissioncontroller.permission.data.get
+import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission
import com.android.permissioncontroller.permission.service.PermissionChangeStorageImpl
import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl
-import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW_ALWAYS
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW_FOREGROUND
@@ -73,12 +68,13 @@ import com.android.permissioncontroller.permission.ui.model.AppPermissionViewMod
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.DENY_FOREGROUND
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.LOCATION_ACCURACY
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.SELECT_PHOTOS
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs
import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity
import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity.EXTRA_SHOULD_SHOW_SETTINGS_SECTION
import com.android.permissioncontroller.permission.utils.KotlinUtils
-import com.android.permissioncontroller.permission.utils.KotlinUtils.getDefaultPrecision
import com.android.permissioncontroller.permission.utils.KotlinUtils.isLocationAccuracyEnabled
import com.android.permissioncontroller.permission.utils.KotlinUtils.isPhotoPickerPromptEnabled
+import com.android.permissioncontroller.permission.utils.KotlinUtils.openPhotoPickerForApp
import com.android.permissioncontroller.permission.utils.LocationUtils
import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.PermissionMapping.getPartialStorageGrantPermissionsForGroup
@@ -112,7 +108,6 @@ class AppPermissionViewModel(
companion object {
private val LOG_TAG = AppPermissionViewModel::class.java.simpleName
private const val DEVICE_PROFILE_ROLE_PREFIX = "android.app.role"
- const val PHOTO_PICKER_REQUEST_CODE = 1
}
interface ConfirmDialogShowingFragment {
@@ -134,15 +129,16 @@ class AppPermissionViewModel(
GRANT_BOTH(GRANT_FOREGROUND.value or GRANT_BACKGROUND.value),
REVOKE_BOTH(REVOKE_FOREGROUND.value or REVOKE_BACKGROUND.value),
GRANT_FOREGROUND_ONLY(GRANT_FOREGROUND.value or REVOKE_BACKGROUND.value),
- GRANT_All_FILE_ACCESS(1 shl 4),
+ GRANT_ALL_FILE_ACCESS(1 shl 4),
GRANT_FINE_LOCATION(1 shl 5),
REVOKE_FINE_LOCATION(1 shl 6),
GRANT_STORAGE_SUPERGROUP(1 shl 7),
REVOKE_STORAGE_SUPERGROUP(1 shl 8),
GRANT_STORAGE_SUPERGROUP_CONFIRMED(
- GRANT_STORAGE_SUPERGROUP.value or GRANT_FOREGROUND.value),
+ GRANT_STORAGE_SUPERGROUP.value or GRANT_FOREGROUND.value
+ ),
REVOKE_STORAGE_SUPERGROUP_CONFIRMED(REVOKE_STORAGE_SUPERGROUP.value or REVOKE_BOTH.value),
- PHOTOS_SELECTED( 1 shl 9);
+ PHOTOS_SELECTED(1 shl 9);
infix fun andValue(other: ChangeRequest): Int {
return value and other.value
@@ -158,89 +154,86 @@ class AppPermissionViewModel(
DENY(5),
DENY_FOREGROUND(6),
LOCATION_ACCURACY(7),
- SELECT_PHOTOS( 8);
+ SELECT_PHOTOS(8)
}
private val isStorageAndLessThanT =
permGroupName == Manifest.permission_group.STORAGE && !SdkLevel.isAtLeastT()
private var hasConfirmedRevoke = false
private var lightAppPermGroup: LightAppPermGroup? = null
- private var photoPickerLauncher: ActivityResultLauncher<Unit>? = null
- private var photoPickerResultConsumer: Consumer<Int>? = null
private val mediaStorageSupergroupPermGroups = mutableMapOf<String, LightAppPermGroup>()
/* Whether the current ViewModel is Location permission with both Coarse and Fine */
private var shouldShowLocationAccuracy: Boolean? = null
- /**
- * A livedata which determines which detail string, if any, should be shown
- */
+ /** A livedata which determines which detail string, if any, should be shown */
val detailResIdLiveData = MutableLiveData<Pair<Int, Int?>>()
- /**
- * A livedata which stores the device admin, if there is one
- */
+ /** A livedata which stores the device admin, if there is one */
val showAdminSupportLiveData = MutableLiveData<RestrictedLockUtils.EnforcedAdmin>()
- /**
- * A livedata for determining the display state of safety label information
- */
- val showPermissionRationaleLiveData = object : SmartUpdateMediatorLiveData<Boolean>() {
- private val safetyLabelInfoLiveData = if (SdkLevel.isAtLeastU()) {
- SafetyLabelInfoLiveData[packageName, user]
- } else {
- null
- }
+ /** A livedata for determining the display state of safety label information */
+ val showPermissionRationaleLiveData =
+ object : SmartUpdateMediatorLiveData<Boolean>() {
+ private val safetyLabelInfoLiveData =
+ if (SdkLevel.isAtLeastU()) {
+ SafetyLabelInfoLiveData[packageName, user]
+ } else {
+ null
+ }
- init {
- if (safetyLabelInfoLiveData != null &&
- PermissionMapping.isSafetyLabelAwarePermissionGroup(permGroupName)) {
- addSource(safetyLabelInfoLiveData) { update() }
- } else {
- value = false
+ init {
+ if (
+ safetyLabelInfoLiveData != null &&
+ PermissionMapping.isSafetyLabelAwarePermissionGroup(permGroupName)
+ ) {
+ addSource(safetyLabelInfoLiveData) { update() }
+ } else {
+ value = false
+ }
}
- }
- override fun onUpdate() {
- if (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale) {
- return
- }
+ override fun onUpdate() {
+ if (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale) {
+ return
+ }
- val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel
- if (safetyLabel == null) {
- value = false
- return
- }
+ val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel
+ if (safetyLabel == null) {
+ value = false
+ return
+ }
- value = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(
- safetyLabel, permGroupName).any()
+ value =
+ SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(
+ safetyLabel,
+ permGroupName
+ )
+ .any()
+ }
}
- }
- /**
- * A livedata which determines which detail string, if any, should be shown
- */
- val fullStorageStateLiveData = object : SmartUpdateMediatorLiveData<FullStoragePackageState>() {
- init {
- if (isStorageAndLessThanT) {
- addSource(FullStoragePermissionAppsLiveData) {
- update()
+ /** A livedata which determines which detail string, if any, should be shown */
+ val fullStorageStateLiveData =
+ object : SmartUpdateMediatorLiveData<FullStoragePackageState>() {
+ init {
+ if (isStorageAndLessThanT) {
+ addSource(FullStoragePermissionAppsLiveData) { update() }
+ } else {
+ value = null
}
- } else {
- value = null
}
- }
- override fun onUpdate() {
- for (state in FullStoragePermissionAppsLiveData.value ?: return) {
- if (state.packageName == packageName && state.user == user) {
- value = state
- return
+ override fun onUpdate() {
+ for (state in FullStoragePermissionAppsLiveData.value ?: return) {
+ if (state.packageName == packageName && state.user == user) {
+ value = state
+ return
+ }
}
+ value = null
+ return
}
- value = null
- return
}
- }
data class ButtonState(
var isChecked: Boolean,
@@ -251,182 +244,211 @@ class AppPermissionViewModel(
constructor() : this(false, true, false, null)
}
- /**
- * A livedata which computes the state of the radio buttons
- */
- val buttonStateLiveData = object :
- SmartUpdateMediatorLiveData<@JvmSuppressWildcards Map<ButtonType, ButtonState>>() {
+ /** A livedata which computes the state of the radio buttons */
+ val buttonStateLiveData =
+ object : SmartUpdateMediatorLiveData<@JvmSuppressWildcards Map<ButtonType, ButtonState>>() {
- private val appPermGroupLiveData = LightAppPermGroupLiveData[packageName, permGroupName,
- user]
- private val mediaStorageSupergroupLiveData =
- mutableMapOf<String, LightAppPermGroupLiveData>()
+ private val appPermGroupLiveData =
+ LightAppPermGroupLiveData[packageName, permGroupName, user]
+ private val mediaStorageSupergroupLiveData =
+ mutableMapOf<String, LightAppPermGroupLiveData>()
- init {
+ init {
+ addSource(appPermGroupLiveData) { appPermGroup ->
+ lightAppPermGroup = appPermGroup
+ if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
+ onMediaPermGroupUpdate(permGroupName, appPermGroup)
+ }
+ if (appPermGroupLiveData.isInitialized && appPermGroup == null) {
+ value = null
+ } else if (appPermGroup != null) {
+ if (isStorageAndLessThanT && !fullStorageStateLiveData.isInitialized) {
+ return@addSource
+ }
+ update()
+ }
+ }
- addSource(appPermGroupLiveData) { appPermGroup ->
- lightAppPermGroup = appPermGroup
- if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
- onMediaPermGroupUpdate(permGroupName, appPermGroup)
+ if (isStorageAndLessThanT) {
+ addSource(fullStorageStateLiveData) { update() }
}
- if (appPermGroupLiveData.isInitialized && appPermGroup == null) {
- value = null
- } else if (appPermGroup != null) {
- if (isStorageAndLessThanT && !fullStorageStateLiveData.isInitialized) {
- return@addSource
+
+ if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
+ for (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
+ val liveData = LightAppPermGroupLiveData[packageName, permGroupName, user]
+ mediaStorageSupergroupLiveData[permGroupName] = liveData
+ }
+ for (permGroupName in mediaStorageSupergroupLiveData.keys) {
+ val liveData = mediaStorageSupergroupLiveData[permGroupName]!!
+ addSource(liveData) { permGroup ->
+ onMediaPermGroupUpdate(permGroupName, permGroup)
+ }
}
- update()
}
+
+ addSource(showPermissionRationaleLiveData) { update() }
}
- if (isStorageAndLessThanT) {
- addSource(fullStorageStateLiveData) {
+ private fun onMediaPermGroupUpdate(
+ permGroupName: String,
+ permGroup: LightAppPermGroup?
+ ) {
+ if (permGroup == null) {
+ mediaStorageSupergroupPermGroups.remove(permGroupName)
+ value = null
+ } else {
+ mediaStorageSupergroupPermGroups[permGroupName] = permGroup
update()
}
}
- if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
- for (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
- val liveData = LightAppPermGroupLiveData[packageName, permGroupName, user]
- mediaStorageSupergroupLiveData[permGroupName] = liveData
- }
- for (permGroupName in mediaStorageSupergroupLiveData.keys) {
- val liveData = mediaStorageSupergroupLiveData[permGroupName]!!
- addSource(liveData) { permGroup ->
- onMediaPermGroupUpdate(permGroupName, permGroup)
+ override fun onUpdate() {
+ val group = appPermGroupLiveData.value ?: return
+ for (mediaGroupLiveData in mediaStorageSupergroupLiveData.values) {
+ if (!mediaGroupLiveData.isInitialized) {
+ return
}
}
- }
-
- addSource(showPermissionRationaleLiveData) {
- update()
- }
- }
-
- private fun onMediaPermGroupUpdate(permGroupName: String, permGroup: LightAppPermGroup?) {
- if (permGroup == null) {
- mediaStorageSupergroupPermGroups.remove(permGroupName)
- value = null
- } else {
- mediaStorageSupergroupPermGroups[permGroupName] = permGroup
- update()
- }
- }
- override fun onUpdate() {
- val group = appPermGroupLiveData.value ?: return
- for (mediaGroupLiveData in mediaStorageSupergroupLiveData.values) {
- if (!mediaGroupLiveData.isInitialized) {
+ if (!showPermissionRationaleLiveData.isInitialized) {
return
}
- }
- if (!showPermissionRationaleLiveData.isInitialized) {
- return
- }
-
- val admin = RestrictedLockUtils.getProfileOrDeviceOwner(app, user)
-
- val allowedState = ButtonState()
- val allowedAlwaysState = ButtonState()
- val allowedForegroundState = ButtonState()
- val askOneTimeState = ButtonState()
- val askState = ButtonState()
- val deniedState = ButtonState()
- val deniedForegroundState = ButtonState()
- val selectState = ButtonState()
-
- askOneTimeState.isShown = group.foreground.isGranted && group.isOneTime
- askState.isShown = PermissionMapping.supportsOneTimeGrant(permGroupName) &&
- !(group.foreground.isGranted && group.isOneTime)
- deniedState.isShown = true
-
- if (group.hasPermWithBackgroundMode) {
- // Background / Foreground / Deny case
- allowedForegroundState.isShown = true
- if (group.hasBackgroundGroup) {
- allowedAlwaysState.isShown = true
- }
+ val admin = RestrictedLockUtils.getProfileOrDeviceOwner(app, user)
+
+ val allowedState = ButtonState()
+ val allowedAlwaysState = ButtonState()
+ val allowedForegroundState = ButtonState()
+ val askOneTimeState = ButtonState()
+ val askState = ButtonState()
+ val deniedState = ButtonState()
+ val deniedForegroundState = ButtonState()
+ val selectState = ButtonState()
+
+ askOneTimeState.isShown = group.foreground.isGranted && group.isOneTime
+ askState.isShown =
+ PermissionMapping.supportsOneTimeGrant(permGroupName) &&
+ !(group.foreground.isGranted && group.isOneTime)
+ deniedState.isShown = true
- allowedAlwaysState.isChecked = group.background.isGranted &&
- group.foreground.isGranted && !group.background.isOneTime
- allowedForegroundState.isChecked = group.foreground.isGranted &&
- (!group.background.isGranted || group.background.isOneTime) &&
- !group.foreground.isOneTime
- askState.isChecked = !group.foreground.isGranted && group.isOneTime
- askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime
- askOneTimeState.isShown = askOneTimeState.isChecked
- deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime
- if (applyFixToForegroundBackground(group, group.foreground.isSystemFixed,
- group.background.isSystemFixed, allowedAlwaysState,
- allowedForegroundState, askState, deniedState,
- deniedForegroundState) ||
- applyFixToForegroundBackground(group, group.foreground.isPolicyFixed,
- group.background.isPolicyFixed, allowedAlwaysState,
- allowedForegroundState, askState, deniedState,
- deniedForegroundState)) {
- showAdminSupportLiveData.value = admin
- val detailId = getDetailResIdForFixedByPolicyPermissionGroup(group,
- admin != null)
- if (detailId != 0) {
- detailResIdLiveData.value = detailId to null
+ if (group.hasPermWithBackgroundMode) {
+ // Background / Foreground / Deny case
+ allowedForegroundState.isShown = true
+ if (group.hasBackgroundGroup) {
+ allowedAlwaysState.isShown = true
}
- } else if (Utils.areGroupPermissionsIndividuallyControlled(app, permGroupName)) {
- val detailId = getIndividualPermissionDetailResId(group)
- detailResIdLiveData.value = detailId.first to detailId.second
- }
- } else if (KotlinUtils.isPhotoPickerPromptEnabled() &&
- group.permGroupName == READ_MEDIA_VISUAL &&
- group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU) {
- // Allow / Select Photos / Deny case
- allowedState.isShown = true
- deniedState.isShown = true
- selectState.isShown = true
- deniedState.isChecked = !group.isGranted
- selectState.isChecked = isPartialStorageGrant(group)
- allowedState.isChecked = group.isGranted && !isPartialStorageGrant(group)
- } else {
- // Allow / Deny case
- allowedState.isShown = true
-
- allowedState.isChecked = group.foreground.isGranted && !group.foreground.isOneTime
- askState.isChecked = !group.foreground.isGranted && group.isOneTime
- askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime
- askOneTimeState.isShown = askOneTimeState.isChecked
- deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime
-
- if (group.foreground.isPolicyFixed || group.foreground.isSystemFixed) {
- allowedState.isEnabled = false
- askState.isEnabled = false
- deniedState.isEnabled = false
- showAdminSupportLiveData.value = admin
- val detailId = getDetailResIdForFixedByPolicyPermissionGroup(group,
- admin != null)
- if (detailId != 0) {
- detailResIdLiveData.value = detailId to null
+ allowedAlwaysState.isChecked =
+ group.background.isGranted &&
+ group.foreground.isGranted &&
+ !group.background.isOneTime
+ allowedForegroundState.isChecked =
+ group.foreground.isGranted &&
+ (!group.background.isGranted || group.background.isOneTime) &&
+ !group.foreground.isOneTime
+ askState.isChecked = !group.foreground.isGranted && group.isOneTime
+ askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime
+ askOneTimeState.isShown = askOneTimeState.isChecked
+ deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime
+ if (
+ applyFixToForegroundBackground(
+ group,
+ group.foreground.isSystemFixed,
+ group.background.isSystemFixed,
+ allowedAlwaysState,
+ allowedForegroundState,
+ askState,
+ deniedState,
+ deniedForegroundState
+ ) ||
+ applyFixToForegroundBackground(
+ group,
+ group.foreground.isPolicyFixed,
+ group.background.isPolicyFixed,
+ allowedAlwaysState,
+ allowedForegroundState,
+ askState,
+ deniedState,
+ deniedForegroundState
+ )
+ ) {
+ showAdminSupportLiveData.value = admin
+ val detailId =
+ getDetailResIdForFixedByPolicyPermissionGroup(group, admin != null)
+ if (detailId != 0) {
+ detailResIdLiveData.value = detailId to null
+ }
+ } else if (
+ Utils.areGroupPermissionsIndividuallyControlled(app, permGroupName)
+ ) {
+ val detailId = getIndividualPermissionDetailResId(group)
+ detailResIdLiveData.value = detailId.first to detailId.second
+ }
+ } else if (
+ shouldShowPhotoPickerPromptForApp(group) &&
+ group.permGroupName == READ_MEDIA_VISUAL
+ ) {
+ // Allow / Select Photos / Deny case
+ allowedState.isShown = true
+ deniedState.isShown = true
+ selectState.isShown = true
+
+ deniedState.isChecked = !group.isGranted
+ selectState.isChecked = isPartialStorageGrant(group)
+ allowedState.isChecked = group.isGranted && !isPartialStorageGrant(group)
+ if (group.foreground.isPolicyFixed || group.foreground.isSystemFixed) {
+ allowedState.isEnabled = false
+ selectState.isEnabled = false
+ deniedState.isEnabled = false
+ showAdminSupportLiveData.value = admin
+ val detailId =
+ getDetailResIdForFixedByPolicyPermissionGroup(group, admin != null)
+ if (detailId != 0) {
+ detailResIdLiveData.value = detailId to null
+ }
+ }
+ } else {
+ // Allow / Deny case
+ allowedState.isShown = true
+
+ allowedState.isChecked =
+ group.foreground.isGranted && !group.foreground.isOneTime
+ askState.isChecked = !group.foreground.isGranted && group.isOneTime
+ askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime
+ askOneTimeState.isShown = askOneTimeState.isChecked
+ deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime
+
+ if (group.foreground.isPolicyFixed || group.foreground.isSystemFixed) {
+ allowedState.isEnabled = false
+ askState.isEnabled = false
+ deniedState.isEnabled = false
+ showAdminSupportLiveData.value = admin
+ val detailId =
+ getDetailResIdForFixedByPolicyPermissionGroup(group, admin != null)
+ if (detailId != 0) {
+ detailResIdLiveData.value = detailId to null
+ }
+ }
+ if (isForegroundGroupSpecialCase(permGroupName)) {
+ allowedForegroundState.isShown = true
+ allowedState.isShown = false
+ allowedForegroundState.isChecked = allowedState.isChecked
+ allowedForegroundState.isEnabled = allowedState.isEnabled
}
}
- if (isForegroundGroupSpecialCase(permGroupName)) {
- allowedForegroundState.isShown = true
- allowedState.isShown = false
- allowedForegroundState.isChecked = allowedState.isChecked
- allowedForegroundState.isEnabled = allowedState.isEnabled
+ if (group.packageInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ // Pre-M app's can't ask for runtime permissions
+ askState.isShown = false
+ deniedState.isChecked = askState.isChecked || deniedState.isChecked
+ deniedForegroundState.isChecked =
+ askState.isChecked || deniedForegroundState.isChecked
}
- }
- if (group.packageInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- // Pre-M app's can't ask for runtime permissions
- askState.isShown = false
- deniedState.isChecked = askState.isChecked || deniedState.isChecked
- deniedForegroundState.isChecked = askState.isChecked ||
- deniedForegroundState.isChecked
- }
- val storageState = fullStorageStateLiveData.value
- if (isStorageAndLessThanT && storageState?.isLegacy != true) {
- val allowedAllFilesState = allowedAlwaysState
- val allowedMediaOnlyState = allowedForegroundState
- if (storageState != null) {
+ val storageState = fullStorageStateLiveData.value
+ if (isStorageAndLessThanT && storageState?.isLegacy != true) {
+ val allowedAllFilesState = allowedAlwaysState
+ val allowedMediaOnlyState = allowedForegroundState
+ if (storageState != null) {
// Set up the tri state permission for storage
allowedAllFilesState.isEnabled = allowedState.isEnabled
allowedAllFilesState.isShown = true
@@ -434,62 +456,64 @@ class AppPermissionViewModel(
allowedAllFilesState.isChecked = true
deniedState.isChecked = false
}
- } else {
- allowedAllFilesState.isEnabled = false
- allowedAllFilesState.isShown = false
+ } else {
+ allowedAllFilesState.isEnabled = false
+ allowedAllFilesState.isShown = false
+ }
+ allowedMediaOnlyState.isShown = true
+ allowedMediaOnlyState.isEnabled = allowedState.isEnabled
+ allowedMediaOnlyState.isChecked =
+ allowedState.isChecked && storageState?.isGranted != true
+ allowedState.isChecked = false
+ allowedState.isShown = false
}
- allowedMediaOnlyState.isShown = true
- allowedMediaOnlyState.isEnabled = allowedState.isEnabled
- allowedMediaOnlyState.isChecked = allowedState.isChecked &&
- storageState?.isGranted != true
- allowedState.isChecked = false
- allowedState.isShown = false
- }
- if (shouldShowLocationAccuracy == null) {
- shouldShowLocationAccuracy = isLocationAccuracyEnabled() &&
- group.permissions.containsKey(ACCESS_FINE_LOCATION)
- }
- val locationAccuracyState = ButtonState(isFineLocationChecked(group),
- true, false, null)
- if (shouldShowLocationAccuracy == true && !deniedState.isChecked) {
- locationAccuracyState.isShown = true
- }
- if (group.foreground.isSystemFixed || group.foreground.isPolicyFixed) {
- locationAccuracyState.isEnabled = false
- }
+ if (shouldShowLocationAccuracy == null) {
+ shouldShowLocationAccuracy =
+ isLocationAccuracyEnabled() &&
+ group.permissions.containsKey(ACCESS_FINE_LOCATION)
+ }
+ val locationAccuracyState =
+ ButtonState(isFineLocationChecked(group), true, false, null)
+ if (shouldShowLocationAccuracy == true && !deniedState.isChecked) {
+ locationAccuracyState.isShown = true
+ }
+ if (group.foreground.isSystemFixed || group.foreground.isPolicyFixed) {
+ locationAccuracyState.isEnabled = false
+ }
- if (value == null) {
- logAppPermissionFragmentViewed()
- }
+ if (value == null) {
+ logAppPermissionFragmentViewed()
+ }
- value = mapOf(
- ALLOW to allowedState, ALLOW_ALWAYS to allowedAlwaysState,
- ALLOW_FOREGROUND to allowedForegroundState, ASK_ONCE to askOneTimeState,
- ASK to askState, DENY to deniedState, DENY_FOREGROUND to deniedForegroundState,
- LOCATION_ACCURACY to locationAccuracyState, SELECT_PHOTOS to selectState)
+ value =
+ mapOf(
+ ALLOW to allowedState,
+ ALLOW_ALWAYS to allowedAlwaysState,
+ ALLOW_FOREGROUND to allowedForegroundState,
+ ASK_ONCE to askOneTimeState,
+ ASK to askState,
+ DENY to deniedState,
+ DENY_FOREGROUND to deniedForegroundState,
+ LOCATION_ACCURACY to locationAccuracyState,
+ SELECT_PHOTOS to selectState
+ )
+ }
}
- }
- fun registerPhotoPickerResultIfNeeded(fragment: Fragment) {
- if (permGroupName != READ_MEDIA_VISUAL) {
- return
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
+ private fun shouldShowPhotoPickerPromptForApp(group: LightAppPermGroup): Boolean {
+ if (
+ !isPhotoPickerPromptEnabled() ||
+ group.packageInfo.targetSdkVersion < Build.VERSION_CODES.TIRAMISU
+ ) {
+ return false
}
- photoPickerLauncher = fragment.registerForActivityResult(
- object : ActivityResultContract<Unit, Int>() {
- override fun parseResult(resultCode: Int, intent: Intent?): Int {
- return resultCode
- }
-
- override fun createIntent(context: Context, input: Unit): Intent {
- return Intent(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP)
- .putExtra(Intent.EXTRA_UID, lightAppPermGroup?.packageInfo?.uid)
- .setType(KotlinUtils.getMimeTypeForPermissions(
- lightAppPermGroup?.foregroundPermNames ?: emptyList()))
- }
- }) { result ->
- photoPickerResultConsumer?.accept(result)
+ if (group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ return true
}
+ val userSelectedPerm = group.permissions[READ_MEDIA_VISUAL_USER_SELECTED] ?: return false
+ return !userSelectedPerm.isImplicit
}
private fun isFineLocationChecked(group: LightAppPermGroup): Boolean {
@@ -501,14 +525,17 @@ class AppPermissionViewModel(
// 2. Else if FINE or COARSE have the isSelectedLocationAccuracy flag set, then return
// true if FINE isSelectedLocationAccuracy is set.
// 3. Else, return default precision from device config.
- return if (fineLocation.isGrantedIncludingAppOp ||
- coarseLocation.isGrantedIncludingAppOp) {
+ return if (
+ fineLocation.isGrantedIncludingAppOp || coarseLocation.isGrantedIncludingAppOp
+ ) {
fineLocation.isGrantedIncludingAppOp
- } else if (fineLocation.isSelectedLocationAccuracy ||
- coarseLocation.isSelectedLocationAccuracy) {
+ } else if (
+ fineLocation.isSelectedLocationAccuracy || coarseLocation.isSelectedLocationAccuracy
+ ) {
fineLocation.isSelectedLocationAccuracy
} else {
- getDefaultPrecision()
+ // default location precision is true, indicates FINE
+ true
}
}
return false
@@ -517,7 +544,7 @@ class AppPermissionViewModel(
// TODO evanseverson: Actually change mic/camera to be a foreground only permission
private fun isForegroundGroupSpecialCase(permissionGroupName: String): Boolean {
return permissionGroupName.equals(Manifest.permission_group.CAMERA) ||
- permissionGroupName.equals(Manifest.permission_group.MICROPHONE)
+ permissionGroupName.equals(Manifest.permission_group.MICROPHONE)
}
/**
@@ -608,10 +635,12 @@ class AppPermissionViewModel(
logAppPermissionFragmentActionReportedForPermissionGroup(
/* changeId= */ Random().nextLong(),
group,
- APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_RATIONALE)
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_RATIONALE
+ )
}
- val intent = Intent(activity, PermissionRationaleActivity::class.java).apply {
+ val intent =
+ Intent(activity, PermissionRationaleActivity::class.java).apply {
putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
putExtra(Constants.EXTRA_SESSION_ID, sessionId)
@@ -622,6 +651,7 @@ class AppPermissionViewModel(
/**
* Navigate to either the App Permission Groups screen, or the Permission Apps Screen.
+ *
* @param fragment The current fragment
* @param action The action to be taken
* @param args The arguments to pass to the fragment
@@ -635,26 +665,33 @@ class AppPermissionViewModel(
fragment.findNavController().navigateSafe(actionId, args)
}
+ fun openPhotoPicker(fragment: Fragment) {
+ val appPermGroup = lightAppPermGroup ?: return
+ openPhotoPickerForApp(
+ fragment.requireActivity(),
+ appPermGroup.packageInfo.uid,
+ appPermGroup.foregroundPermNames,
+ 0
+ )
+ }
+
/**
* Request to grant/revoke permissions group.
*
* Does <u>not</u> handle:
- *
- * * Individually granted permissions
- * * Permission groups with background permissions
+ * * Individually granted permissions
+ * * Permission groups with background permissions
*
* <u>Does</u> handle:
- *
- * * Default grant permissions
+ * * Default grant permissions
*
* @param setOneTime Whether or not to set this permission as one time
* @param fragment The fragment calling this method
* @param defaultDeny The system which will show the default deny dialog. Usually the same as
- * the fragment.
+ * the fragment.
* @param changeRequest Which permission group (foreground/background/both) should be changed
* @param buttonClicked button which was pressed to initiate the change, one of
- * AppPermissionFragmentActionReported.button_pressed constants
- *
+ * AppPermissionFragmentActionReported.button_pressed constants
* @return The dialogue to show, if applicable, or if the request was processed.
*/
fun requestChange(
@@ -685,8 +722,12 @@ class AppPermissionViewModel(
if (changeRequest == ChangeRequest.REVOKE_FINE_LOCATION) {
if (!group.isOneTime) {
- val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group,
- filterPermissions = listOf(ACCESS_FINE_LOCATION))
+ val newGroup =
+ KotlinUtils.revokeForegroundRuntimePermissions(
+ app,
+ group,
+ filterPermissions = listOf(ACCESS_FINE_LOCATION)
+ )
logPermissionChanges(group, newGroup, buttonClicked)
}
KotlinUtils.setFlagsWhenLocationAccuracyChanged(app, group, false)
@@ -696,10 +737,18 @@ class AppPermissionViewModel(
if (changeRequest == ChangeRequest.PHOTOS_SELECTED) {
val partialGrantPerms = getPartialStorageGrantPermissionsForGroup(group)
val nonSelectedPerms = group.permissions.keys.filter { it !in partialGrantPerms }
- var newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group,
- filterPermissions = nonSelectedPerms)
- newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, newGroup,
- filterPermissions = partialGrantPerms.toList())
+ var newGroup =
+ KotlinUtils.revokeForegroundRuntimePermissions(
+ app,
+ group,
+ filterPermissions = nonSelectedPerms
+ )
+ newGroup =
+ KotlinUtils.grantForegroundRuntimePermissions(
+ app,
+ newGroup,
+ filterPermissions = partialGrantPerms.toList()
+ )
logPermissionChanges(group, newGroup, buttonClicked)
return
}
@@ -713,27 +762,31 @@ class AppPermissionViewModel(
var showCDMWarning = false
if (shouldRevokeForeground && wasForegroundGranted) {
- showDefaultDenyDialog = (group.foreground.isGrantedByDefault ||
+ showDefaultDenyDialog =
+ (group.foreground.isGrantedByDefault ||
!group.supportsRuntimePerms ||
group.hasInstallToRuntimeSplit)
- showGrantedByDefaultWarning = showGrantedByDefaultWarning ||
- group.foreground.isGrantedByDefault
+ showGrantedByDefaultWarning =
+ showGrantedByDefaultWarning || group.foreground.isGrantedByDefault
showCDMWarning = showCDMWarning || group.foreground.isGrantedByRole
}
if (shouldRevokeBackground && wasBackgroundGranted) {
- showDefaultDenyDialog = showDefaultDenyDialog ||
+ showDefaultDenyDialog =
+ showDefaultDenyDialog ||
group.background.isGrantedByDefault ||
!group.supportsRuntimePerms ||
group.hasInstallToRuntimeSplit
- showGrantedByDefaultWarning = showGrantedByDefaultWarning ||
- group.background.isGrantedByDefault
+ showGrantedByDefaultWarning =
+ showGrantedByDefaultWarning || group.background.isGrantedByDefault
showCDMWarning = showCDMWarning || group.background.isGrantedByRole
}
if (showCDMWarning) {
// Refine showCDMWarning to only trigger for apps holding a device profile role
- val heldRoles = context.getSystemService(android.app.role.RoleManager::class.java)
+ val heldRoles =
+ context
+ .getSystemService(android.app.role.RoleManager::class.java)!!
.getHeldRolesFromController(packageName)
val heldProfiles = heldRoles.filter { it.startsWith(DEVICE_PROFILE_ROLE_PREFIX) }
showCDMWarning = showCDMWarning && heldProfiles.isNotEmpty()
@@ -743,14 +796,24 @@ class AppPermissionViewModel(
if (group.permGroupName == Manifest.permission_group.STORAGE) {
showDefaultDenyDialog = false
} else if (changeRequest == ChangeRequest.GRANT_FOREGROUND) {
- showMediaConfirmDialog(setOneTime, defaultDeny,
- ChangeRequest.GRANT_STORAGE_SUPERGROUP, buttonClicked, group.permGroupName,
- group.packageInfo.targetSdkVersion)
+ showMediaConfirmDialog(
+ setOneTime,
+ defaultDeny,
+ ChangeRequest.GRANT_STORAGE_SUPERGROUP,
+ buttonClicked,
+ group.permGroupName,
+ group.packageInfo.targetSdkVersion
+ )
return
} else if (changeRequest == ChangeRequest.REVOKE_BOTH) {
- showMediaConfirmDialog(setOneTime, defaultDeny,
- ChangeRequest.REVOKE_STORAGE_SUPERGROUP, buttonClicked, group.permGroupName,
- group.packageInfo.targetSdkVersion)
+ showMediaConfirmDialog(
+ setOneTime,
+ defaultDeny,
+ ChangeRequest.REVOKE_STORAGE_SUPERGROUP,
+ buttonClicked,
+ group.permGroupName,
+ group.packageInfo.targetSdkVersion
+ )
return
} else {
showDefaultDenyDialog = false
@@ -758,20 +821,32 @@ class AppPermissionViewModel(
}
if (showDefaultDenyDialog && !hasConfirmedRevoke && showGrantedByDefaultWarning) {
- defaultDeny.showConfirmDialog(changeRequest, R.string.system_warning, buttonClicked,
- setOneTime)
+ defaultDeny.showConfirmDialog(
+ changeRequest,
+ R.string.system_warning,
+ buttonClicked,
+ setOneTime
+ )
return
}
if (showDefaultDenyDialog && !hasConfirmedRevoke) {
- defaultDeny.showConfirmDialog(changeRequest, R.string.old_sdk_deny_warning,
- buttonClicked, setOneTime)
+ defaultDeny.showConfirmDialog(
+ changeRequest,
+ R.string.old_sdk_deny_warning,
+ buttonClicked,
+ setOneTime
+ )
return
}
if (showCDMWarning) {
- defaultDeny.showConfirmDialog(changeRequest,
- R.string.cdm_profile_revoke_warning, buttonClicked, setOneTime)
+ defaultDeny.showConfirmDialog(
+ changeRequest,
+ R.string.cdm_profile_revoke_warning,
+ buttonClicked,
+ setOneTime
+ )
return
}
@@ -780,12 +855,20 @@ class AppPermissionViewModel(
var newGroup = group2
val oldGroup = group2
- if (shouldRevokeBackground && group2.hasBackgroundGroup &&
- (wasBackgroundGranted || group2.background.isUserFixed ||
- group2.isOneTime != setOneTime)) {
- newGroup = KotlinUtils
- .revokeBackgroundRuntimePermissions(app, newGroup, oneTime = setOneTime,
- forceRemoveRevokedCompat = shouldClearOneTimeRevokedCompat(newGroup))
+ if (
+ shouldRevokeBackground &&
+ group2.hasBackgroundGroup &&
+ (wasBackgroundGranted ||
+ group2.background.isUserFixed ||
+ group2.isOneTime != setOneTime)
+ ) {
+ newGroup =
+ KotlinUtils.revokeBackgroundRuntimePermissions(
+ app,
+ newGroup,
+ oneTime = setOneTime,
+ forceRemoveRevokedCompat = shouldClearOneTimeRevokedCompat(newGroup)
+ )
// only log if we have actually denied permissions, not if we switch from
// "ask every time" to denied
@@ -794,12 +877,17 @@ class AppPermissionViewModel(
}
}
- if (shouldRevokeForeground &&
- (wasForegroundGranted || group2.isOneTime != setOneTime)) {
- newGroup = KotlinUtils
- .revokeForegroundRuntimePermissions(app, newGroup, userFixed = false,
- oneTime = setOneTime,
- forceRemoveRevokedCompat = shouldClearOneTimeRevokedCompat(newGroup))
+ if (
+ shouldRevokeForeground && (wasForegroundGranted || group2.isOneTime != setOneTime)
+ ) {
+ newGroup =
+ KotlinUtils.revokeForegroundRuntimePermissions(
+ app,
+ newGroup,
+ userFixed = false,
+ oneTime = setOneTime,
+ forceRemoveRevokedCompat = shouldClearOneTimeRevokedCompat(newGroup)
+ )
// only log if we have actually denied permissions, not if we switch from
// "ask every time" to denied
@@ -809,13 +897,16 @@ class AppPermissionViewModel(
}
if (shouldGrantForeground) {
- newGroup = if (shouldShowLocationAccuracy == true &&
- !isFineLocationChecked(newGroup)) {
- KotlinUtils.grantForegroundRuntimePermissions(app, newGroup,
- filterPermissions = listOf(ACCESS_COARSE_LOCATION))
- } else {
- KotlinUtils.grantForegroundRuntimePermissions(app, newGroup)
- }
+ newGroup =
+ if (shouldShowLocationAccuracy == true && !isFineLocationChecked(newGroup)) {
+ KotlinUtils.grantForegroundRuntimePermissions(
+ app,
+ newGroup,
+ filterPermissions = listOf(ACCESS_COARSE_LOCATION)
+ )
+ } else {
+ KotlinUtils.grantForegroundRuntimePermissions(app, newGroup)
+ }
if (!wasForegroundGranted) {
SafetyNetLogger.logPermissionToggled(newGroup)
@@ -832,15 +923,14 @@ class AppPermissionViewModel(
logPermissionChanges(oldGroup, newGroup, buttonClicked)
- fullStorageStateLiveData.value?.let {
- FullStoragePermissionAppsLiveData.recalculate()
- }
+ fullStorageStateLiveData.value?.let { FullStoragePermissionAppsLiveData.recalculate() }
}
}
private fun shouldClearOneTimeRevokedCompat(group: LightAppPermGroup): Boolean {
- return isPhotoPickerPromptEnabled() && permGroupName == READ_MEDIA_VISUAL &&
- group.permissions.values.any { it.isCompatRevoked && it.isOneTime }
+ return isPhotoPickerPromptEnabled() &&
+ permGroupName == READ_MEDIA_VISUAL &&
+ group.permissions.values.any { it.isCompatRevoked && it.isOneTime }
}
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
@@ -850,8 +940,10 @@ class AppPermissionViewModel(
}
private fun expandToSupergroup(group: LightAppPermGroup): List<LightAppPermGroup> {
- val mediaSupergroup = PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS
- .mapNotNull { mediaStorageSupergroupPermGroups[it] }
+ val mediaSupergroup =
+ PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS.mapNotNull {
+ mediaStorageSupergroupPermGroups[it]
+ }
return if (expandsToStorageSupergroup(group)) {
mediaSupergroup
} else {
@@ -860,21 +952,23 @@ class AppPermissionViewModel(
}
private fun getPermGroupIcon(permGroup: String) =
- Utils.getGroupInfo(permGroup, app.applicationContext)?.icon ?: R.drawable.ic_empty_icon
+ Utils.getGroupInfo(permGroup, app.applicationContext)?.icon ?: R.drawable.ic_empty_icon
private val storagePermGroupIcon = getPermGroupIcon(Manifest.permission_group.STORAGE)
- private val auralPermGroupIcon = if (SdkLevel.isAtLeastT()) {
- getPermGroupIcon(Manifest.permission_group.READ_MEDIA_AURAL)
- } else {
- R.drawable.ic_empty_icon
- }
+ private val auralPermGroupIcon =
+ if (SdkLevel.isAtLeastT()) {
+ getPermGroupIcon(Manifest.permission_group.READ_MEDIA_AURAL)
+ } else {
+ R.drawable.ic_empty_icon
+ }
- private val visualPermGroupIcon = if (SdkLevel.isAtLeastT()) {
- getPermGroupIcon(Manifest.permission_group.READ_MEDIA_VISUAL)
- } else {
- R.drawable.ic_empty_icon
- }
+ private val visualPermGroupIcon =
+ if (SdkLevel.isAtLeastT()) {
+ getPermGroupIcon(Manifest.permission_group.READ_MEDIA_VISUAL)
+ } else {
+ R.drawable.ic_empty_icon
+ }
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun showMediaConfirmDialog(
@@ -885,56 +979,63 @@ class AppPermissionViewModel(
groupName: String,
targetSdk: Int
) {
-
val aural = groupName == Manifest.permission_group.READ_MEDIA_AURAL
val visual = groupName == Manifest.permission_group.READ_MEDIA_VISUAL
val allow = changeRequest === ChangeRequest.GRANT_STORAGE_SUPERGROUP
val deny = changeRequest === ChangeRequest.REVOKE_STORAGE_SUPERGROUP
- val (iconId, titleId, messageId) = when {
- targetSdk < Build.VERSION_CODES.Q && aural && allow ->
- Triple(
- storagePermGroupIcon,
- R.string.media_confirm_dialog_title_a_to_p_aural_allow,
- R.string.media_confirm_dialog_message_a_to_p_aural_allow)
- targetSdk < Build.VERSION_CODES.Q && aural && deny ->
- Triple(
- storagePermGroupIcon,
- R.string.media_confirm_dialog_title_a_to_p_aural_deny,
- R.string.media_confirm_dialog_message_a_to_p_aural_deny)
- targetSdk < Build.VERSION_CODES.Q && visual && allow ->
- Triple(
- storagePermGroupIcon,
- R.string.media_confirm_dialog_title_a_to_p_visual_allow,
- R.string.media_confirm_dialog_message_a_to_p_visual_allow)
- targetSdk < Build.VERSION_CODES.Q && visual && deny ->
- Triple(
- storagePermGroupIcon,
- R.string.media_confirm_dialog_title_a_to_p_visual_deny,
- R.string.media_confirm_dialog_message_a_to_p_visual_deny)
- targetSdk <= Build.VERSION_CODES.S_V2 && aural && allow ->
- Triple(
- visualPermGroupIcon,
- R.string.media_confirm_dialog_title_q_to_s_aural_allow,
- R.string.media_confirm_dialog_message_q_to_s_aural_allow)
- targetSdk <= Build.VERSION_CODES.S_V2 && aural && deny ->
- Triple(
- visualPermGroupIcon,
- R.string.media_confirm_dialog_title_q_to_s_aural_deny,
- R.string.media_confirm_dialog_message_q_to_s_aural_deny)
- targetSdk <= Build.VERSION_CODES.S_V2 && visual && allow ->
- Triple(
- auralPermGroupIcon,
- R.string.media_confirm_dialog_title_q_to_s_visual_allow,
- R.string.media_confirm_dialog_message_q_to_s_visual_allow)
- targetSdk <= Build.VERSION_CODES.S_V2 && visual && deny ->
- Triple(
- auralPermGroupIcon,
- R.string.media_confirm_dialog_title_q_to_s_visual_deny,
- R.string.media_confirm_dialog_message_q_to_s_visual_deny)
- else ->
- Triple(0, 0, 0)
- }
+ val (iconId, titleId, messageId) =
+ when {
+ targetSdk < Build.VERSION_CODES.Q && aural && allow ->
+ Triple(
+ storagePermGroupIcon,
+ R.string.media_confirm_dialog_title_a_to_p_aural_allow,
+ R.string.media_confirm_dialog_message_a_to_p_aural_allow
+ )
+ targetSdk < Build.VERSION_CODES.Q && aural && deny ->
+ Triple(
+ storagePermGroupIcon,
+ R.string.media_confirm_dialog_title_a_to_p_aural_deny,
+ R.string.media_confirm_dialog_message_a_to_p_aural_deny
+ )
+ targetSdk < Build.VERSION_CODES.Q && visual && allow ->
+ Triple(
+ storagePermGroupIcon,
+ R.string.media_confirm_dialog_title_a_to_p_visual_allow,
+ R.string.media_confirm_dialog_message_a_to_p_visual_allow
+ )
+ targetSdk < Build.VERSION_CODES.Q && visual && deny ->
+ Triple(
+ storagePermGroupIcon,
+ R.string.media_confirm_dialog_title_a_to_p_visual_deny,
+ R.string.media_confirm_dialog_message_a_to_p_visual_deny
+ )
+ targetSdk <= Build.VERSION_CODES.S_V2 && aural && allow ->
+ Triple(
+ visualPermGroupIcon,
+ R.string.media_confirm_dialog_title_q_to_s_aural_allow,
+ R.string.media_confirm_dialog_message_q_to_s_aural_allow
+ )
+ targetSdk <= Build.VERSION_CODES.S_V2 && aural && deny ->
+ Triple(
+ visualPermGroupIcon,
+ R.string.media_confirm_dialog_title_q_to_s_aural_deny,
+ R.string.media_confirm_dialog_message_q_to_s_aural_deny
+ )
+ targetSdk <= Build.VERSION_CODES.S_V2 && visual && allow ->
+ Triple(
+ auralPermGroupIcon,
+ R.string.media_confirm_dialog_title_q_to_s_visual_allow,
+ R.string.media_confirm_dialog_message_q_to_s_visual_allow
+ )
+ targetSdk <= Build.VERSION_CODES.S_V2 && visual && deny ->
+ Triple(
+ auralPermGroupIcon,
+ R.string.media_confirm_dialog_title_q_to_s_visual_deny,
+ R.string.media_confirm_dialog_message_q_to_s_visual_deny
+ )
+ else -> Triple(0, 0, 0)
+ }
if (iconId == 0 || titleId == 0 || messageId == 0) {
throw UnsupportedOperationException()
@@ -962,9 +1063,8 @@ class AppPermissionViewModel(
*
* @param changeRequest whether to change foreground, background, or both.
* @param buttonPressed button pressed to initiate the change, one of
- * AppPermissionFragmentActionReported.button_pressed constants
+ * AppPermissionFragmentActionReported.button_pressed constants
* @param oneTime whether the change should show that the permission was selected as one-time
- *
*/
fun onDenyAnyWay(changeRequest: ChangeRequest, buttonPressed: Int, oneTime: Boolean) {
val unexpandedGroup = lightAppPermGroup ?: return
@@ -977,16 +1077,17 @@ class AppPermissionViewModel(
var newGroup = group
val oldGroup = group
- if (changeRequest andValue ChangeRequest.REVOKE_BACKGROUND != 0 &&
- group.hasBackgroundGroup) {
+ if (
+ changeRequest andValue ChangeRequest.REVOKE_BACKGROUND != 0 &&
+ group.hasBackgroundGroup
+ ) {
newGroup =
KotlinUtils.revokeBackgroundRuntimePermissions(app, newGroup, false, oneTime)
if (wasBackgroundGranted) {
SafetyNetLogger.logPermissionToggled(newGroup)
}
- hasDefaultPermissions = hasDefaultPermissions ||
- group.background.isGrantedByDefault
+ hasDefaultPermissions = hasDefaultPermissions || group.background.isGrantedByDefault
}
if (changeRequest andValue ChangeRequest.REVOKE_FOREGROUND != 0) {
@@ -1003,9 +1104,7 @@ class AppPermissionViewModel(
hasConfirmedRevoke = true
}
- fullStorageStateLiveData.value?.let {
- FullStoragePermissionAppsLiveData.recalculate()
- }
+ fullStorageStateLiveData.value?.let { FullStoragePermissionAppsLiveData.recalculate() }
}
}
@@ -1017,11 +1116,12 @@ class AppPermissionViewModel(
fun setAllFilesAccess(granted: Boolean) {
val aom = app.getSystemService(AppOpsManager::class.java)!!
val uid = lightAppPermGroup?.packageInfo?.uid ?: return
- val mode = if (granted) {
- MODE_ALLOWED
- } else {
- MODE_ERRORED
- }
+ val mode =
+ if (granted) {
+ MODE_ALLOWED
+ } else {
+ MODE_ERRORED
+ }
val fullStorageGrant = fullStorageStateLiveData.value?.isGranted
if (fullStorageGrant != null && fullStorageGrant != granted) {
aom.setUidMode(OPSTR_MANAGE_EXTERNAL_STORAGE, uid, mode)
@@ -1039,8 +1139,9 @@ class AppPermissionViewModel(
}
private fun getIndividualPermissionDetailResId(group: LightAppPermGroup): Pair<Int, Int> {
- return when (val numRevoked =
- group.permissions.filter { !it.value.isGrantedIncludingAppOp }.size) {
+ return when (
+ val numRevoked = group.permissions.filter { !it.value.isGrantedIncludingAppOp }.size
+ ) {
0 -> R.string.permission_revoked_none to numRevoked
group.permissions.size -> R.string.permission_revoked_all to numRevoked
else -> R.string.permission_revoked_count to numRevoked
@@ -1055,16 +1156,16 @@ class AppPermissionViewModel(
hasAdmin: Boolean
): Int {
val isForegroundPolicyDenied = group.foreground.isPolicyFixed && !group.foreground.isGranted
- val isPolicyFullyFixedWithGrantedOrNoBkg = group.isPolicyFullyFixed &&
- (group.background.isGranted || !group.hasBackgroundGroup)
+ val isPolicyFullyFixedWithGrantedOrNoBkg =
+ group.isPolicyFullyFixed && (group.background.isGranted || !group.hasBackgroundGroup)
if (group.foreground.isSystemFixed || group.background.isSystemFixed) {
return R.string.permission_summary_enabled_system_fixed
} else if (hasAdmin) {
// Permission is fully controlled by policy and cannot be switched
if (isForegroundPolicyDenied) {
- return R.string.disabled_by_admin
+ return com.android.settingslib.widget.restricted.R.string.disabled_by_admin
} else if (isPolicyFullyFixedWithGrantedOrNoBkg) {
- return R.string.enabled_by_admin
+ return com.android.settingslib.widget.restricted.R.string.enabled_by_admin
} else if (group.isPolicyFullyFixed) {
return R.string.permission_summary_enabled_by_admin_foreground_only
}
@@ -1110,11 +1211,17 @@ class AppPermissionViewModel(
for ((permName, permission) in oldGroup.permissions) {
val newPermission = newGroup.permissions[permName] ?: continue
- if (permission.isGrantedIncludingAppOp != newPermission.isGrantedIncludingAppOp ||
- permission.flags != newPermission.flags) {
+ if (
+ permission.isGrantedIncludingAppOp != newPermission.isGrantedIncludingAppOp ||
+ permission.flags != newPermission.flags
+ ) {
logAppPermissionFragmentActionReported(changeId, newPermission, buttonPressed)
- PermissionDecisionStorageImpl.recordPermissionDecision(app.applicationContext,
- packageName, permGroupName, newPermission.isGrantedIncludingAppOp)
+ PermissionDecisionStorageImpl.recordPermissionDecision(
+ app.applicationContext,
+ packageName,
+ permGroupName,
+ newPermission.isGrantedIncludingAppOp
+ )
PermissionChangeStorageImpl.recordPermissionChange(packageName)
}
}
@@ -1136,13 +1243,28 @@ class AppPermissionViewModel(
buttonPressed: Int
) {
val uid = KotlinUtils.getPackageUid(app, packageName, user) ?: return
- PermissionControllerStatsLog.write(APP_PERMISSION_FRAGMENT_ACTION_REPORTED, sessionId,
- changeId, uid, packageName, permission.permInfo.name,
- permission.isGrantedIncludingAppOp, permission.flags, buttonPressed)
- Log.v(LOG_TAG, "Permission changed via UI with sessionId=$sessionId changeId=" +
- "$changeId uid=$uid packageName=$packageName permission=" + permission.permInfo.name +
- " isGranted=" + permission.isGrantedIncludingAppOp + " permissionFlags=" +
- permission.flags + " buttonPressed=$buttonPressed")
+ PermissionControllerStatsLog.write(
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED,
+ sessionId,
+ changeId,
+ uid,
+ packageName,
+ permission.permInfo.name,
+ permission.isGrantedIncludingAppOp,
+ permission.flags,
+ buttonPressed
+ )
+ Log.i(
+ LOG_TAG,
+ "Permission changed via UI with sessionId=$sessionId changeId=" +
+ "$changeId uid=$uid packageName=$packageName permission=" +
+ permission.permInfo.name +
+ " isGranted=" +
+ permission.isGrantedIncludingAppOp +
+ " permissionFlags=" +
+ permission.flags +
+ " buttonPressed=$buttonPressed"
+ )
}
/** Logs information about this AppPermissionGroup and view session */
@@ -1156,19 +1278,20 @@ class AppPermissionViewModel(
uid,
packageName,
permGroupName,
- permissionRationaleShown)
- Log.v(
+ permissionRationaleShown
+ )
+ Log.i(
LOG_TAG,
"AppPermission fragment viewed with sessionId=$sessionId uid=$uid " +
"packageName=$packageName permGroupName=$permGroupName " +
- "permissionRationaleShown=$permissionRationaleShown")
+ "permissionRationaleShown=$permissionRationaleShown"
+ )
}
/**
- * A partial storage grant happens when:
- * An app which doesn't support the photo picker has READ_MEDIA_VISUAL_USER_SELECTED granted, or
- * An app which does support the photo picker has READ_MEDIA_VISUAL_USER_SELECTED and/or
- * ACCESS_MEDIA_LOCATION granted
+ * A partial storage grant happens when: An app which doesn't support the photo picker has
+ * READ_MEDIA_VISUAL_USER_SELECTED granted, or An app which does support the photo picker has
+ * READ_MEDIA_VISUAL_USER_SELECTED and/or ACCESS_MEDIA_LOCATION granted
*/
private fun isPartialStorageGrant(group: LightAppPermGroup): Boolean {
if (!isPhotoPickerPromptEnabled() || group.permGroupName != READ_MEDIA_VISUAL) {
@@ -1177,9 +1300,10 @@ class AppPermissionViewModel(
val partialPerms = getPartialStorageGrantPermissionsForGroup(group)
- return group.isGranted && group.permissions.values.all {
- it.name in partialPerms || (it.name !in partialPerms && !it.isGrantedIncludingAppOp)
- }
+ return group.isGranted &&
+ group.permissions.values.all {
+ it.name in partialPerms || (it.name !in partialPerms && !it.isGrantedIncludingAppOp)
+ }
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
index 0680ffcd2..3786b99bd 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
@@ -17,13 +17,14 @@
package com.android.permissioncontroller.permission.ui.model
-import android.Manifest
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
-import android.Manifest.permission.POST_NOTIFICATIONS
import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
import android.Manifest.permission_group.LOCATION
+import android.Manifest.permission_group.NOTIFICATIONS
+import android.Manifest.permission_group.READ_MEDIA_AURAL
import android.Manifest.permission_group.READ_MEDIA_VISUAL
+import android.Manifest.permission_group.STORAGE
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
@@ -39,11 +40,8 @@ import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP
import android.os.Build
import android.os.Bundle
import android.os.Process
-import android.os.UserManager
import android.permission.PermissionManager
-import android.provider.MediaStore
import android.util.Log
-import androidx.annotation.ChecksSdkIntAtLeast
import androidx.core.util.Consumer
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
@@ -73,9 +71,9 @@ import com.android.permissioncontroller.auto.DrivingDecisionReminderService
import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData
import com.android.permissioncontroller.permission.data.LightPackageInfoLiveData
import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData
-import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
import com.android.permissioncontroller.permission.data.get
+import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData
import com.android.permissioncontroller.permission.model.AppPermissionGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
@@ -84,29 +82,7 @@ import com.android.permissioncontroller.permission.service.PermissionChangeStora
import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl
import com.android.permissioncontroller.permission.ui.AutoGrantPermissionsNotifier
import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ALL_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_FOREGROUND_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ONE_TIME_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_SELECTED_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.COARSE_RADIO_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_AND_DONT_ASK_AGAIN_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_BOTH_LOCATIONS
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_COARSE_LOCATION_ONLY
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_FINE_LOCATION_ONLY
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DONT_ALLOW_MORE_SELECTED_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.FINE_RADIO_BUTTON
import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.INTENT_PHOTOS_SELECTED
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.LINK_TO_PERMISSION_RATIONALE
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.LINK_TO_SETTINGS
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.LOCATION_ACCURACY_LAYOUT
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NEXT_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NEXT_LOCATION_DIALOG
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON
-import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_BUTTON
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.CANCELED
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_DO_NOT_ASK_AGAIN
@@ -118,56 +94,70 @@ import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandle
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT
+import com.android.permissioncontroller.permission.ui.model.grantPermissions.BackgroundGrantBehavior
+import com.android.permissioncontroller.permission.ui.model.grantPermissions.BasicGrantBehavior
+import com.android.permissioncontroller.permission.ui.model.grantPermissions.GrantBehavior
+import com.android.permissioncontroller.permission.ui.model.grantPermissions.HealthGrantBehavior
+import com.android.permissioncontroller.permission.ui.model.grantPermissions.LocationGrantBehavior
+import com.android.permissioncontroller.permission.ui.model.grantPermissions.NotificationGrantBehavior
+import com.android.permissioncontroller.permission.ui.model.grantPermissions.StorageGrantBehavior
import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity
-import com.android.permissioncontroller.permission.utils.v31.AdminRestrictedPermissionsUtils
+import com.android.permissioncontroller.permission.utils.ContextCompat
import com.android.permissioncontroller.permission.utils.KotlinUtils
-import com.android.permissioncontroller.permission.utils.KotlinUtils.getDefaultPrecision
import com.android.permissioncontroller.permission.utils.KotlinUtils.grantBackgroundRuntimePermissions
import com.android.permissioncontroller.permission.utils.KotlinUtils.grantForegroundRuntimePermissions
-import com.android.permissioncontroller.permission.utils.KotlinUtils.isLocationAccuracyEnabled
+import com.android.permissioncontroller.permission.utils.KotlinUtils.openPhotoPickerForApp
import com.android.permissioncontroller.permission.utils.KotlinUtils.revokeBackgroundRuntimePermissions
import com.android.permissioncontroller.permission.utils.KotlinUtils.revokeForegroundRuntimePermissions
import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.PermissionMapping.getPartialStorageGrantPermissionsForGroup
import com.android.permissioncontroller.permission.utils.SafetyNetLogger
import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.v31.AdminRestrictedPermissionsUtils
import com.android.permissioncontroller.permission.utils.v34.SafetyLabelUtils
/**
- * ViewModel for the GrantPermissionsActivity. Tracks all permission groups that are affected by
- * the permissions requested by the user, and generates a RequestInfo object for each group, if
- * action is needed. It will not return any data if one of the requests is malformed.
+ * ViewModel for the GrantPermissionsActivity. Tracks all permission groups that are affected by the
+ * permissions requested by the user, and generates a RequestInfo object for each group, if action
+ * is needed. It will not return any data if one of the requests is malformed.
*
* @param app: The current application
* @param packageName: The packageName permissions are being requested for
* @param requestedPermissions: The list of permissions requested
+ * @param systemRequestedPermissions: The list of permissions requested as a result of a system
+ * triggered dialog, not an app-triggered dialog
* @param sessionId: A long to identify this session
* @param storedState: Previous state, if this activity was stopped and is being recreated
*/
class GrantPermissionsViewModel(
private val app: Application,
private val packageName: String,
+ private val deviceId: Int,
private val requestedPermissions: List<String>,
+ private val systemRequestedPermissions: List<String>,
private val sessionId: Long,
private val storedState: Bundle?
) : ViewModel() {
private val LOG_TAG = GrantPermissionsViewModel::class.java.simpleName
private val user = Process.myUserHandle()
- private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
+ private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user, deviceId]
private val safetyLabelInfoLiveData =
- if (SdkLevel.isAtLeastU() && requestedPermissions
- .mapNotNull { PermissionMapping.getGroupOfPlatformPermission(it) }
- .any { PermissionMapping.isSafetyLabelAwarePermissionGroup(it) }) {
+ if (
+ SdkLevel.isAtLeastU() &&
+ requestedPermissions
+ .mapNotNull { PermissionMapping.getGroupOfPlatformPermission(it) }
+ .any { PermissionMapping.isSafetyLabelAwarePermissionGroup(it) }
+ ) {
SafetyLabelInfoLiveData[packageName, user]
} else {
null
}
private val dpm = app.getSystemService(DevicePolicyManager::class.java)!!
private val permissionPolicy = dpm.getPermissionPolicy(null)
- private val permGroupsToSkip = mutableListOf<String>()
- private var groupStates = mutableMapOf<Pair<String, Boolean>, GroupState>()
+ private val groupStates = mutableMapOf<String, GroupState>()
private var autoGrantNotifier: AutoGrantPermissionsNotifier? = null
+
private fun getAutoGrantNotifier(): AutoGrantPermissionsNotifier {
autoGrantNotifier = AutoGrantPermissionsNotifier(app, packageInfo.toPackageInfo(app)!!)
return autoGrantNotifier!!
@@ -179,447 +169,254 @@ class GrantPermissionsViewModel(
// filtering system fixed, auto grant, etc.
private var unfilteredAffectedPermissions = requestedPermissions
- private val splitPermissionTargetSdkMap = mutableMapOf<String, Int>()
-
private var appPermGroupLiveDatas = mutableMapOf<String, LightAppPermGroupLiveData>()
+ internal data class ResultCallback(val consumer: Consumer<Intent>, val requestCode: Int)
+
+ private var activityResultCallback: ResultCallback? = null
+
+ init {
+ if (storedState?.containsKey(SAVED_REQUEST_CODE_KEY) == true) {
+ if (storedState.getInt(SAVED_REQUEST_CODE_KEY) == PHOTO_PICKER_REQUEST_CODE) {
+ setPhotoPickerCallback()
+ }
+ }
+ }
+
/**
- * A class which represents a correctly requested permission group, and the buttons and messages
- * which should be shown with it.
+ * An internal class which represents the state of a current AppPermissionGroup grant request.
+ * It is made up of the following:
+ *
+ * @param group The LightAppPermGroup representing the current state of the permissions for this
+ * app
+ * @param affectedPermissions The permissions that should be affected by this
*/
+ internal class GroupState(
+ internal val group: LightAppPermGroup,
+ internal val affectedPermissions: MutableSet<String> = mutableSetOf(),
+ internal var state: Int = STATE_UNKNOWN,
+ ) {
+ val fgPermissions = affectedPermissions - group.backgroundPermNames.toSet()
+ val bgPermissions = affectedPermissions - fgPermissions
+
+ override fun toString(): String {
+ val stateStr: String =
+ when (state) {
+ STATE_UNKNOWN -> "unknown"
+ STATE_GRANTED -> "granted"
+ STATE_DENIED -> "denied"
+ STATE_FG_GRANTED_BG_UNKNOWN -> "foreground granted, background unknown"
+ else -> "skipped"
+ }
+ return "${group.permGroupName} $stateStr $affectedPermissions"
+ }
+ }
+
data class RequestInfo(
val groupInfo: LightPermGroupInfo,
- val buttonVisibilities: List<Boolean> = List(NEXT_BUTTON) { false },
- val locationVisibilities: List<Boolean> = List(NEXT_LOCATION_DIALOG) { false },
- val message: RequestMessage = RequestMessage.FG_MESSAGE,
- val detailMessage: RequestMessage = RequestMessage.NO_MESSAGE,
- val sendToSettingsImmediately: Boolean = false,
- val openPhotoPicker: Boolean = false,
+ val prompt: Prompt,
+ val deny: DenyButton,
+ val showRationale: Boolean,
+ val deviceId: Int = ContextCompat.DEVICE_ID_DEFAULT
) {
val groupName = groupInfo.name
}
- var activityResultCallback: Consumer<Intent>? = null
-
- /**
- * A LiveData which holds a list of the currently pending RequestInfos
- */
- val requestInfosLiveData = object :
- SmartUpdateMediatorLiveData<List<RequestInfo>>() {
- private val LOG_TAG = GrantPermissionsViewModel::class.java.simpleName
- private val packagePermissionsLiveData = PackagePermissionsLiveData[packageName, user]
-
- init {
- addSource(packagePermissionsLiveData) { onPackageLoaded() }
- addSource(packageInfoLiveData) { onPackageLoaded() }
- if (safetyLabelInfoLiveData != null) {
- addSource(safetyLabelInfoLiveData) { onPackageLoaded() }
- }
-
- // Load package state, if available
- onPackageLoaded()
- }
+ val requestInfosLiveData =
+ object : SmartUpdateMediatorLiveData<List<RequestInfo>>() {
+ private val LOG_TAG = GrantPermissionsViewModel::class.java.simpleName
+ private val packagePermissionsLiveData = PackagePermissionsLiveData[packageName, user]
- private fun onPackageLoaded() {
- if (packageInfoLiveData.isStale ||
- packagePermissionsLiveData.isStale ||
- (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale)) {
- return
- }
+ init {
+ addSource(packagePermissionsLiveData) { onPackageLoaded() }
+ addSource(packageInfoLiveData) { onPackageLoaded() }
+ if (safetyLabelInfoLiveData != null) {
+ addSource(safetyLabelInfoLiveData) { onPackageLoaded() }
+ }
- val groups = packagePermissionsLiveData.value
- val pI = packageInfoLiveData.value
- if (groups == null || groups.isEmpty() || pI == null) {
- Log.e(LOG_TAG, "Package $packageName not found")
- value = null
- return
+ // Load package state, if available
+ onPackageLoaded()
}
- packageInfo = pI
- if (packageInfo.requestedPermissions.isEmpty() ||
- packageInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- Log.e(LOG_TAG, "Package $packageName has no requested permissions, or " +
- "is a pre-M app")
- value = null
- return
- }
+ private fun onPackageLoaded() {
+ if (
+ packageInfoLiveData.isStale ||
+ packagePermissionsLiveData.isStale ||
+ (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale)
+ ) {
+ return
+ }
- val allAffectedPermissions = requestedPermissions.toMutableSet()
- for (requestedPerm in requestedPermissions) {
- allAffectedPermissions.addAll(computeAffectedPermissions(requestedPerm, groups))
- }
- unfilteredAffectedPermissions = allAffectedPermissions.toList()
+ val groups = packagePermissionsLiveData.value
+ val pI = packageInfoLiveData.value
+ if (groups.isNullOrEmpty() || pI == null) {
+ Log.e(LOG_TAG, "Package $packageName not found")
+ value = null
+ return
+ }
+ packageInfo = pI
+
+ if (
+ packageInfo.requestedPermissions.isEmpty() ||
+ packageInfo.targetSdkVersion < Build.VERSION_CODES.M
+ ) {
+ Log.e(
+ LOG_TAG,
+ "Package $packageName has no requested permissions, or " + "is a pre-M app"
+ )
+ value = null
+ return
+ }
- setAppPermGroupsLiveDatas(groups.toMutableMap().apply {
- remove(PackagePermissionsLiveData.NON_RUNTIME_NORMAL_PERMS)
- })
+ val affectedPermissions = requestedPermissions.toMutableSet()
+ for (requestedPerm in requestedPermissions) {
+ affectedPermissions.addAll(getAffectedSplitPermissions(requestedPerm))
+ }
+ if (packageInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+ // For < O apps all permissions of the groups of the requested ones are affected
+ for (affectedPerm in affectedPermissions.toSet()) {
+ val otherGroupPerms =
+ groups.values.firstOrNull { affectedPerm in it } ?: emptyList()
+ affectedPermissions.addAll(otherGroupPerms)
+ }
+ }
+ unfilteredAffectedPermissions = affectedPermissions.toList()
- for (splitPerm in app.getSystemService(
- PermissionManager::class.java)!!.splitPermissions) {
- splitPermissionTargetSdkMap[splitPerm.splitPermission] = splitPerm.targetSdk
+ setAppPermGroupsLiveDatas(
+ groups.toMutableMap().apply {
+ remove(PackagePermissionsLiveData.NON_RUNTIME_NORMAL_PERMS)
+ }
+ )
}
- }
-
- private fun setAppPermGroupsLiveDatas(groups: Map<String, List<String>>) {
- val requestedGroups = groups.filter { (_, perms) ->
- perms.any { it in unfilteredAffectedPermissions }
- }
+ private fun setAppPermGroupsLiveDatas(groups: Map<String, List<String>>) {
+ val requestedGroups =
+ groups.filter { (_, perms) ->
+ perms.any { it in unfilteredAffectedPermissions }
+ }
- if (requestedGroups.isEmpty()) {
- Log.e(LOG_TAG, "None of " +
- "$unfilteredAffectedPermissions in $groups")
- value = null
- return
- }
+ if (requestedGroups.isEmpty()) {
+ Log.e(LOG_TAG, "None of " + "$unfilteredAffectedPermissions in $groups")
+ value = null
+ return
+ }
- val getLiveDataFun = { groupName: String ->
- LightAppPermGroupLiveData[packageName, groupName, user]
+ val getLiveDataFun = { groupName: String ->
+ LightAppPermGroupLiveData[packageName, groupName, user, deviceId]
+ }
+ setSourcesToDifference(requestedGroups.keys, appPermGroupLiveDatas, getLiveDataFun)
}
- setSourcesToDifference(requestedGroups.keys, appPermGroupLiveDatas, getLiveDataFun)
- }
- override fun onUpdate() {
- if (appPermGroupLiveDatas.any { it.value.isStale }) {
- return
- }
- var newGroups = false
- for ((groupName, groupLiveData) in appPermGroupLiveDatas) {
- val appPermGroup = groupLiveData.value
- if (appPermGroup == null || groupName in permGroupsToSkip) {
+ override fun onUpdate() {
+ if (appPermGroupLiveDatas.any { it.value.isStale }) {
+ return
+ }
+ var newGroups = false
+ for ((groupName, groupLiveData) in appPermGroupLiveDatas) {
+ val appPermGroup = groupLiveData.value
if (appPermGroup == null) {
Log.e(LOG_TAG, "Group $packageName $groupName invalid")
+ groupStates[groupName]?.state = STATE_SKIPPED
+ continue
}
- groupStates[groupName to true]?.state = STATE_SKIPPED
- groupStates[groupName to false]?.state = STATE_SKIPPED
- continue
- }
- packageInfo = appPermGroup.packageInfo
+ packageInfo = appPermGroup.packageInfo
- val states = groupStates.filter { it.key.first == groupName }
- if (states.isNotEmpty()) {
- for ((key, state) in states) {
- val allAffectedGranted = state.affectedPermissions.all { perm ->
- appPermGroup.permissions[perm]?.isGrantedIncludingAppOp == true &&
- appPermGroup.permissions[perm]?.isRevokeWhenRequested == false
- }
+ val state = groupStates[groupName]
+ if (state != null) {
+ val allAffectedGranted =
+ state.affectedPermissions.all { perm ->
+ appPermGroup.permissions[perm]?.isGrantedIncludingAppOp == true &&
+ appPermGroup.permissions[perm]?.isRevokeWhenRequested == false
+ }
if (allAffectedGranted) {
- groupStates[key]!!.state = STATE_ALLOWED
+ groupStates[groupName]!!.state = STATE_GRANTED
}
+ } else {
+ newGroups = true
}
- } else {
- newGroups = true
}
- }
- if (newGroups) {
- groupStates = getRequiredGroupStates(
- appPermGroupLiveDatas.mapNotNull { it.value.value })
- }
- setRequestInfosFromGroupStates()
- }
-
- private fun setRequestInfosFromGroupStates() {
- val requestInfos = mutableListOf<RequestInfo>()
- for ((key, groupState) in groupStates) {
- val groupInfo = groupState.group.permGroupInfo
- val (groupName, isBackground) = key
- if (groupState.state != STATE_UNKNOWN) {
- continue
- }
- val fgState = groupStates[groupName to false]
- val bgState = groupStates[groupName to true]
- var needFgPermissions = false
- var needBgPermissions = false
- var isFgUserSet = false
- var isBgUserSet = false
- var minSdkForOrderedSplitPermissions = Build.VERSION_CODES.R
- if (fgState?.group != null) {
- val fgGroup = fgState.group
- for (perm in fgState.affectedPermissions) {
- minSdkForOrderedSplitPermissions = maxOf(minSdkForOrderedSplitPermissions,
- splitPermissionTargetSdkMap.getOrDefault(perm, 0))
- if (fgGroup.permissions[perm]?.isGrantedIncludingAppOp == false) {
- // If any of the requested permissions is not granted,
- // needFgPermissions = true
- needFgPermissions = true
- // If any of the requested permission's UserSet is true and the
- // permission is not granted, isFgUserSet = true.
- if (fgGroup.permissions[perm]?.isUserSet == true) {
- isFgUserSet = true
- }
- }
- }
- }
- if (bgState?.group?.background?.isGranted == false) {
- needBgPermissions = true
- isBgUserSet = bgState.group.background.isUserSet
+ if (newGroups) {
+ addRequiredGroupStates(appPermGroupLiveDatas.mapNotNull { it.value.value })
}
+ setRequestInfosFromGroupStates()
+ }
- val buttonVisibilities = MutableList(NEXT_BUTTON) { false }
- buttonVisibilities[ALLOW_BUTTON] = true
- buttonVisibilities[DENY_BUTTON] = true
- buttonVisibilities[ALLOW_ONE_TIME_BUTTON] =
- PermissionMapping.supportsOneTimeGrant(groupName)
- var message = RequestMessage.FG_MESSAGE
- // Whether or not to use the foreground, background, or no detail message.
- // null ==
- var detailMessage = RequestMessage.NO_MESSAGE
-
- if (KotlinUtils.isPhotoPickerPromptEnabled() &&
- groupState.group.permGroupName == READ_MEDIA_VISUAL &&
- groupState.group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU) {
- // If the USER_SELECTED permission is user fixed and granted, or the app is only
- // requesting USER_SELECTED, direct straight to photo picker
- val userPerm = groupState.group.permissions[READ_MEDIA_VISUAL_USER_SELECTED]
- if ((userPerm?.isUserFixed == true && userPerm.isGrantedIncludingAppOp) ||
- groupState.affectedPermissions == listOf(READ_MEDIA_VISUAL_USER_SELECTED)) {
- requestInfos.add(RequestInfo(groupInfo, openPhotoPicker = true))
+ private fun setRequestInfosFromGroupStates() {
+ val requestInfos = mutableListOf<RequestInfo>()
+ for (groupState in groupStates.values) {
+ if (!isStateUnknown(groupState.state)) {
continue
- } else if (isPartialStorageGrant(groupState.group)) {
- // More photos dialog
- message = RequestMessage.MORE_PHOTOS_MESSAGE
- buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] = false
- buttonVisibilities[DENY_BUTTON] = false
- buttonVisibilities[DONT_ALLOW_MORE_SELECTED_BUTTON] = true
- } else {
- // Standard photos dialog
- buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] = isFgUserSet
- buttonVisibilities[DENY_BUTTON] = !isFgUserSet
- }
- buttonVisibilities[ALLOW_SELECTED_BUTTON] = true
- buttonVisibilities[ALLOW_BUTTON] = false
- buttonVisibilities[ALLOW_ALL_BUTTON] = true
- } else if (groupState.group.packageInfo.targetSdkVersion >=
- minSdkForOrderedSplitPermissions) {
- if (isBackground || Utils.hasPermWithBackgroundModeCompat(groupState.group)) {
- if (needFgPermissions) {
- if (needBgPermissions) {
- if (groupState.group.permGroupName
- .equals(Manifest.permission_group.CAMERA) ||
- groupState.group.permGroupName
- .equals(Manifest.permission_group.MICROPHONE)) {
- if (groupState.group.packageInfo.targetSdkVersion >=
- Build.VERSION_CODES.S) {
- Log.e(LOG_TAG,
- "For S apps, background permissions must be " +
- "requested after foreground permissions are" +
- " already granted")
- value = null
- return
- } else {
- // Case: sdk < S, BG&FG mic/camera permission requested
- buttonVisibilities[ALLOW_BUTTON] = false
- buttonVisibilities[ALLOW_FOREGROUND_BUTTON] = true
- buttonVisibilities[DENY_BUTTON] = !isFgUserSet
- buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] =
- isFgUserSet
- if (needBgPermissions) {
- // Case: sdk < R, BG/FG permission requesting both
- message = RequestMessage.BG_MESSAGE
- detailMessage = RequestMessage.BG_MESSAGE
- }
- }
- } else {
- // Shouldn't be reached as background must be requested as a
- // singleton
- Log.e(LOG_TAG, "For R+ apps, background permissions must be " +
- "requested after foreground permissions are already" +
- " granted")
- value = null
- return
- }
- } else {
- buttonVisibilities[ALLOW_BUTTON] = false
- buttonVisibilities[ALLOW_FOREGROUND_BUTTON] = true
- buttonVisibilities[DENY_BUTTON] = !isFgUserSet
- buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] = isFgUserSet
- }
- } else if (needBgPermissions) {
- // Case: sdk >= R, BG/FG permission requesting BG only
- if (storedState != null && storedState.containsKey(getInstanceStateKey(
- groupInfo.name, groupState.isBackground))) {
- // If we're restoring state, and we had this groupInfo in our
- // previous state, that means that we likely sent the user to
- // settings already. Don't send the user back.
- permGroupsToSkip.add(groupInfo.name)
- groupState.state = STATE_SKIPPED
- } else {
- requestInfos.add(RequestInfo(
- groupInfo, sendToSettingsImmediately = true))
- }
- continue
- } else {
- // Not reached as the permissions should be auto-granted
- value = null
- return
- }
- } else {
- // Case: sdk >= R, Requesting normal permission
- buttonVisibilities[DENY_BUTTON] = !isFgUserSet
- buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] = isFgUserSet
- }
- } else {
- if (isBackground || Utils.hasPermWithBackgroundModeCompat(groupState.group)) {
- if (needFgPermissions) {
- // Case: sdk < R, BG/FG permission requesting both or FG only
- buttonVisibilities[ALLOW_BUTTON] = false
- buttonVisibilities[ALLOW_FOREGROUND_BUTTON] = true
- buttonVisibilities[DENY_BUTTON] = !isFgUserSet
- buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] = isFgUserSet
- if (needBgPermissions) {
- // Case: sdk < R, BG/FG permission requesting both
- message = RequestMessage.BG_MESSAGE
- detailMessage = RequestMessage.BG_MESSAGE
- }
- } else if (needBgPermissions) {
- // Case: sdk < R, BG/FG permission requesting BG only
- if (!groupState.group.foreground.isGranted) {
- Log.e(LOG_TAG, "Background permissions can't be requested " +
- "solely before foreground permissions are granted.")
- value = null
- return
- }
- message = RequestMessage.UPGRADE_MESSAGE
- detailMessage = RequestMessage.UPGRADE_MESSAGE
- buttonVisibilities[ALLOW_BUTTON] = false
- buttonVisibilities[DENY_BUTTON] = false
- buttonVisibilities[ALLOW_ONE_TIME_BUTTON] = false
- if (groupState.group.isOneTime) {
- buttonVisibilities[NO_UPGRADE_OT_BUTTON] = !isBgUserSet
- buttonVisibilities[NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON] =
- isBgUserSet
- } else {
- buttonVisibilities[NO_UPGRADE_BUTTON] = !isBgUserSet
- buttonVisibilities[NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON] =
- isBgUserSet
- }
- } else {
- // Not reached as the permissions should be auto-granted
- value = null
- return
- }
- } else {
- // If no permissions needed, do nothing
- if (!needFgPermissions && !needBgPermissions) {
- value = null
- return
- }
- // Case: sdk < R, Requesting normal permission
- buttonVisibilities[DENY_BUTTON] = !isFgUserSet
- buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON] = isFgUserSet
}
- }
- buttonVisibilities[LINK_TO_SETTINGS] =
- detailMessage != RequestMessage.NO_MESSAGE
-
- // Show location permission dialogs based on location permissions
- val locationVisibilities = MutableList(NEXT_LOCATION_DIALOG) { false }
- if (groupState.group.permGroupName == LOCATION && isLocationAccuracyEnabled() &&
- packageInfo.targetSdkVersion >= Build.VERSION_CODES.S) {
- if (needFgPermissions) {
- locationVisibilities[LOCATION_ACCURACY_LAYOUT] = true
- if (fgState != null &&
- fgState.affectedPermissions.contains(ACCESS_FINE_LOCATION)) {
- val coarseLocationPerm =
- groupState.group.allPermissions[ACCESS_COARSE_LOCATION]
- if (coarseLocationPerm?.isGrantedIncludingAppOp == true) {
- // Upgrade flow
- locationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY] = true
- message = RequestMessage.FG_FINE_LOCATION_MESSAGE
- // If COARSE was granted one time, hide 'While in use' button
- if (coarseLocationPerm.isOneTime) {
- buttonVisibilities[ALLOW_FOREGROUND_BUTTON] = false
- }
- } else {
- if (!fgState.affectedPermissions.contains(ACCESS_COARSE_LOCATION)) {
- Log.e(LOG_TAG, "ACCESS_FINE_LOCATION must be requested " +
- "with ACCESS_COARSE_LOCATION.")
- value = null
- return
- }
- // Normal flow with both Coarse and Fine locations
- locationVisibilities[DIALOG_WITH_BOTH_LOCATIONS] = true
- // Steps to decide location accuracy default state
- // 1. If none of the FINE and COARSE isSelectedLocationAccuracy
- // flags is set, then use default precision from device config.
- // 2. Otherwise set to whichever isSelectedLocationAccuracy is true.
- val fineLocationPerm =
- groupState.group.allPermissions[ACCESS_FINE_LOCATION]
- if (coarseLocationPerm?.isSelectedLocationAccuracy == false &&
- fineLocationPerm?.isSelectedLocationAccuracy == false) {
- if (getDefaultPrecision()) {
- locationVisibilities[FINE_RADIO_BUTTON] = true
- } else {
- locationVisibilities[COARSE_RADIO_BUTTON] = true
- }
- } else if (coarseLocationPerm?.isSelectedLocationAccuracy == true) {
- locationVisibilities[COARSE_RADIO_BUTTON] = true
- } else {
- locationVisibilities[FINE_RADIO_BUTTON] = true
- }
- }
- } else if (fgState != null && fgState.affectedPermissions
- .contains(ACCESS_COARSE_LOCATION)) {
- // Request Coarse only
- locationVisibilities[DIALOG_WITH_COARSE_LOCATION_ONLY] = true
- message = RequestMessage.FG_COARSE_LOCATION_MESSAGE
- }
+ val behavior = getGrantBehavior(groupState.group)
+ val isSystemTriggered =
+ groupState.affectedPermissions.any { it in systemRequestedPermissions }
+ val prompt =
+ behavior.getPrompt(
+ groupState.group,
+ groupState.affectedPermissions,
+ isSystemTriggered
+ )
+ if (prompt == Prompt.NO_UI_REJECT_ALL_GROUPS) {
+ value = null
+ return
}
- }
-
- if (SdkLevel.isAtLeastT()) {
- // If app is T+, requests for the STORAGE group are ignored
- if (packageInfo.targetSdkVersion > Build.VERSION_CODES.S_V2 &&
- groupState.group.permGroupName == Manifest.permission_group.STORAGE) {
+ if (prompt == Prompt.NO_UI_REJECT_THIS_GROUP) {
+ reportRequestResult(
+ groupState.affectedPermissions,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED
+ )
continue
}
- // If app is <T and requests STORAGE, grant dialogs has special text
- if (groupState.group.permGroupName in
- PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
- if (packageInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
- message = RequestMessage.STORAGE_SUPERGROUP_MESSAGE_PRE_Q
- } else if (packageInfo.targetSdkVersion <= Build.VERSION_CODES.S_V2) {
- message = RequestMessage.STORAGE_SUPERGROUP_MESSAGE_Q_TO_S
- }
- }
- }
-
- val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel
- val showPermissionRationale =
- shouldShowPermissionRationale(safetyLabel, groupState.group.permGroupName)
- buttonVisibilities[LINK_TO_PERMISSION_RATIONALE] = showPermissionRationale
-
- requestInfos.add(RequestInfo(
- groupInfo,
- buttonVisibilities,
- locationVisibilities,
- message,
- detailMessage))
- }
-
- sortPermissionGroups(requestInfos)
- value = if (requestInfos.any { it.sendToSettingsImmediately } &&
- requestInfos.size > 1) {
- Log.e(LOG_TAG, "For R+ apps, background permissions must be requested " +
- "individually")
- null
- } else {
- requestInfos
+ val denyBehavior =
+ behavior.getDenyButton(
+ groupState.group,
+ groupState.affectedPermissions,
+ prompt
+ )
+ val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel
+ requestInfos.add(
+ RequestInfo(
+ groupState.group.permGroupInfo,
+ prompt,
+ denyBehavior,
+ shouldShowPermissionRationale(
+ safetyLabel,
+ groupState.group.permGroupName
+ ),
+ deviceId
+ )
+ )
+ }
+ sortPermissionGroups(requestInfos)
+
+ value =
+ if (
+ requestInfos.any { it.prompt == Prompt.NO_UI_SETTINGS_REDIRECT } &&
+ requestInfos.size > 1
+ ) {
+ Log.e(
+ LOG_TAG,
+ "For R+ apps, background permissions must be requested " +
+ "individually"
+ )
+ null
+ } else {
+ requestInfos
+ }
}
}
- }
- fun sortPermissionGroups(requestInfos: MutableList<RequestInfo>) {
+ private fun sortPermissionGroups(requestInfos: MutableList<RequestInfo>) {
requestInfos.sortWith { rhs, lhs ->
- val rhsHasOneTime = rhs.buttonVisibilities[ALLOW_ONE_TIME_BUTTON]
- val lhsHasOneTime = lhs.buttonVisibilities[ALLOW_ONE_TIME_BUTTON]
+ val rhsHasOneTime = isOneTimePrompt(rhs.prompt)
+ val lhsHasOneTime = isOneTimePrompt(lhs.prompt)
if (rhsHasOneTime && !lhsHasOneTime) {
-1
- } else if ((!rhsHasOneTime && lhsHasOneTime) ||
- isHealthPermissionGroup(rhs.groupName)
+ } else if (
+ (!rhsHasOneTime && lhsHasOneTime) || Utils.isHealthPermissionGroup(rhs.groupName)
) {
1
} else {
@@ -628,6 +425,18 @@ class GrantPermissionsViewModel(
}
}
+ private fun isOneTimePrompt(prompt: Prompt): Boolean {
+ return prompt in
+ setOf(
+ Prompt.ONE_TIME_FG,
+ Prompt.SETTINGS_LINK_WITH_OT,
+ Prompt.LOCATION_TWO_BUTTON_COARSE_HIGHLIGHT,
+ Prompt.LOCATION_TWO_BUTTON_FINE_HIGHLIGHT,
+ Prompt.LOCATION_COARSE_ONLY,
+ Prompt.LOCATION_FINE_UPGRADE
+ )
+ }
+
private fun shouldShowPermissionRationale(
safetyLabel: SafetyLabel?,
permissionGroupName: String?
@@ -636,70 +445,65 @@ class GrantPermissionsViewModel(
return false
}
- val purposes = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(safetyLabel,
- permissionGroupName)
+ val purposes =
+ SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(safetyLabel, permissionGroupName)
return purposes.isNotEmpty()
}
/**
- * Converts a list of LightAppPermGroups into a list of GroupStates
+ * Converts a list of LightAppPermGroups into a list of GroupStates, and adds new GroupState
+ * objects to the tracked groupStates.
*/
- private fun getRequiredGroupStates(
- groups: List<LightAppPermGroup>
- ): MutableMap<Pair<String, Boolean>, GroupState> {
- val groupStates = mutableMapOf<Pair<String, Boolean>, GroupState>()
- val filteredPermissions = unfilteredAffectedPermissions.filter { perm ->
- val group = getGroupWithPerm(perm, groups)
- group != null && isPermissionGrantableAndNotFixed(perm, group)
- }
+ private fun addRequiredGroupStates(groups: List<LightAppPermGroup>) {
+ val filteredPermissions =
+ unfilteredAffectedPermissions.filter { perm ->
+ val group = getGroupWithPerm(perm, groups)
+ group != null && isPermissionGrantableAndNotFixed(perm, group)
+ }
+ val newGroupStates = mutableMapOf<String, GroupState>()
for (perm in filteredPermissions) {
val group = getGroupWithPerm(perm, groups)!!
- val isBackground = perm in group.backgroundPermNames
- val groupStateInfo = groupStates.getOrPut(group.permGroupName to isBackground) {
- GroupState(group, isBackground)
+ val oldGroupState = groupStates[group.permGroupName]
+ if (!isStateUnknown(oldGroupState?.state)) {
+ // we've already dealt with this group
+ continue
}
- var currGroupState = groupStateInfo.state
- if (storedState != null && currGroupState != STATE_UNKNOWN) {
- currGroupState = storedState.getInt(getInstanceStateKey(group.permGroupName,
- isBackground), STATE_UNKNOWN)
+ val groupState = newGroupStates.getOrPut(group.permGroupName) { GroupState(group) }
+
+ var currGroupState = groupState.state
+ if (storedState != null && !isStateUnknown(groupState.state)) {
+ currGroupState = storedState.getInt(group.permGroupName, STATE_UNKNOWN)
}
- val otherGroupPermissions = filteredPermissions.filter { it in group.permissions }
- val groupStateOfPerm = getGroupState(perm, group, otherGroupPermissions)
+ val otherAffectedPermissionsInGroup =
+ filteredPermissions.filter { it in group.permissions }.toSet()
+ val groupStateOfPerm = getGroupState(perm, group, otherAffectedPermissionsInGroup)
if (groupStateOfPerm != STATE_UNKNOWN) {
+ // update the state if it is allowed, denied, or granted in foreground
currGroupState = groupStateOfPerm
}
- if (group.permGroupName in permGroupsToSkip) {
- currGroupState = STATE_SKIPPED
- }
-
if (currGroupState != STATE_UNKNOWN) {
- groupStateInfo.state = currGroupState
+ groupState.state = currGroupState
}
- // If we saved state, load it
- groupStateInfo.affectedPermissions.add(perm)
+
+ groupState.affectedPermissions.add(perm)
}
- return groupStates
+ newGroupStates.forEach { (groupName, groupState) -> groupStates[groupName] = groupState }
}
/**
- * Get the actually requested permissions when a permission is requested.
- *
- * >In some cases requesting to grant a single permission requires the system to grant
- * additional permissions. E.g. before N-MR1 a single permission of a group caused the whole
- * group to be granted. Another case are permissions that are split into two. For apps that
- * target an SDK before the split, this method automatically adds the split off permission.
+ * Add additional permissions that should be granted in this request. For permissions that have
+ * split permissions, and apps that target an SDK before the split, this method automatically
+ * adds the split off permission.
*
* @param perm The requested permission
- *
- * @return The actually requested permissions
+ * @return The requested permissions plus any needed split permissions
*/
- private fun computeAffectedPermissions(
+ private fun getAffectedSplitPermissions(
perm: String,
- appPermissions: Map<String, List<String>>
): List<String> {
val requestingAppTargetSDK = packageInfo.targetSdkVersion
@@ -709,53 +513,30 @@ class GrantPermissionsViewModel(
val splitPerms = app.getSystemService(PermissionManager::class.java)!!.splitPermissions
for (splitPerm in splitPerms) {
-
if (requestingAppTargetSDK < splitPerm.targetSdk && perm == splitPerm.splitPermission) {
extendedBySplitPerms.addAll(splitPerm.newPermissions)
}
}
-
- // For <= N_MR1 apps all permissions of the groups of the requested permissions are affected
- if (requestingAppTargetSDK <= Build.VERSION_CODES.N_MR1) {
- val extendedBySplitPermsAndGroup = mutableListOf<String>()
-
- for (splitPerm in extendedBySplitPerms) {
- val groups = appPermissions.filter { splitPerm in it.value }
- if (groups.isEmpty()) {
- continue
- }
-
- val permissionsInGroup = groups.values.first()
- for (permissionInGroup in permissionsInGroup) {
- extendedBySplitPermsAndGroup.add(permissionInGroup)
- }
- }
-
- return extendedBySplitPermsAndGroup
- } else {
- return extendedBySplitPerms
- }
+ return extendedBySplitPerms
}
private fun isPermissionGrantableAndNotFixed(perm: String, group: LightAppPermGroup): Boolean {
-
// If the permission is restricted it does not show in the UI and
// is not added to the group at all, so check that first.
if (perm in group.packageInfo.requestedPermissions && perm !in group.permissions) {
- reportRequestResult(perm,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION)
+ reportRequestResult(
+ perm,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION
+ )
return false
}
- if (HEALTH_PERMISSION_GROUP == group.permGroupName) {
- return !(group.permissions[perm]?.isUserFixed ?: true)
- }
-
- val subGroup = if (perm in group.backgroundPermNames) {
- group.background
- } else {
- group.foreground
- }
+ val subGroup =
+ if (perm in group.backgroundPermNames) {
+ group.background
+ } else {
+ group.foreground
+ }
val lightPermission = group.permissions[perm] ?: return false
@@ -763,27 +544,22 @@ class GrantPermissionsViewModel(
reportRequestResult(perm, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED)
// Skip showing groups that we know cannot be granted.
return false
- } else if (subGroup.isUserFixed) {
- if (perm == ACCESS_COARSE_LOCATION) {
- val coarsePerm = group.permissions[perm]
- if (coarsePerm != null && !coarsePerm.isUserFixed) {
- // If the location group is user fixed but ACCESS_COARSE_LOCATION is not, then
- // ACCESS_FINE_LOCATION must be user fixed. In this case ACCESS_COARSE_LOCATION
- // is still grantable.
- return true
- }
- } else if (perm in getPartialStorageGrantPermissionsForGroup(group) &&
- lightPermission.isGrantedIncludingAppOp) {
- // If a partial storage permission is granted as fixed, we should immediately show
- // the photo picker
- return true
- }
- reportRequestResult(perm,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED)
+ }
+
+ if (subGroup.isPolicyFixed && !subGroup.isGranted || lightPermission.isPolicyFixed) {
+ reportRequestResult(
+ perm,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED
+ )
return false
- } else if (subGroup.isPolicyFixed && !subGroup.isGranted || lightPermission.isPolicyFixed) {
- reportRequestResult(perm,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED)
+ }
+
+ val behavior = getGrantBehavior(group)
+ if (behavior.isPermissionFixed(group, perm)) {
+ reportRequestResult(
+ perm,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED
+ )
return false
}
@@ -793,151 +569,94 @@ class GrantPermissionsViewModel(
private fun getGroupState(
perm: String,
group: LightAppPermGroup,
- groupRequestedPermissions: List<String>
+ groupRequestedPermissions: Set<String>
): Int {
val policyState = getStateFromPolicy(perm, group)
- if (policyState != STATE_UNKNOWN) {
+ if (!isStateUnknown(policyState)) {
return policyState
}
- if (perm == POST_NOTIFICATIONS &&
- packageInfo.targetSdkVersion <= Build.VERSION_CODES.S_V2 &&
- group.foreground.isUserSet) {
- return STATE_SKIPPED
- } else if (perm == READ_MEDIA_VISUAL_USER_SELECTED) {
- val partialPerms = getPartialStorageGrantPermissionsForGroup(group)
- val otherRequestedPerms = unfilteredAffectedPermissions.filter { otherPerm ->
- otherPerm in group.permissions && otherPerm !in partialPerms
- }
- if (otherRequestedPerms.isEmpty()) {
- // If the app requested USER_SELECTED while not supporting the photo picker, or if
- // the app explicitly requested only USER_SELECTED and/or ACCESS_MEDIA_LOCATION,
- // then skip the request
- return STATE_SKIPPED
- }
- }
-
val isBackground = perm in group.backgroundPermNames
- val hasForegroundRequest = groupRequestedPermissions.any {
- it !in group.backgroundPermNames
- }
-
- // Do not attempt to grant background access if foreground access is not either already
- // granted or requested
- if (isBackground && !group.foreground.isGrantedExcludingRWROrAllRWR &&
- !hasForegroundRequest) {
- Log.w(LOG_TAG, "Cannot grant $perm as the matching foreground permission is not " +
- "already granted.")
- val affectedPermissions = groupRequestedPermissions.filter {
- it in group.backgroundPermNames
- }
- reportRequestResult(affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED)
- return STATE_SKIPPED
- }
-
- if ((isBackground && group.background.isGrantedExcludingRWROrAllRWR ||
- !isBackground && group.foreground.isGrantedExcludingRWROrAllRWR) &&
- canAutoGrantWholeGroup(group)) {
+ val behavior = getGrantBehavior(group)
+ return if (behavior.isGroupFullyGranted(group, groupRequestedPermissions)) {
if (group.permissions[perm]?.isGrantedIncludingAppOp == false) {
if (isBackground) {
grantBackgroundRuntimePermissions(app, group, listOf(perm))
} else {
grantForegroundRuntimePermissions(app, group, listOf(perm), group.isOneTime)
}
- KotlinUtils.setGroupFlags(app, group, FLAG_PERMISSION_USER_SET to false,
- FLAG_PERMISSION_USER_FIXED to false, filterPermissions = listOf(perm))
- reportRequestResult(perm,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED)
- }
-
- return if (storedState == null) {
- STATE_SKIPPED
- } else {
- STATE_ALLOWED
+ KotlinUtils.setGroupFlags(
+ app,
+ group,
+ FLAG_PERMISSION_USER_SET to false,
+ FLAG_PERMISSION_USER_FIXED to false,
+ filterPermissions = listOf(perm)
+ )
+ reportRequestResult(
+ perm,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED
+ )
}
- }
- return STATE_UNKNOWN
- }
-
- /**
- * Determines if remaining permissions in the group can be auto granted based on
- * granted permissions in the group.
- */
- private fun canAutoGrantWholeGroup(group: LightAppPermGroup): Boolean {
- // If FINE location is not granted, do not grant it automatically when COARSE
- // location is already granted.
- if (group.permGroupName == LOCATION &&
- group.allPermissions[ACCESS_FINE_LOCATION]?.isGrantedIncludingAppOp == false) {
- return false
- }
- // If READ_MEDIA_VISUAL_USER_SELECTED is the only permission in the group that is granted,
- // do not grant.
- if (isPartialStorageGrant(group) || HEALTH_PERMISSION_GROUP == group.permGroupName) {
- return false
- }
- return true
- }
-
- /**
- * A partial storage grant happens when:
- * An app which doesn't support the photo picker has READ_MEDIA_VISUAL_USER_SELECTED granted, or
- * An app which does support the photo picker has READ_MEDIA_VISUAL_USER_SELECTED and/or
- * ACCESS_MEDIA_LOCATION granted
- */
- private fun isPartialStorageGrant(group: LightAppPermGroup): Boolean {
- if (!KotlinUtils.isPhotoPickerPromptEnabled() || group.permGroupName != READ_MEDIA_VISUAL) {
- return false
- }
-
- val partialPerms = getPartialStorageGrantPermissionsForGroup(group)
- return group.isGranted && group.permissions.values.all {
- it.name in partialPerms || (it.name !in partialPerms && !it.isGrantedIncludingAppOp)
+ STATE_GRANTED
+ } else if (behavior.isForegroundFullyGranted(group, groupRequestedPermissions)) {
+ STATE_FG_GRANTED_BG_UNKNOWN
+ } else {
+ STATE_UNKNOWN
}
}
private fun getStateFromPolicy(perm: String, group: LightAppPermGroup): Int {
val isBackground = perm in group.backgroundPermNames
- var skipGroup = false
var state = STATE_UNKNOWN
when (permissionPolicy) {
DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT -> {
- if (AdminRestrictedPermissionsUtils.mayAdminGrantPermission(
- app, perm, user.identifier)) {
+ if (
+ AdminRestrictedPermissionsUtils.mayAdminGrantPermission(
+ app,
+ perm,
+ user.identifier
+ )
+ ) {
if (isBackground) {
grantBackgroundRuntimePermissions(app, group, listOf(perm))
} else {
grantForegroundRuntimePermissions(app, group, listOf(perm))
}
- KotlinUtils.setGroupFlags(app, group, FLAG_PERMISSION_POLICY_FIXED to true,
- FLAG_PERMISSION_USER_SET to false, FLAG_PERMISSION_USER_FIXED to false,
- filterPermissions = listOf(perm))
- state = STATE_ALLOWED
- skipGroup = true
-
+ KotlinUtils.setGroupFlags(
+ app,
+ group,
+ FLAG_PERMISSION_POLICY_FIXED to true,
+ FLAG_PERMISSION_USER_SET to false,
+ FLAG_PERMISSION_USER_FIXED to false,
+ filterPermissions = listOf(perm)
+ )
+ state = STATE_GRANTED
getAutoGrantNotifier().onPermissionAutoGranted(perm)
- reportRequestResult(perm,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED)
+ reportRequestResult(
+ perm,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED
+ )
}
}
-
DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY -> {
if (group.permissions[perm]?.isPolicyFixed == false) {
- KotlinUtils.setGroupFlags(app, group, FLAG_PERMISSION_POLICY_FIXED to true,
- FLAG_PERMISSION_USER_SET to false, FLAG_PERMISSION_USER_FIXED to false,
- filterPermissions = listOf(perm))
+ KotlinUtils.setGroupFlags(
+ app,
+ group,
+ FLAG_PERMISSION_POLICY_FIXED to true,
+ FLAG_PERMISSION_USER_SET to false,
+ FLAG_PERMISSION_USER_FIXED to false,
+ filterPermissions = listOf(perm)
+ )
}
state = STATE_DENIED
- skipGroup = true
-
- reportRequestResult(perm,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED)
+ reportRequestResult(
+ perm,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED
+ )
}
}
- if (skipGroup && storedState == null) {
- return STATE_SKIPPED
- }
return state
}
@@ -967,98 +686,83 @@ class GrantPermissionsViewModel(
}
// If this is a legacy app, and a storage group is requested: request all storage groups
- if (!alreadyRequestedStorageGroupsIfNeeded &&
- groupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS &&
- packageInfo.targetSdkVersion <= Build.VERSION_CODES.S_V2) {
+ if (
+ !alreadyRequestedStorageGroupsIfNeeded &&
+ groupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS &&
+ packageInfo.targetSdkVersion <= Build.VERSION_CODES.S_V2
+ ) {
for (storageGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
- val groupPerms = appPermGroupLiveDatas[storageGroupName]
- ?.value?.allPermissions?.keys?.toList()
+ val groupPerms =
+ appPermGroupLiveDatas[storageGroupName]?.value?.allPermissions?.keys?.toList()
onPermissionGrantResult(storageGroupName, groupPerms, result, true)
}
return
}
- val foregroundGroupState = groupStates[groupName to false]
- val backgroundGroupState = groupStates[groupName to true]
+ val groupState = groupStates[groupName] ?: return
when (result) {
CANCELED -> {
- if (foregroundGroupState != null) {
- reportRequestResult(foregroundGroupState.affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_IGNORED)
- foregroundGroupState.state = STATE_SKIPPED
- }
- if (backgroundGroupState != null) {
- reportRequestResult(backgroundGroupState.affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_IGNORED)
- backgroundGroupState.state = STATE_SKIPPED
- }
+ reportRequestResult(
+ groupState.affectedPermissions,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_IGNORED
+ )
+ groupState.state = STATE_SKIPPED
requestInfosLiveData.update()
return
}
GRANTED_ALWAYS -> {
- if (foregroundGroupState != null) {
- onPermissionGrantResultSingleState(foregroundGroupState,
- affectedForegroundPermissions, granted = true, isOneTime = false,
- doNotAskAgain = false)
- }
- if (backgroundGroupState != null) {
- onPermissionGrantResultSingleState(backgroundGroupState,
- affectedForegroundPermissions, granted = true, isOneTime = false,
- doNotAskAgain = false)
- }
+ onPermissionGrantResultSingleState(
+ groupState,
+ affectedForegroundPermissions,
+ granted = true,
+ isOneTime = false,
+ foregroundOnly = false,
+ doNotAskAgain = false
+ )
}
GRANTED_FOREGROUND_ONLY -> {
- if (foregroundGroupState != null) {
- onPermissionGrantResultSingleState(foregroundGroupState,
- affectedForegroundPermissions, granted = true, isOneTime = false,
- doNotAskAgain = false)
- }
- if (backgroundGroupState != null) {
- onPermissionGrantResultSingleState(backgroundGroupState,
- affectedForegroundPermissions, granted = false, isOneTime = false,
- doNotAskAgain = false)
- }
+ onPermissionGrantResultSingleState(
+ groupState,
+ affectedForegroundPermissions,
+ granted = true,
+ isOneTime = false,
+ foregroundOnly = true,
+ doNotAskAgain = false
+ )
}
GRANTED_ONE_TIME -> {
- if (foregroundGroupState != null) {
- onPermissionGrantResultSingleState(foregroundGroupState,
- affectedForegroundPermissions, granted = true, isOneTime = true,
- doNotAskAgain = false)
- }
- if (backgroundGroupState != null) {
- onPermissionGrantResultSingleState(backgroundGroupState,
- affectedForegroundPermissions, granted = false, isOneTime = true,
- doNotAskAgain = false)
- }
+ onPermissionGrantResultSingleState(
+ groupState,
+ affectedForegroundPermissions,
+ granted = true,
+ isOneTime = true,
+ foregroundOnly = false,
+ doNotAskAgain = false
+ )
}
- GRANTED_USER_SELECTED, DENIED_MORE -> {
- if (foregroundGroupState != null) {
- grantUserSelectedVisualGroupPermissions(foregroundGroupState)
- }
+ GRANTED_USER_SELECTED,
+ DENIED_MORE -> {
+ grantUserSelectedVisualGroupPermissions(groupState)
}
DENIED -> {
- if (foregroundGroupState != null) {
- onPermissionGrantResultSingleState(foregroundGroupState,
- affectedForegroundPermissions, granted = false, isOneTime = false,
- doNotAskAgain = false)
- }
- if (backgroundGroupState != null) {
- onPermissionGrantResultSingleState(backgroundGroupState,
- affectedForegroundPermissions, granted = false, isOneTime = false,
- doNotAskAgain = false)
- }
+ onPermissionGrantResultSingleState(
+ groupState,
+ affectedForegroundPermissions,
+ granted = false,
+ isOneTime = false,
+ foregroundOnly = false,
+ doNotAskAgain = false
+ )
}
DENIED_DO_NOT_ASK_AGAIN -> {
- if (foregroundGroupState != null) {
- onPermissionGrantResultSingleState(foregroundGroupState,
- affectedForegroundPermissions, granted = false, isOneTime = false,
- doNotAskAgain = true)
- }
- if (backgroundGroupState != null) {
- onPermissionGrantResultSingleState(backgroundGroupState,
- affectedForegroundPermissions, granted = false, isOneTime = false,
- doNotAskAgain = true)
- }
+ onPermissionGrantResultSingleState(
+ groupState,
+ affectedForegroundPermissions,
+ granted = false,
+ isOneTime = false,
+ foregroundOnly = false,
+ doNotAskAgain = true
+ )
}
}
}
@@ -1067,32 +771,61 @@ class GrantPermissionsViewModel(
val userSelectedPerm =
groupState.group.permissions[READ_MEDIA_VISUAL_USER_SELECTED] ?: return
if (userSelectedPerm.isImplicit) {
- val nonSelectedPerms = groupState.group.permissions.keys
- .filter { it != READ_MEDIA_VISUAL_USER_SELECTED }
+ val nonSelectedPerms =
+ groupState.group.permissions.keys.filter { it != READ_MEDIA_VISUAL_USER_SELECTED }
// If the permission is implicit, grant USER_SELECTED as user set, and all other
// permissions as one time, and without app ops.
- grantForegroundRuntimePermissions(app, groupState.group,
- listOf(READ_MEDIA_VISUAL_USER_SELECTED))
- grantForegroundRuntimePermissions(app, groupState.group,
- nonSelectedPerms, isOneTime = true, userFixed = false, withoutAppOps = true)
- val appPermGroup = AppPermissionGroup.create(app, packageName,
- groupState.group.permGroupName, groupState.group.userHandle, false)
+ grantForegroundRuntimePermissions(
+ app,
+ groupState.group,
+ listOf(READ_MEDIA_VISUAL_USER_SELECTED)
+ )
+ grantForegroundRuntimePermissions(
+ app,
+ groupState.group,
+ nonSelectedPerms,
+ isOneTime = true,
+ userFixed = false,
+ withoutAppOps = true
+ )
+ val appPermGroup =
+ AppPermissionGroup.create(
+ app,
+ packageName,
+ groupState.group.permGroupName,
+ groupState.group.userHandle,
+ false
+ )
appPermGroup.setSelfRevoked()
appPermGroup.persistChanges(false, null, nonSelectedPerms.toSet())
} else {
- val partialPerms = getPartialStorageGrantPermissionsForGroup(groupState.group).filter {
- it in groupState.affectedPermissions
- }
+ val partialPerms =
+ getPartialStorageGrantPermissionsForGroup(groupState.group).filter {
+ it in groupState.affectedPermissions
+ }
val nonSelectedPerms = groupState.affectedPermissions.filter { it !in partialPerms }
val setUserFixed = userSelectedPerm.isUserFixed || userSelectedPerm.isUserSet
- grantForegroundRuntimePermissions(app, groupState.group,
- partialPerms.toList(), userFixed = setUserFixed)
- revokeForegroundRuntimePermissions(app, groupState.group,
- userFixed = setUserFixed, oneTime = false, filterPermissions = nonSelectedPerms)
+ grantForegroundRuntimePermissions(
+ app,
+ groupState.group,
+ partialPerms.toList(),
+ userFixed = setUserFixed
+ )
+ revokeForegroundRuntimePermissions(
+ app,
+ groupState.group,
+ userFixed = setUserFixed,
+ oneTime = false,
+ filterPermissions = nonSelectedPerms
+ )
}
- groupState.state = STATE_ALLOWED
- reportButtonClickResult(groupState, true,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__PHOTOS_SELECTED)
+ groupState.state = STATE_GRANTED
+ reportButtonClickResult(
+ groupState,
+ groupState.affectedPermissions,
+ true,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__PHOTOS_SELECTED
+ )
}
@SuppressLint("NewApi")
@@ -1100,75 +833,127 @@ class GrantPermissionsViewModel(
groupState: GroupState,
affectedForegroundPermissions: List<String>?,
granted: Boolean,
+ foregroundOnly: Boolean,
isOneTime: Boolean,
doNotAskAgain: Boolean
) {
- if (groupState.state != STATE_UNKNOWN) {
+ if (!isStateUnknown(groupState.state)) {
// We already dealt with this group, don't re-grant/re-revoke
return
}
+ val shouldAffectBackgroundPermissions =
+ groupState.bgPermissions.isNotEmpty() && !foregroundOnly
+ val shouldAffectForegroundPermssions = groupState.state != STATE_FG_GRANTED_BG_UNKNOWN
val result: Int
if (granted) {
- result = if (isOneTime) {
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_ONE_TIME
- } else {
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED
- }
- if (groupState.isBackground) {
- grantBackgroundRuntimePermissions(app, groupState.group,
- groupState.affectedPermissions)
- } else {
+ result =
+ if (isOneTime) {
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_ONE_TIME
+ } else {
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED
+ }
+ if (shouldAffectBackgroundPermissions) {
+ grantBackgroundRuntimePermissions(
+ app,
+ groupState.group,
+ groupState.affectedPermissions
+ )
+ } else if (shouldAffectForegroundPermssions) {
if (affectedForegroundPermissions == null) {
- grantForegroundRuntimePermissions(app, groupState.group,
- groupState.affectedPermissions, isOneTime)
+ grantForegroundRuntimePermissions(
+ app,
+ groupState.group,
+ groupState.affectedPermissions,
+ isOneTime
+ )
// This prevents weird flag state when app targetSDK switches from S+ to R-
if (groupState.affectedPermissions.contains(ACCESS_FINE_LOCATION)) {
- KotlinUtils.setFlagsWhenLocationAccuracyChanged(
- app, groupState.group, true)
+ KotlinUtils.setFlagsWhenLocationAccuracyChanged(app, groupState.group, true)
}
} else {
- val newGroup = grantForegroundRuntimePermissions(app,
- groupState.group, affectedForegroundPermissions, isOneTime)
+ val newGroup =
+ grantForegroundRuntimePermissions(
+ app,
+ groupState.group,
+ affectedForegroundPermissions,
+ isOneTime
+ )
if (!isOneTime || newGroup.isOneTime) {
- KotlinUtils.setFlagsWhenLocationAccuracyChanged(app, newGroup,
- affectedForegroundPermissions.contains(ACCESS_FINE_LOCATION))
+ KotlinUtils.setFlagsWhenLocationAccuracyChanged(
+ app,
+ newGroup,
+ affectedForegroundPermissions.contains(ACCESS_FINE_LOCATION)
+ )
}
}
}
- groupState.state = STATE_ALLOWED
+ groupState.state = STATE_GRANTED
} else {
- if (groupState.isBackground) {
- revokeBackgroundRuntimePermissions(app, groupState.group,
- userFixed = doNotAskAgain, filterPermissions = groupState.affectedPermissions)
- } else {
- if (affectedForegroundPermissions == null ||
- affectedForegroundPermissions.contains(ACCESS_COARSE_LOCATION)) {
- revokeForegroundRuntimePermissions(app, groupState.group,
+ if (shouldAffectBackgroundPermissions) {
+ revokeBackgroundRuntimePermissions(
+ app,
+ groupState.group,
+ userFixed = doNotAskAgain,
+ filterPermissions = groupState.affectedPermissions
+ )
+ } else if (shouldAffectForegroundPermssions) {
+ if (
+ affectedForegroundPermissions == null ||
+ affectedForegroundPermissions.contains(ACCESS_COARSE_LOCATION)
+ ) {
+ revokeForegroundRuntimePermissions(
+ app,
+ groupState.group,
userFixed = doNotAskAgain,
- filterPermissions = groupState.affectedPermissions, oneTime = isOneTime)
+ filterPermissions = groupState.affectedPermissions,
+ oneTime = isOneTime
+ )
} else {
- revokeForegroundRuntimePermissions(app, groupState.group,
+ revokeForegroundRuntimePermissions(
+ app,
+ groupState.group,
userFixed = doNotAskAgain,
- filterPermissions = affectedForegroundPermissions, oneTime = isOneTime)
+ filterPermissions = affectedForegroundPermissions,
+ oneTime = isOneTime
+ )
}
}
- result = if (doNotAskAgain) {
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE
- } else {
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED
- }
+ result =
+ if (doNotAskAgain) {
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE
+ } else {
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED
+ }
groupState.state = STATE_DENIED
}
- reportButtonClickResult(groupState, granted, result)
+ val permissionsChanged =
+ if (foregroundOnly) {
+ groupState.fgPermissions
+ } else {
+ groupState.affectedPermissions
+ }
+ reportButtonClickResult(groupState, permissionsChanged, granted, result)
}
- private fun reportButtonClickResult(groupState: GroupState, granted: Boolean, result: Int) {
- reportRequestResult(groupState.affectedPermissions, result)
+ private fun reportButtonClickResult(
+ groupState: GroupState,
+ permissions: Set<String>,
+ granted: Boolean,
+ result: Int
+ ) {
+ reportRequestResult(permissions, result)
// group state has changed, reload liveData
requestInfosLiveData.update()
- PermissionDecisionStorageImpl.recordPermissionDecision(app.applicationContext,
- packageName, groupState.group.permGroupName, granted)
- PermissionChangeStorageImpl.recordPermissionChange(packageName)
+
+ if (SdkLevel.isAtLeastT()) {
+ PermissionDecisionStorageImpl.recordPermissionDecision(
+ app.applicationContext,
+ packageName,
+ groupState.group.permGroupName,
+ granted
+ )
+ PermissionChangeStorageImpl.recordPermissionChange(packageName)
+ }
if (granted) {
startDrivingDecisionReminderServiceIfNecessary(groupState.group.permGroupName)
}
@@ -1183,7 +968,10 @@ class GrantPermissionsViewModel(
return
}
DrivingDecisionReminderService.startServiceIfCurrentlyRestricted(
- Utils.getUserContext(app, user), packageName, permGroupName)
+ Utils.getUserContext(app, user),
+ packageName,
+ permGroupName
+ )
}
private fun getGroupWithPerm(
@@ -1197,30 +985,8 @@ class GrantPermissionsViewModel(
return groupsWithPerm.first()
}
- /**
- * An internal class which represents the state of a current AppPermissionGroup grant request.
- */
- internal class GroupState(
- internal val group: LightAppPermGroup,
- internal val isBackground: Boolean,
- internal val affectedPermissions: MutableList<String> = mutableListOf(),
- internal var state: Int = STATE_UNKNOWN
- ) {
- override fun toString(): String {
- val stateStr: String = when (state) {
- STATE_UNKNOWN -> "unknown"
- STATE_ALLOWED -> "granted"
- STATE_DENIED -> "denied"
- else -> "skipped"
- }
- return "${group.permGroupName} $isBackground $stateStr $affectedPermissions"
- }
- }
-
- private fun reportRequestResult(permissions: List<String>, result: Int) {
- for (perm in permissions) {
- reportRequestResult(perm, result)
- }
+ private fun reportRequestResult(permissions: Collection<String>, result: Int) {
+ permissions.forEach { reportRequestResult(it, result) }
}
/**
@@ -1231,19 +997,32 @@ class GrantPermissionsViewModel(
*/
private fun reportRequestResult(permission: String, result: Int) {
val isImplicit = permission !in requestedPermissions
- val isPermissionRationaleShown = shouldShowPermissionRationale(
- safetyLabelInfoLiveData?.value?.safetyLabel,
- PermissionMapping.getGroupOfPlatformPermission(permission))
-
- Log.v(LOG_TAG, "Permission grant result requestId=$sessionId " +
- "callingUid=${packageInfo.uid} callingPackage=$packageName permission=$permission " +
- "isImplicit=$isImplicit result=$result " +
- "isPermissionRationaleShown=$isPermissionRationaleShown")
+ val isPermissionRationaleShown =
+ shouldShowPermissionRationale(
+ safetyLabelInfoLiveData?.value?.safetyLabel,
+ PermissionMapping.getGroupOfPlatformPermission(permission)
+ )
+
+ Log.i(
+ LOG_TAG,
+ "Permission grant result requestId=$sessionId " +
+ "callingUid=${packageInfo.uid} " +
+ "callingPackage=$packageName " +
+ "permission=$permission " +
+ "isImplicit=$isImplicit result=$result " +
+ "isPermissionRationaleShown=$isPermissionRationaleShown"
+ )
PermissionControllerStatsLog.write(
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED, sessionId,
- packageInfo.uid, packageName, permission, isImplicit, result,
- isPermissionRationaleShown)
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED,
+ sessionId,
+ packageInfo.uid,
+ packageName,
+ permission,
+ isImplicit,
+ result,
+ isPermissionRationaleShown
+ )
}
/**
@@ -1253,17 +1032,17 @@ class GrantPermissionsViewModel(
* @param outState The bundle in which to store state
*/
fun saveInstanceState(outState: Bundle) {
- for ((groupKey, groupState) in groupStates) {
- val (groupName, isBackground) = groupKey
- outState.putInt(getInstanceStateKey(groupName, isBackground), groupState.state)
+ for ((groupName, groupState) in groupStates) {
+ outState.putInt(groupName, groupState.state)
}
+ activityResultCallback?.let { outState.putInt(SAVED_REQUEST_CODE_KEY, it.requestCode) }
}
/**
* Determine if the activity should return permission state to the caller
*
* @return Whether or not state should be returned. False only if the package is pre-M, true
- * otherwise.
+ * otherwise.
*/
fun shouldReturnPermissionState(): Boolean {
return if (packageInfoLiveData.value != null) {
@@ -1272,33 +1051,45 @@ class GrantPermissionsViewModel(
// Should not be reached, as this method shouldn't be called before data is passed to
// the activity for the first time
try {
- Utils.getUserContext(app, user).packageManager
- .getApplicationInfo(packageName, 0).targetSdkVersion >= Build.VERSION_CODES.M
+ Utils.getUserContext(app, user)
+ .packageManager
+ .getApplicationInfo(packageName, 0)
+ .targetSdkVersion >= Build.VERSION_CODES.M
} catch (e: PackageManager.NameNotFoundException) {
true
}
}
}
- @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
- private fun isHealthPermissionGroup(permGroupName: String): Boolean {
- return SdkLevel.isAtLeastU() && HEALTH_PERMISSION_GROUP.equals(permGroupName)
+ fun handleCallback(data: Intent?, requestCode: Int) {
+ val currCallback = activityResultCallback
+ if (currCallback == null || requestCode != currCallback.requestCode) {
+ return
+ }
+ currCallback.consumer.accept(data)
+ activityResultCallback = null
}
fun handleHealthConnectPermissions(activity: Activity) {
if (activityResultCallback == null) {
- activityResultCallback = Consumer {
- permGroupsToSkip.add(HEALTH_PERMISSION_GROUP)
- requestInfosLiveData.update()
- }
- val healthPermissions = unfilteredAffectedPermissions.filter { permission ->
- isHealthPermission(activity, permission)
- }.toTypedArray()
- val intent: Intent = Intent(ACTION_REQUEST_HEALTH_PERMISSIONS)
- .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
- .putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, healthPermissions)
- .putExtra(Intent.EXTRA_USER, Process.myUserHandle())
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ activityResultCallback =
+ ResultCallback(
+ {
+ groupStates[HEALTH_PERMISSION_GROUP]?.state = STATE_SKIPPED
+ requestInfosLiveData.update()
+ },
+ APP_PERMISSION_REQUEST_CODE
+ )
+ val healthPermissions =
+ unfilteredAffectedPermissions
+ .filter { permission -> isHealthPermission(activity, permission) }
+ .toTypedArray()
+ val intent: Intent =
+ Intent(ACTION_REQUEST_HEALTH_PERMISSIONS)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
+ .putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, healthPermissions)
+ .putExtra(Intent.EXTRA_USER, Process.myUserHandle())
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
activity.startActivityForResult(intent, APP_PERMISSION_REQUEST_CODE)
}
}
@@ -1311,56 +1102,69 @@ class GrantPermissionsViewModel(
*/
fun sendDirectlyToSettings(activity: Activity, groupName: String) {
if (activityResultCallback == null) {
- activityResultCallback = Consumer { data ->
- if (data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED) == null) {
- // User didn't interact, count against rate limit
- val group = groupStates[groupName to false]?.group
- ?: groupStates[groupName to true]?.group ?: return@Consumer
- if (group.background.isUserSet) {
- KotlinUtils.setGroupFlags(app, group, FLAG_PERMISSION_USER_FIXED to true,
- filterPermissions = group.backgroundPermNames)
- } else {
- KotlinUtils.setGroupFlags(app, group, FLAG_PERMISSION_USER_SET to true,
- filterPermissions = group.backgroundPermNames)
- }
- }
+ activityResultCallback =
+ ResultCallback(
+ Consumer { data ->
+ if (data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED) == null) {
+ // User didn't interact, count against rate limit
+ val group = groupStates[groupName]?.group ?: return@Consumer
+ if (group.background.isUserSet) {
+ KotlinUtils.setGroupFlags(
+ app,
+ group,
+ FLAG_PERMISSION_USER_FIXED to true,
+ filterPermissions = group.backgroundPermNames
+ )
+ } else {
+ KotlinUtils.setGroupFlags(
+ app,
+ group,
+ FLAG_PERMISSION_USER_SET to true,
+ filterPermissions = group.backgroundPermNames
+ )
+ }
+ }
- permGroupsToSkip.add(groupName)
- // Update our liveData now that there is a new skipped group
- requestInfosLiveData.update()
- }
+ groupStates[groupName]?.state = STATE_SKIPPED
+ // Update our liveData now that there is a new skipped group
+ requestInfosLiveData.update()
+ },
+ APP_PERMISSION_REQUEST_CODE
+ )
startAppPermissionFragment(activity, groupName)
}
}
- fun openPhotoPicker(activity: Activity, result: Int) {
+ fun openPhotoPicker(activity: Activity) {
if (activityResultCallback != null) {
return
}
- if (groupStates[READ_MEDIA_VISUAL to false]?.affectedPermissions == null) {
+ if (groupStates[READ_MEDIA_VISUAL]?.affectedPermissions == null) {
return
}
- activityResultCallback = Consumer { data ->
- val anySelected = data?.getBooleanExtra(INTENT_PHOTOS_SELECTED, true) == true
- if (anySelected) {
- onPermissionGrantResult(READ_MEDIA_VISUAL, null, result)
- } else {
- onPermissionGrantResult(READ_MEDIA_VISUAL, null, CANCELED)
- }
- requestInfosLiveData.update()
- }
- // A clone profile doesn't have a MediaProvider. If this user is a clone profile, open
- // the photo picker in the parent profile
- val userManager = activity.getSystemService(UserManager::class.java)!!
- val user = if (userManager.isCloneProfile) {
- userManager.getProfileParent(Process.myUserHandle()) ?: Process.myUserHandle()
- } else {
- Process.myUserHandle()
- }
- activity.startActivityForResultAsUser(Intent(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP)
- .putExtra(Intent.EXTRA_UID, packageInfo.uid)
- .setType(KotlinUtils.getMimeTypeForPermissions(unfilteredAffectedPermissions)),
- PHOTO_PICKER_REQUEST_CODE, user)
+ setPhotoPickerCallback()
+ openPhotoPickerForApp(
+ activity,
+ packageInfo.uid,
+ unfilteredAffectedPermissions,
+ PHOTO_PICKER_REQUEST_CODE
+ )
+ }
+
+ private fun setPhotoPickerCallback() {
+ activityResultCallback =
+ ResultCallback(
+ { data ->
+ val anySelected = data?.getBooleanExtra(INTENT_PHOTOS_SELECTED, true) == true
+ if (anySelected) {
+ onPermissionGrantResult(READ_MEDIA_VISUAL, null, GRANTED_USER_SELECTED)
+ } else {
+ onPermissionGrantResult(READ_MEDIA_VISUAL, null, CANCELED)
+ }
+ requestInfosLiveData.update()
+ },
+ PHOTO_PICKER_REQUEST_CODE
+ )
}
/**
@@ -1371,113 +1175,126 @@ class GrantPermissionsViewModel(
*/
fun sendToSettingsFromLink(activity: Activity, groupName: String) {
startAppPermissionFragment(activity, groupName)
- activityResultCallback = Consumer { data ->
- val returnGroupName = data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED)
- if (returnGroupName != null) {
- permGroupsToSkip.add(returnGroupName)
- val result = data.getIntExtra(EXTRA_RESULT_PERMISSION_RESULT, -1)
- logSettingsInteraction(returnGroupName, result)
- requestInfosLiveData.update()
- }
- }
+ activityResultCallback =
+ ResultCallback(
+ { data ->
+ val returnGroupName = data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED)
+ if (returnGroupName != null) {
+ groupStates[returnGroupName]?.state = STATE_SKIPPED
+ val result = data.getIntExtra(EXTRA_RESULT_PERMISSION_RESULT, -1)
+ logSettingsInteraction(returnGroupName, result)
+ requestInfosLiveData.update()
+ }
+ },
+ APP_PERMISSION_REQUEST_CODE
+ )
}
/**
- * Shows the Permission Rationale Dialog. For use with U+ only, otherwise no-op.
- *
- * @param activity The current activity
- * @param groupName The name of the permission group whose fragment should be opened
- */
+ * Shows the Permission Rationale Dialog. For use with U+ only, otherwise no-op.
+ *
+ * @param activity The current activity
+ * @param groupName The name of the permission group whose fragment should be opened
+ */
fun showPermissionRationaleActivity(activity: Activity, groupName: String) {
if (!SdkLevel.isAtLeastU()) {
return
}
- val intent = Intent(activity, PermissionRationaleActivity::class.java).apply {
- putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
- putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
- putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- }
- activityResultCallback = Consumer { data ->
- val returnGroupName = data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED)
- if (returnGroupName != null) {
- permGroupsToSkip.add(returnGroupName)
- val result = data.getIntExtra(EXTRA_RESULT_PERMISSION_RESULT, CANCELED)
- logSettingsInteraction(returnGroupName, result)
- requestInfosLiveData.update()
+ val intent =
+ Intent(activity, PermissionRationaleActivity::class.java).apply {
+ putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
+ putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
}
- }
+ activityResultCallback =
+ ResultCallback(
+ { data ->
+ val returnGroupName = data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED)
+ if (returnGroupName != null) {
+ groupStates[returnGroupName]?.state = STATE_SKIPPED
+ val result = data.getIntExtra(EXTRA_RESULT_PERMISSION_RESULT, CANCELED)
+ logSettingsInteraction(returnGroupName, result)
+ requestInfosLiveData.update()
+ }
+ },
+ APP_PERMISSION_REQUEST_CODE
+ )
activity.startActivityForResult(intent, APP_PERMISSION_REQUEST_CODE)
}
private fun startAppPermissionFragment(activity: Activity, groupName: String) {
- val intent = Intent(Intent.ACTION_MANAGE_APP_PERMISSION)
- .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
- .putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
- .putExtra(Intent.EXTRA_USER, user)
- .putExtra(ManagePermissionsActivity.EXTRA_CALLER_NAME,
- GrantPermissionsActivity::class.java.name)
- .putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ val intent =
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSION)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
+ .putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
+ .putExtra(Intent.EXTRA_USER, user)
+ .putExtra(
+ ManagePermissionsActivity.EXTRA_CALLER_NAME,
+ GrantPermissionsActivity::class.java.name
+ )
+ .putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
activity.startActivityForResult(intent, APP_PERMISSION_REQUEST_CODE)
}
- private fun getInstanceStateKey(groupName: String, isBackground: Boolean): String {
- return "${this::class.java.name}_${groupName}_$isBackground"
+ private fun getGrantBehavior(group: LightAppPermGroup): GrantBehavior {
+ return when (group.permGroupName) {
+ LOCATION -> LocationGrantBehavior
+ HEALTH_PERMISSION_GROUP -> HealthGrantBehavior
+ NOTIFICATIONS -> NotificationGrantBehavior
+ STORAGE,
+ READ_MEDIA_VISUAL,
+ READ_MEDIA_AURAL -> StorageGrantBehavior
+ else -> {
+ if (Utils.hasPermWithBackgroundModeCompat(group)) {
+ BackgroundGrantBehavior
+ } else {
+ BasicGrantBehavior
+ }
+ }
+ }
}
private fun logSettingsInteraction(groupName: String, result: Int) {
- val foregroundGroupState = groupStates[groupName to false]
- val backgroundGroupState = groupStates[groupName to true]
+ val groupState = groupStates[groupName] ?: return
+ val backgroundPerms =
+ groupState.affectedPermissions.filter { it in groupState.group.backgroundPermNames }
+ val foregroundPerms = groupState.affectedPermissions.filter { it !in backgroundPerms }
val deniedPrejudiceInSettings =
PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE_IN_SETTINGS
when (result) {
GRANTED_ALWAYS -> {
- if (foregroundGroupState != null) {
- reportRequestResult(foregroundGroupState.affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS)
- }
- if (backgroundGroupState != null) {
- reportRequestResult(backgroundGroupState.affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS)
- }
+ reportRequestResult(
+ groupState.affectedPermissions,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS
+ )
}
GRANTED_FOREGROUND_ONLY -> {
- if (foregroundGroupState != null) {
- reportRequestResult(foregroundGroupState.affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS)
- }
- if (backgroundGroupState != null) {
- reportRequestResult(backgroundGroupState.affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS)
+ reportRequestResult(
+ foregroundPerms,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED_IN_SETTINGS
+ )
+ if (backgroundPerms.isNotEmpty()) {
+ reportRequestResult(
+ backgroundPerms,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS
+ )
}
}
DENIED -> {
- if (foregroundGroupState != null) {
- reportRequestResult(foregroundGroupState.affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS)
- }
- if (backgroundGroupState != null) {
- reportRequestResult(backgroundGroupState.affectedPermissions,
- PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS)
- }
+ reportRequestResult(
+ groupState.affectedPermissions,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS
+ )
}
DENIED_DO_NOT_ASK_AGAIN -> {
- if (foregroundGroupState != null) {
- reportRequestResult(foregroundGroupState.affectedPermissions,
- deniedPrejudiceInSettings)
- }
- if (backgroundGroupState != null) {
- reportRequestResult(backgroundGroupState.affectedPermissions,
- deniedPrejudiceInSettings)
- }
+ reportRequestResult(groupState.affectedPermissions, deniedPrejudiceInSettings)
}
}
}
- /**
- * Log all permission groups which were requested
- */
+ /** Log all permission groups which were requested */
fun logRequestedPermissionGroups() {
if (groupStates.isEmpty()) {
return
@@ -1491,7 +1308,7 @@ class GrantPermissionsViewModel(
*
* @param groupName The name of the permission group which was interacted with
* @param selectedPrecision Selected precision of the location permission - bit flags indicate
- * which locations were chosen
+ * which locations were chosen
* @param clickedButton The button that was clicked by the user
* @param presentedButtons All buttons which were shown to the user
*/
@@ -1507,74 +1324,59 @@ class GrantPermissionsViewModel(
}
if (!requestInfosLiveData.isInitialized || !packageInfoLiveData.isInitialized) {
- Log.wtf(LOG_TAG, "Logged buttons presented and clicked permissionGroupName=" +
+ Log.wtf(
+ LOG_TAG,
+ "Logged buttons presented and clicked permissionGroupName=" +
"$groupName package=$packageName presentedButtons=$presentedButtons " +
"clickedButton=$clickedButton isPermissionRationaleShown=" +
"$isPermissionRationaleShown sessionId=$sessionId, but requests were not yet" +
- "initialized", IllegalStateException())
+ "initialized",
+ IllegalStateException()
+ )
return
}
- PermissionControllerStatsLog.write(GRANT_PERMISSIONS_ACTIVITY_BUTTON_ACTIONS,
- groupName, packageInfo.uid, packageName, presentedButtons, clickedButton, sessionId,
- packageInfo.targetSdkVersion, selectedPrecision,
- isPermissionRationaleShown)
- Log.v(LOG_TAG, "Logged buttons presented and clicked permissionGroupName=" +
+ PermissionControllerStatsLog.write(
+ GRANT_PERMISSIONS_ACTIVITY_BUTTON_ACTIONS,
+ groupName,
+ packageInfo.uid,
+ packageName,
+ presentedButtons,
+ clickedButton,
+ sessionId,
+ packageInfo.targetSdkVersion,
+ selectedPrecision,
+ isPermissionRationaleShown
+ )
+ Log.i(
+ LOG_TAG,
+ "Logged buttons presented and clicked permissionGroupName=" +
"$groupName uid=${packageInfo.uid} selectedPrecision=$selectedPrecision " +
"package=$packageName presentedButtons=$presentedButtons " +
"clickedButton=$clickedButton isPermissionRationaleShown=" +
"$isPermissionRationaleShown sessionId=$sessionId " +
- "targetSdk=${packageInfo.targetSdkVersion}")
+ "targetSdk=${packageInfo.targetSdkVersion}"
+ )
}
- /**
- * Use the autoGrantNotifier to notify of auto-granted permissions.
- */
+ /** Use the autoGrantNotifier to notify of auto-granted permissions. */
fun autoGrantNotify() {
autoGrantNotifier?.notifyOfAutoGrantPermissions(true)
}
+ private fun isStateUnknown(state: Int?): Boolean {
+ return state == null || state == STATE_UNKNOWN || state == STATE_FG_GRANTED_BG_UNKNOWN
+ }
+
companion object {
const val APP_PERMISSION_REQUEST_CODE = 1
const val PHOTO_PICKER_REQUEST_CODE = 2
+ const val SAVED_REQUEST_CODE_KEY = "saved_request_code"
private const val STATE_UNKNOWN = 0
- private const val STATE_ALLOWED = 1
+ private const val STATE_GRANTED = 1
private const val STATE_DENIED = 2
private const val STATE_SKIPPED = 3
- private const val STATE_ALREADY_ALLOWED = 4
-
- /**
- * An enum that represents the type of message which should be shown- foreground,
- * background, upgrade, or no message.
- */
- enum class RequestMessage {
- FG_MESSAGE,
- BG_MESSAGE,
- UPGRADE_MESSAGE,
- NO_MESSAGE,
- FG_FINE_LOCATION_MESSAGE,
- FG_COARSE_LOCATION_MESSAGE,
- STORAGE_SUPERGROUP_MESSAGE_Q_TO_S,
- STORAGE_SUPERGROUP_MESSAGE_PRE_Q,
- MORE_PHOTOS_MESSAGE,
- }
-
- /**
- * Make a copy of a list of permissions that is filtered to remove permissions blocked
- * according to the target SDK level.
- */
- fun getSanitizedPermissionsList(
- permissions: Array<String?>,
- targetSdkVersion: Int
- ): List<String> {
- return permissions
- .filter { !it.isNullOrEmpty() }
- // POST_NOTIFICATIONS is actively disallowed to be declared by apps below T.
- // Others we don't care as much if they were declared but not used.
- .filter { targetSdkVersion >= Build.VERSION_CODES.TIRAMISU ||
- it != POST_NOTIFICATIONS }
- .filterIsInstance<String>()
- }
+ private const val STATE_FG_GRANTED_BG_UNKNOWN = 4
}
}
@@ -1584,16 +1386,64 @@ class GrantPermissionsViewModel(
* @param app The current application
* @param packageName The name of the package this ViewModel represents
*/
-class GrantPermissionsViewModelFactory(
+class NewGrantPermissionsViewModelFactory(
private val app: Application,
private val packageName: String,
+ private val deviceId: Int,
private val requestedPermissions: List<String>,
+ private val systemRequestedPermissions: List<String>,
private val sessionId: Long,
private val savedState: Bundle?
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
- return GrantPermissionsViewModel(app, packageName, requestedPermissions,
- sessionId, savedState) as T
+ return GrantPermissionsViewModel(
+ app,
+ packageName,
+ deviceId,
+ requestedPermissions,
+ systemRequestedPermissions,
+ sessionId,
+ savedState
+ )
+ as T
}
}
+
+enum class Prompt {
+ BASIC, // Allow/Deny
+ ONE_TIME_FG, // Allow in foreground/one time/deny
+ FG_ONLY, // Allow in foreground/deny
+ SETTINGS_LINK_FOR_BG, // Allow in foreground/deny, with link to settings to change background
+ SETTINGS_LINK_WITH_OT, // Same as above, but with a one time button
+ UPGRADE_SETTINGS_LINK, // Keep foreground, with link to settings to grant background
+ OT_UPGRADE_SETTINGS_LINK, // Same as above, but the button is "keep one time"
+ LOCATION_TWO_BUTTON_COARSE_HIGHLIGHT, // Choose coarse/fine, foreground/one time/deny, coarse
+ // button highlighted
+ LOCATION_TWO_BUTTON_FINE_HIGHLIGHT, // Same as above, but fine location highlighted
+ LOCATION_COARSE_ONLY, // Only coarse location, foreground/one time/deny
+ LOCATION_FINE_UPGRADE, // Upgrade coarse to fine, upgrade to fine/ one time/ keep coarse
+ SELECT_PHOTOS, // Select photos/allow all photos/deny
+ SELECT_MORE_PHOTOS, // Select more photos/allow all photos/don't allow more
+ // These next two are for T+ devices, and < T apps. They request the old "storage" group, and
+ // we "grant" it, while actually granting the new visual and audio groups
+ STORAGE_SUPERGROUP_Q_TO_S, // Allow/deny, special message
+ STORAGE_SUPERGROUP_PRE_Q, // Allow/deny, special message (different from above)
+ NO_UI_SETTINGS_REDIRECT, // Send the user directly to permission settings
+ NO_UI_PHOTO_PICKER_REDIRECT, // Send the user directly to the photo picker
+ NO_UI_HEALTH_REDIRECT, // Send the user directly to the Health Connect settings
+ NO_UI_REJECT_THIS_GROUP, // Auto deny this permission group
+ NO_UI_REJECT_ALL_GROUPS, // Auto deny all permission groups in this request
+ NO_UI_FILTER_THIS_GROUP, // Do not act on this permission group. Remove it from results.
+}
+
+enum class DenyButton {
+ DENY,
+ DENY_DONT_ASK_AGAIN,
+ NO_UPGRADE,
+ NO_UPGRADE_OT,
+ NO_UPGRADE_AND_DONT_ASK_AGAIN,
+ NO_UPGRADE_AND_DONT_ASK_AGAIN_OT,
+ DONT_SELECT_MORE, // used in the SELECT_MORE_PHOTOS dialog
+ NONE,
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt
index 09866870a..bd80a88cd 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageCustomPermissionsViewModel.kt
@@ -35,12 +35,9 @@ import com.android.permissioncontroller.permission.utils.navigateSafe
*
* @param app The current application of the fragment
*/
-class ManageCustomPermissionsViewModel(
- private val app: Application
-) : AndroidViewModel(app) {
+class ManageCustomPermissionsViewModel(private val app: Application) : AndroidViewModel(app) {
- val uiDataLiveData = PermGroupsPackagesUiInfoLiveData(app,
- UsedCustomPermGroupNamesLiveData())
+ val uiDataLiveData = PermGroupsPackagesUiInfoLiveData(app, UsedCustomPermGroupNamesLiveData())
/**
* Navigate to a Permission Apps fragment
@@ -58,12 +55,10 @@ class ManageCustomPermissionsViewModel(
*
* @param app The current application of the fragment
*/
-class ManageCustomPermissionsViewModelFactory(
- private val app: Application
-) : ViewModelProvider.Factory {
+class ManageCustomPermissionsViewModelFactory(private val app: Application) :
+ ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
- @Suppress("UNCHECKED_CAST")
- return ManageCustomPermissionsViewModel(app) as T
+ @Suppress("UNCHECKED_CAST") return ManageCustomPermissionsViewModel(app) as T
}
}
@@ -72,14 +67,13 @@ class ManageCustomPermissionsViewModelFactory(
* package. This includes single-permission permission groups, as well as the Undefined permission
* group, and any other permission groups not defined by the system.
*/
-class UsedCustomPermGroupNamesLiveData :
- SmartUpdateMediatorLiveData<List<String>>() {
+class UsedCustomPermGroupNamesLiveData : SmartUpdateMediatorLiveData<List<String>>() {
init {
- addSource(PermGroupsPackagesLiveData.get(customGroups = true)) {
- value = it.keys.toList()
- }
+ addSource(PermGroupsPackagesLiveData.get(customGroups = true)) { value = it.keys.toList() }
}
- override fun onUpdate() { /* No op override */ }
+ override fun onUpdate() {
+ /* No op override */
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManagePermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManagePermissionsViewModel.kt
index 871a89aeb..f964fb9d2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManagePermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManagePermissionsViewModel.kt
@@ -26,71 +26,71 @@ import com.android.permissioncontroller.permission.model.livedatatypes.PermGroup
/**
* A [androidx.lifecycle.ViewModel] for [ManagePermissionsFragment] and
- * [ManagePermissionsOtherFragment].
- * However, [ManagePermissionsViewModel] is designed in a way so that its owner should be an
- * [Activity][androidx.fragment.app.FragmentActivity] rather than individual
- * [Fragments][androidx.fragment.app.Fragment], and the aforementioned Fragments that manage
- * different sets of the permission groups should to share a single instance of
+ * [ManagePermissionsOtherFragment]. However, [ManagePermissionsViewModel] is designed in a way so
+ * that its owner should be an [Activity][androidx.fragment.app.FragmentActivity] rather than
+ * individual [Fragments][androidx.fragment.app.Fragment], and the aforementioned Fragments that
+ * manage different sets of the permission groups should to share a single instance of
* [ManagePermissionsViewModel].
*/
class ManagePermissionsViewModel(app: Application) : AndroidViewModel(app) {
- /**
- * [LiveData] that contains a list of all platform-defined permission groups.
- */
+ /** [LiveData] that contains a list of all platform-defined permission groups. */
val standardPermGroupsLiveData: LiveData<List<PermGroupPackagesUiInfo>> =
MediatorLiveData<List<PermGroupPackagesUiInfo>>().apply {
addSource(PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData)) {
- permGroups -> value = permGroups.values.filterNotNull()
+ permGroups ->
+ value = permGroups.values.filterNotNull()
}
}
/**
- * [LiveData] that contains a list of platform-defined permission groups, such
- * that at least one the permissions in the group has been requested at runtime by at least one
- * non-system application or has been pregranted to a non-system application.
+ * [LiveData] that contains a list of platform-defined permission groups, such that at least one
+ * the permissions in the group has been requested at runtime by at least one non-system
+ * application or has been pregranted to a non-system application.
+ *
* @see com.android.permissioncontroller.permission.ui.television.ManagePermissionsFragment
*/
val usedPermissionGroups: LiveData<List<PermGroupPackagesUiInfo>> =
MediatorLiveData<List<PermGroupPackagesUiInfo>>().apply {
- addSource(standardPermGroupsLiveData) {
- permGroups -> value = permGroups.filter { it.nonSystemUserSetOrPreGranted > 0 }
+ addSource(standardPermGroupsLiveData) { permGroups ->
+ value = permGroups.filter { it.nonSystemUserSetOrPreGranted > 0 }
}
}
/**
- * [LiveData] that contains a list of platform-defined permission groups, such that all
- * of the permissions in the group neither has been requested at runtime by any of the
- * non-system applications nor has been pregranted to any such application. But at least one of
- * the permissions in the group is requested by or pregranted to at least one system
- * application, other than the Shell (we do not show permission groups that are granted only to
- * the Shell, because it has all the permissions granted).
+ * [LiveData] that contains a list of platform-defined permission groups, such that all of the
+ * permissions in the group neither has been requested at runtime by any of the non-system
+ * applications nor has been pregranted to any such application. But at least one of the
+ * permissions in the group is requested by or pregranted to at least one system application,
+ * other than the Shell (we do not show permission groups that are granted only to the Shell,
+ * because it has all the permissions granted).
+ *
* @see com.android.permissioncontroller.permission.ui.television.ManagePermissionsOtherFragment
*/
val unusedPermissionGroups: LiveData<List<PermGroupPackagesUiInfo>> =
MediatorLiveData<List<PermGroupPackagesUiInfo>>().apply {
- addSource(standardPermGroupsLiveData) {
- permGroups -> value = permGroups
- .filter { it.nonSystemUserSetOrPreGranted == 0 }
- .filter { it.systemUserSetOrPreGranted > 0 }
- .filterNot { it.onlyShellPackageGranted }
+ addSource(standardPermGroupsLiveData) { permGroups ->
+ value =
+ permGroups
+ .filter { it.nonSystemUserSetOrPreGranted == 0 }
+ .filter { it.systemUserSetOrPreGranted > 0 }
+ .filterNot { it.onlyShellPackageGranted }
}
}
/**
- * [LiveData] that contains a list of the application-defined permission groups
- * (a.k.a. "custom" permissions), such that at least one of the permissions in the group has
- * been requested at runtime by or has been pregranted to at least one application (system or
- * non-system).
+ * [LiveData] that contains a list of the application-defined permission groups (a.k.a. "custom"
+ * permissions), such that at least one of the permissions in the group has been requested at
+ * runtime by or has been pregranted to at least one application (system or non-system).
+ *
* @see com.android.permissioncontroller.permission.ui.television.ManagePermissionsOtherFragment
*/
val additionalPermissionGroups: LiveData<List<PermGroupPackagesUiInfo>> =
MediatorLiveData<List<PermGroupPackagesUiInfo>>().apply {
- addSource(PermGroupsPackagesUiInfoLiveData(
- app, UsedCustomPermGroupNamesLiveData())) {
- permGroups -> value = permGroups.values
- .filterNotNull()
- .filter {
+ addSource(PermGroupsPackagesUiInfoLiveData(app, UsedCustomPermGroupNamesLiveData())) {
+ permGroups ->
+ value =
+ permGroups.values.filterNotNull().filter {
(it.nonSystemUserSetOrPreGranted > 0) or (it.systemUserSetOrPreGranted > 0)
}
}
@@ -98,16 +98,18 @@ class ManagePermissionsViewModel(app: Application) : AndroidViewModel(app) {
/**
* [LiveData] that indicates whether there any unused or additional permission groups.
+ *
* @see com.android.permissioncontroller.permission.ui.television.ManagePermissionsFragment
*/
@get:JvmName("hasUnusedOrAdditionalPermissionGroups")
val hasUnusedOrAdditionalPermissionGroups: LiveData<Boolean> =
MediatorLiveData<Boolean>().apply {
val updateValue: (Any?) -> Unit = {
- value = !unusedPermissionGroups.value.isNullOrEmpty() ||
- !additionalPermissionGroups.value.isNullOrEmpty()
+ value =
+ !unusedPermissionGroups.value.isNullOrEmpty() ||
+ !additionalPermissionGroups.value.isNullOrEmpty()
}
addSource(unusedPermissionGroups, updateValue)
addSource(additionalPermissionGroups, updateValue)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt
index e3ddab925..aeab0aa89 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt
@@ -37,16 +37,14 @@ import com.android.permissioncontroller.permission.utils.navigateSafe
/**
* A ViewModel for the ManageStandardPermissionsFragment. Provides a LiveData which watches over all
* platform permission groups, and sends async updates when these groups have changes. It also
- * provides a liveData which watches the custom permission groups of the system, and provides
- * a list of group names.
+ * provides a liveData which watches the custom permission groups of the system, and provides a list
+ * of group names.
+ *
* @param app The current application of the fragment
*/
-class ManageStandardPermissionsViewModel(
- private val app: Application
-) : AndroidViewModel(app) {
+class ManageStandardPermissionsViewModel(private val app: Application) : AndroidViewModel(app) {
- val uiDataLiveData = PermGroupsPackagesUiInfoLiveData(app,
- StandardPermGroupNamesLiveData)
+ val uiDataLiveData = PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData)
val numCustomPermGroups = NumCustomPermGroupsWithPackagesLiveData()
val numAutoRevoked = unusedAutoRevokePackagesLiveData.map { it?.size ?: 0 }
@@ -72,8 +70,7 @@ class ManageStandardPermissionsViewModel(
Utils.navigateToNotificationSettings(fragment.context!!)
return
}
- if (Utils.isHealthPermissionUiEnabled() &&
- groupName == HEALTH_PERMISSION_GROUP) {
+ if (Utils.isHealthPermissionUiEnabled() && groupName == HEALTH_PERMISSION_GROUP) {
Utils.navigateToHealthConnectSettings(fragment.context!!)
return
}
@@ -89,15 +86,12 @@ class ManageStandardPermissionsViewModel(
* A LiveData which tracks the number of custom permission groups that are used by at least one
* package
*/
-class NumCustomPermGroupsWithPackagesLiveData() :
- SmartUpdateMediatorLiveData<Int>() {
+class NumCustomPermGroupsWithPackagesLiveData() : SmartUpdateMediatorLiveData<Int>() {
private val customPermGroupPackages = PermGroupsPackagesLiveData.get(customGroups = true)
init {
- addSource(customPermGroupPackages) {
- update()
- }
+ addSource(customPermGroupPackages) { update() }
}
override fun onUpdate() {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
index 114b8e045..9317e7577 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
@@ -67,9 +67,9 @@ import java.util.concurrent.TimeUnit
import kotlin.math.max
/**
- * ViewModel for the PermissionAppsFragment. Has a liveData with all of the UI info for each
- * package which requests permissions in this permission group, a liveData which tracks whether or
- * not to show system apps, and a liveData tracking whether there are any system apps which request
+ * ViewModel for the PermissionAppsFragment. Has a liveData with all of the UI info for each package
+ * which requests permissions in this permission group, a liveData which tracks whether or not to
+ * show system apps, and a liveData tracking whether there are any system apps which request
* permissions in this group.
*
* @param app The current application
@@ -96,10 +96,8 @@ class PermissionAppsViewModel(
val categorizedAppsLiveData = CategorizedAppsLiveData(groupName)
@get:RequiresApi(Build.VERSION_CODES.S)
- val sensorStatusLiveData: SensorStatusLiveData by lazy(LazyThreadSafetyMode.NONE)
- @RequiresApi(Build.VERSION_CODES.S) {
- SensorStatusLiveData()
- }
+ val sensorStatusLiveData: SensorStatusLiveData by
+ lazy(LazyThreadSafetyMode.NONE) { SensorStatusLiveData() }
fun updateShowSystem(showSystem: Boolean) {
if (showSystem != state.get(SHOULD_SHOW_SYSTEM_KEY)) {
@@ -111,9 +109,7 @@ class PermissionAppsViewModel(
get() = state.get(CREATION_LOGGED_KEY) ?: false
set(value) = state.set(CREATION_LOGGED_KEY, value)
- /**
- * A LiveData that tracks the status (blocked or available) of a sensor
- */
+ /** A LiveData that tracks the status (blocked or available) of a sensor */
@RequiresApi(Build.VERSION_CODES.S)
inner class SensorStatusLiveData() : SmartUpdateMediatorLiveData<Boolean>() {
val sensorPrivacyManager = app.getSystemService(SensorPrivacyManager::class.java)!!
@@ -157,13 +153,9 @@ class PermissionAppsViewModel(
}
}
- private val listener = { _: Int, status: Boolean ->
- value = status
- }
+ private val listener = { _: Int, status: Boolean -> value = status }
- private val locListener = { status: Boolean ->
- value = !status
- }
+ private val locListener = { status: Boolean -> value = !status }
override fun onUpdate() {
// Do nothing
@@ -171,8 +163,9 @@ class PermissionAppsViewModel(
}
inner class CategorizedAppsLiveData(groupName: String) :
- MediatorLiveData<@kotlin.jvm.JvmSuppressWildcards
- Map<Category, List<Pair<String, UserHandle>>>>() {
+ MediatorLiveData<
+ @kotlin.jvm.JvmSuppressWildcards Map<Category, List<Pair<String, UserHandle>>>
+ >() {
private val packagesUiInfoLiveData = SinglePermGroupPackagesUiInfoLiveData[groupName]
init {
@@ -193,18 +186,18 @@ class PermissionAppsViewModel(
}
addSource(packagesUiInfoLiveData) {
- if (fullStorageLiveData == null || fullStorageLiveData.isInitialized)
- update()
+ if (fullStorageLiveData == null || fullStorageLiveData.isInitialized) update()
}
addSource(shouldShowSystemLiveData) {
- if (fullStorageLiveData == null || fullStorageLiveData.isInitialized)
- update()
+ if (fullStorageLiveData == null || fullStorageLiveData.isInitialized) update()
}
- if ((fullStorageLiveData == null || fullStorageLiveData.isInitialized) &&
- packagesUiInfoLiveData.isInitialized) {
- packagesWithFullFileAccess = fullStorageLiveData?.value?.filter { it.isGranted }
- ?: emptyList()
+ if (
+ (fullStorageLiveData == null || fullStorageLiveData.isInitialized) &&
+ packagesUiInfoLiveData.isInitialized
+ ) {
+ packagesWithFullFileAccess =
+ fullStorageLiveData?.value?.filter { it.isGranted } ?: emptyList()
update()
}
}
@@ -218,12 +211,14 @@ class PermissionAppsViewModel(
categoryMap[Category.ASK] = mutableListOf()
categoryMap[Category.DENIED] = mutableListOf()
- val packageMap = packagesUiInfoLiveData.value ?: run {
- if (packagesUiInfoLiveData.isInitialized) {
- value = categoryMap
- }
- return
- }
+ val packageMap =
+ packagesUiInfoLiveData.value
+ ?: run {
+ if (packagesUiInfoLiveData.isInitialized) {
+ value = categoryMap
+ }
+ return
+ }
val hasSystem = packageMap.any { it.value.isSystem && it.value.shouldShow }
if (hasSystem != state.get(HAS_SYSTEM_APPS_KEY)) {
@@ -241,22 +236,31 @@ class PermissionAppsViewModel(
continue
}
- if (uiInfo.permGrantState == PermGrantState.PERMS_ALLOWED_ALWAYS ||
- uiInfo.permGrantState == PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY) {
+ if (
+ uiInfo.permGrantState == PermGrantState.PERMS_ALLOWED_ALWAYS ||
+ uiInfo.permGrantState == PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY
+ ) {
showAlwaysAllowedString = true
}
- var category = when (uiInfo.permGrantState) {
- PermGrantState.PERMS_ALLOWED -> Category.ALLOWED
- PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY -> Category.ALLOWED_FOREGROUND
- PermGrantState.PERMS_ALLOWED_ALWAYS -> Category.ALLOWED
- PermGrantState.PERMS_DENIED -> Category.DENIED
- PermGrantState.PERMS_ASK -> Category.ASK
- }
+ var category =
+ when (uiInfo.permGrantState) {
+ PermGrantState.PERMS_ALLOWED -> Category.ALLOWED
+ PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY -> Category.ALLOWED_FOREGROUND
+ PermGrantState.PERMS_ALLOWED_ALWAYS -> Category.ALLOWED
+ PermGrantState.PERMS_DENIED -> Category.DENIED
+ PermGrantState.PERMS_ASK -> Category.ASK
+ }
- if (!SdkLevel.isAtLeastT() && groupName == Manifest.permission_group.STORAGE &&
- packagesWithFullFileAccess.any { !it.isLegacy && it.isGranted &&
- it.packageName to it.user == packageUserPair }) {
+ if (
+ !SdkLevel.isAtLeastT() &&
+ groupName == Manifest.permission_group.STORAGE &&
+ packagesWithFullFileAccess.any {
+ !it.isLegacy &&
+ it.isGranted &&
+ it.packageName to it.user == packageUserPair
+ }
+ ) {
category = Category.ALLOWED
}
categoryMap[category]!!.add(packageUserPair)
@@ -267,9 +271,9 @@ class PermissionAppsViewModel(
}
/**
- * If this is the storage permission group, some apps have full access to storage, while
- * others just have access to media files. This list contains the packages with full access.
- * To listen for changes, create and observe a FullStoragePermissionAppsLiveData
+ * If this is the storage permission group, some apps have full access to storage, while others
+ * just have access to media files. This list contains the packages with full access. To listen
+ * for changes, create and observe a FullStoragePermissionAppsLiveData
*/
private var packagesWithFullFileAccess = listOf<FullStoragePackageState>()
@@ -280,17 +284,15 @@ class PermissionAppsViewModel(
*
* @param packageName The name of the package we want to check
* @param user The name of the user whose package we want to check
- *
* @return true if the package and user has full file access
*/
fun packageHasFullStorage(packageName: String, user: UserHandle): Boolean {
- return packagesWithFullFileAccess.any {
- it.packageName == packageName && it.user == user }
+ return packagesWithFullFileAccess.any { it.packageName == packageName && it.user == user }
}
/**
- * Whether or not packages have been loaded from the system.
- * To update, need to observe the allPackageInfosLiveData.
+ * Whether or not packages have been loaded from the system. To update, need to observe the
+ * allPackageInfosLiveData.
*
* @return Whether or not all packages have been loaded
*/
@@ -313,16 +315,16 @@ class PermissionAppsViewModel(
args: Bundle
) {
val activity = fragment.activity!!
- if (LocationUtils.isLocationGroupAndProvider(
- activity, groupName, packageName)) {
+ if (LocationUtils.isLocationGroupAndProvider(activity, groupName, packageName)) {
val intent = Intent(activity, LocationProviderInterceptDialog::class.java)
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
activity.startActivityAsUser(intent, user)
return
}
- if (LocationUtils.isLocationGroupAndControllerExtraPackage(
- activity, groupName, packageName)) {
+ if (
+ LocationUtils.isLocationGroupAndControllerExtraPackage(activity, groupName, packageName)
+ ) {
// Redirect to location controller extra package settings.
LocationUtils.startLocationControllerExtraPackageSettings(activity, user)
return
@@ -332,31 +334,38 @@ class PermissionAppsViewModel(
}
fun getFilterTimeBeginMillis(): Long {
- val aggregateDataFilterBeginDays = if (is7DayToggleEnabled())
- AGGREGATE_DATA_FILTER_BEGIN_DAYS_7 else AGGREGATE_DATA_FILTER_BEGIN_DAYS_1
+ val aggregateDataFilterBeginDays =
+ if (is7DayToggleEnabled()) AGGREGATE_DATA_FILTER_BEGIN_DAYS_7
+ else AGGREGATE_DATA_FILTER_BEGIN_DAYS_1
- return max(System.currentTimeMillis() -
+ return max(
+ System.currentTimeMillis() -
TimeUnit.DAYS.toMillis(aggregateDataFilterBeginDays.toLong()),
- Instant.EPOCH.toEpochMilli())
+ Instant.EPOCH.toEpochMilli()
+ )
}
/**
* Return a mapping of user + packageName to their last access timestamps for the permission
* group.
*/
- fun extractGroupUsageLastAccessTime(appPermissionUsages: List<AppPermissionUsage>):
- MutableMap<String, Long> {
+ fun extractGroupUsageLastAccessTime(
+ appPermissionUsages: List<AppPermissionUsage>
+ ): MutableMap<String, Long> {
val accessTime: MutableMap<String, Long> = HashMap()
if (!SdkLevel.isAtLeastS()) {
return accessTime
}
- val aggregateDataFilterBeginDays = if (is7DayToggleEnabled())
- AGGREGATE_DATA_FILTER_BEGIN_DAYS_7 else AGGREGATE_DATA_FILTER_BEGIN_DAYS_1
+ val aggregateDataFilterBeginDays =
+ if (is7DayToggleEnabled()) AGGREGATE_DATA_FILTER_BEGIN_DAYS_7
+ else AGGREGATE_DATA_FILTER_BEGIN_DAYS_1
val now = System.currentTimeMillis()
- val filterTimeBeginMillis = max(
+ val filterTimeBeginMillis =
+ max(
now - TimeUnit.DAYS.toMillis(aggregateDataFilterBeginDays.toLong()),
- Instant.EPOCH.toEpochMilli())
+ Instant.EPOCH.toEpochMilli()
+ )
val numApps: Int = appPermissionUsages.size
for (appIndex in 0 until numApps) {
val appUsage: AppPermissionUsage = appPermissionUsages.get(appIndex)
@@ -380,41 +389,39 @@ class PermissionAppsViewModel(
return accessTime
}
- /**
- * Return the String preference summary based on the last access time.
- */
- fun getPreferenceSummary(res: Resources, summaryTimestamp: Triple<String, Int, String>):
- String {
+ /** Return the String preference summary based on the last access time. */
+ fun getPreferenceSummary(
+ res: Resources,
+ summaryTimestamp: Triple<String, Int, String>
+ ): String {
return when (summaryTimestamp.second) {
- Utils.LAST_24H_CONTENT_PROVIDER -> res.getString(
- R.string.app_perms_content_provider_24h)
- Utils.LAST_7D_CONTENT_PROVIDER -> res.getString(
- R.string.app_perms_content_provider_7d)
- Utils.LAST_24H_SENSOR_TODAY -> res.getString(R.string.app_perms_24h_access,
- summaryTimestamp.first)
- Utils.LAST_24H_SENSOR_YESTERDAY -> res.getString(R.string.app_perms_24h_access_yest,
- summaryTimestamp.first)
- Utils.LAST_7D_SENSOR -> res.getString(R.string.app_perms_7d_access,
- summaryTimestamp.third, summaryTimestamp.first)
+ Utils.LAST_24H_CONTENT_PROVIDER ->
+ res.getString(R.string.app_perms_content_provider_24h)
+ Utils.LAST_7D_CONTENT_PROVIDER -> res.getString(R.string.app_perms_content_provider_7d)
+ Utils.LAST_24H_SENSOR_TODAY ->
+ res.getString(R.string.app_perms_24h_access, summaryTimestamp.first)
+ Utils.LAST_24H_SENSOR_YESTERDAY ->
+ res.getString(R.string.app_perms_24h_access_yest, summaryTimestamp.first)
+ Utils.LAST_7D_SENSOR ->
+ res.getString(
+ R.string.app_perms_7d_access,
+ summaryTimestamp.third,
+ summaryTimestamp.first
+ )
else -> ""
}
}
- /**
- * Return two preferences to determine their ordering.
- */
+ /** Return two preferences to determine their ordering. */
fun comparePreference(collator: Collator, lhs: Preference, rhs: Preference): Int {
- var result: Int = collator.compare(lhs.title.toString(),
- rhs.title.toString())
+ var result: Int = collator.compare(lhs.title.toString(), rhs.title.toString())
if (result == 0) {
result = lhs.key.compareTo(rhs.key)
}
return result
}
- /**
- * Log that the fragment was created.
- */
+ /** Log that the fragment was created. */
fun logPermissionAppsFragmentCreated(
packageName: String,
user: UserHandle,
@@ -439,14 +446,30 @@ class PermissionAppsViewModel(
category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__DENIED
}
}
- val uid = getPackageUid(application,
- packageName, user) ?: return
+ val uid = getPackageUid(application, packageName, user) ?: return
PermissionControllerStatsLog.write(
- PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED, sessionId, viewId,
- permGroupName, uid, packageName, category)
- Log.v(tag, tag + " created with sessionId=" + sessionId +
- " permissionGroupName=" + permGroupName + " appUid=" + uid +
- " packageName=" + packageName + " category=" + category)
+ PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED,
+ sessionId,
+ viewId,
+ permGroupName,
+ uid,
+ packageName,
+ category
+ )
+ Log.i(
+ tag,
+ tag +
+ " created with sessionId=" +
+ sessionId +
+ " permissionGroupName=" +
+ permGroupName +
+ " appUid=" +
+ uid +
+ " packageName=" +
+ packageName +
+ " category=" +
+ category
+ )
}
}
@@ -473,7 +496,6 @@ class PermissionAppsViewModelFactory(
handle.set(HAS_SYSTEM_APPS_KEY, handle.get<Boolean>(HAS_SYSTEM_APPS_KEY) ?: true)
handle.set(SHOW_ALWAYS_ALLOWED, handle.get<Boolean>(SHOW_ALWAYS_ALLOWED) ?: false)
handle.set(CREATION_LOGGED_KEY, handle.get<Boolean>(CREATION_LOGGED_KEY) ?: false)
- @Suppress("UNCHECKED_CAST")
- return PermissionAppsViewModel(handle, app, groupName) as T
+ @Suppress("UNCHECKED_CAST") return PermissionAppsViewModel(handle, app, groupName) as T
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt
index 4e1fc1861..8613d1cae 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt
@@ -39,53 +39,51 @@ import com.android.settingslib.RestrictedLockUtils
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
import java.util.stream.Collectors
-/**
- * View model for legacy {@link ReviewPermissionsFragment}.
- */
-class ReviewPermissionsViewModel(
- val app: Application,
- val packageInfo: PackageInfo
-) : ViewModel() {
+/** View model for legacy {@link ReviewPermissionsFragment}. */
+class ReviewPermissionsViewModel(val app: Application, val packageInfo: PackageInfo) : ViewModel() {
private val mUser = android.os.Process.myUserHandle()
- /**
- * Holds permission groups for a package or an empty map in case no user review is required.
- */
+ /** Holds permission groups for a package or an empty map in case no user review is required. */
val permissionGroupsLiveData =
object : SmartUpdateMediatorLiveData<Map<String, LightAppPermGroup>>() {
val packagePermsLiveData = PackagePermissionsLiveData[packageInfo.packageName, mUser]
init {
- addSource(packagePermsLiveData) {
- update()
- }
+ addSource(packagePermsLiveData) { update() }
}
val permissionGroups = mutableMapOf<String, LightAppPermGroupLiveData>()
override fun onUpdate() {
val permissionGroupsMap = packagePermsLiveData.value ?: return
- val filteredGroups = permissionGroupsMap.keys.stream()
- .filter { it -> !it.equals(NON_RUNTIME_NORMAL_PERMS) }
- .collect(Collectors.toList())
+ val filteredGroups =
+ permissionGroupsMap.keys
+ .stream()
+ .filter { it -> !it.equals(NON_RUNTIME_NORMAL_PERMS) }
+ .collect(Collectors.toList())
val getPermGroupLiveData = { permGroupName: String ->
LightAppPermGroupLiveData[packageInfo.packageName, permGroupName, mUser]
}
setSourcesToDifference(filteredGroups, permissionGroups, getPermGroupLiveData)
- if (permissionGroups.values.all { it.isInitialized } &&
- permissionGroups.values.all { !it.isStale }) {
- val permGroups: List<LightAppPermGroup?> = permissionGroups.values.map {
- it.value }
- val reviewGroups = permGroups.filterNotNull().filter {
- shouldShowPermission(it) &&
- Utils.OS_PKG == it.permGroupInfo.packageName
- }.associateBy {
- it.permGroupName
- }
- value = if (reviewGroups.any { it.value.isReviewRequired }) reviewGroups
- else emptyMap()
+ if (
+ permissionGroups.values.all { it.isInitialized } &&
+ permissionGroups.values.all { !it.isStale }
+ ) {
+ val permGroups: List<LightAppPermGroup?> =
+ permissionGroups.values.map { it.value }
+ val reviewGroups =
+ permGroups
+ .filterNotNull()
+ .filter {
+ shouldShowPermission(it) &&
+ Utils.OS_PKG == it.permGroupInfo.packageName
+ }
+ .associateBy { it.permGroupName }
+ value =
+ if (reviewGroups.any { it.value.isReviewRequired }) reviewGroups
+ else emptyMap()
}
}
}
@@ -110,15 +108,15 @@ class ReviewPermissionsViewModel(
}
/**
- * Update the summary of a permission group that has background permission.
- * This does not apply to permission groups that are fixed by policy
+ * Update the summary of a permission group that has background permission. This does not apply
+ * to permission groups that are fixed by policy
*/
- fun getSummaryForPermGroupWithBackgroundPermission(
- state: PermissionTarget
- ): PermissionSummary {
+ fun getSummaryForPermGroupWithBackgroundPermission(state: PermissionTarget): PermissionSummary {
if (state != PermissionTarget.PERMISSION_NONE) {
- if (state.and(PermissionTarget.PERMISSION_BACKGROUND)
- != PermissionTarget.PERMISSION_NONE.value) {
+ if (
+ state.and(PermissionTarget.PERMISSION_BACKGROUND) !=
+ PermissionTarget.PERMISSION_NONE.value
+ ) {
return SummaryMessage.ACCESS_ALWAYS.toPermSummary()
} else {
return SummaryMessage.ACCESS_ONLY_FOREGROUND.toPermSummary()
@@ -152,9 +150,7 @@ class ReviewPermissionsViewModel(
}
}
- /**
- * Show all individual permissions in this group in a new fragment.
- */
+ /** Show all individual permissions in this group in a new fragment. */
fun showAllPermissions(fragment: Fragment, args: Bundle) {
val navController: NavController = NavHostFragment.findNavController(fragment)
navController.navigateSafe(R.id.app_to_all_perms, args)
@@ -222,8 +218,10 @@ class ReviewPermissionsViewModel(
SummaryMessage.ENFORCED_BY_POLICY.toPermSummary()
}
} else {
- if (mState.and(PermissionTarget.PERMISSION_BACKGROUND) !=
- PermissionTarget.PERMISSION_NONE.value) {
+ if (
+ mState.and(PermissionTarget.PERMISSION_BACKGROUND) !=
+ PermissionTarget.PERMISSION_NONE.value
+ ) {
return if (hasAdmin) {
SummaryMessage.ENABLED_BY_ADMIN.toPermSummary()
} else {
@@ -242,8 +240,10 @@ class ReviewPermissionsViewModel(
} else {
// Part of the permission group can still be switched
if (permGroup.background.isPolicyFixed) {
- return if (mState.and(PermissionTarget.PERMISSION_BACKGROUND) !=
- PermissionTarget.PERMISSION_NONE.value) {
+ return if (
+ mState.and(PermissionTarget.PERMISSION_BACKGROUND) !=
+ PermissionTarget.PERMISSION_NONE.value
+ ) {
if (hasAdmin) {
SummaryMessage.ENABLED_BY_ADMIN_BACKGROUND_ONLY.toPermSummary(true)
} else {
@@ -277,11 +277,10 @@ class ReviewPermissionsViewModel(
return mGroup.foreground.isPolicyFixed && !mGroup.isGranted
}
- /**
- * Whether policy is system fixed or fully fixed or foreground disabled
- */
+ /** Whether policy is system fixed or fully fixed or foreground disabled */
fun isFixedOrForegroundDisabled(mGroup: LightAppPermGroup): Boolean {
- return mGroup.isSystemFixed || mGroup.isPolicyFullyFixed ||
+ return mGroup.isSystemFixed ||
+ mGroup.isPolicyFullyFixed ||
isForegroundDisabledByPolicy(mGroup)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/UnusedAppsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/UnusedAppsViewModel.kt
index 3c3f347a4..868f9229f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/UnusedAppsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/UnusedAppsViewModel.kt
@@ -96,85 +96,89 @@ class UnusedAppsViewModel(private val app: Application, private val sessionId: L
private data class PackageLastUsageTime(val packageName: String, val usageTime: Long)
val unusedPackageCategoriesLiveData =
- object : SmartAsyncMediatorLiveData<Map<UnusedPeriod, List<UnusedPackageInfo>>>(
- alwaysUpdateOnActive = false
- ) {
- // Get apps usage stats from the longest interesting period (MAX_UNUSED_PERIOD_MILLIS)
- private val usageStatsLiveData = UsageStatsLiveData[MAX_UNUSED_PERIOD_MILLIS]
-
- init {
- addSource(getUnusedPackages()) {
- onUpdate()
- }
-
- addSource(AllPackageInfosLiveData) {
- onUpdate()
- }
+ object :
+ SmartAsyncMediatorLiveData<Map<UnusedPeriod, List<UnusedPackageInfo>>>(
+ alwaysUpdateOnActive = false
+ ) {
+ // Get apps usage stats from the longest interesting period (MAX_UNUSED_PERIOD_MILLIS)
+ private val usageStatsLiveData = UsageStatsLiveData[MAX_UNUSED_PERIOD_MILLIS]
- addSource(usageStatsLiveData) {
- onUpdate()
- }
- }
+ init {
+ addSource(getUnusedPackages()) { onUpdate() }
- override suspend fun loadDataAndPostValue(job: Job) {
- if (!getUnusedPackages().isInitialized ||
- !usageStatsLiveData.isInitialized || !AllPackageInfosLiveData.isInitialized
- ) {
- return
- }
+ addSource(AllPackageInfosLiveData) { onUpdate() }
- val unusedApps = getUnusedPackages().value!!
- Log.i(LOG_TAG, "Unused apps: $unusedApps")
- val categorizedApps = mutableMapOf<UnusedPeriod, MutableList<UnusedPackageInfo>>()
- for (period in UnusedPeriod.allPeriods) {
- categorizedApps[period] = mutableListOf()
+ addSource(usageStatsLiveData) { onUpdate() }
}
- // Get all packages which cannot be uninstalled.
- val systemApps = getUnusedSystemApps(AllPackageInfosLiveData.value!!, unusedApps)
- val lastUsedDataUnusedApps =
- extractUnusedAppsUsageData(usageStatsLiveData.value!!, unusedApps)
- { it: UsageStats ->
- PackageLastUsageTime(it.packageName, it.lastTimePackageUsed())
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (
+ !getUnusedPackages().isInitialized ||
+ !usageStatsLiveData.isInitialized ||
+ !AllPackageInfosLiveData.isInitialized
+ ) {
+ return
}
- val firstInstallDataUnusedApps =
- extractUnusedAppsUsageData(AllPackageInfosLiveData.value!!, unusedApps)
- { it: LightPackageInfo ->
- PackageLastUsageTime(it.packageName, it.firstInstallTime)
+
+ val unusedApps = getUnusedPackages().value!!
+ Log.i(LOG_TAG, "Unused apps: $unusedApps")
+ val categorizedApps = mutableMapOf<UnusedPeriod, MutableList<UnusedPackageInfo>>()
+ for (period in UnusedPeriod.allPeriods) {
+ categorizedApps[period] = mutableListOf()
}
- val now = System.currentTimeMillis()
- unusedApps.keys.forEach { (packageName, user) ->
- val userPackage = packageName to user
-
- // If we didn't find the stat for a package in our usageStats search, it is more than
- // 6 months old, or the app has never been opened. Then use first install date instead.
- var lastUsageTime =
- lastUsedDataUnusedApps[userPackage] ?: firstInstallDataUnusedApps[
- userPackage] ?: 0L
-
- val period = UnusedPeriod.findLongestValidPeriod(now - lastUsageTime)
- categorizedApps[period]!!.add(
- UnusedPackageInfo(
- packageName, user, systemApps.contains(userPackage),
- unusedApps[userPackage]!!
+ // Get all packages which cannot be uninstalled.
+ val systemApps = getUnusedSystemApps(AllPackageInfosLiveData.value!!, unusedApps)
+ val lastUsedDataUnusedApps =
+ extractUnusedAppsUsageData(usageStatsLiveData.value!!, unusedApps) {
+ it: UsageStats ->
+ PackageLastUsageTime(it.packageName, it.lastTimePackageUsed())
+ }
+ val firstInstallDataUnusedApps =
+ extractUnusedAppsUsageData(AllPackageInfosLiveData.value!!, unusedApps) {
+ it: LightPackageInfo ->
+ PackageLastUsageTime(it.packageName, it.firstInstallTime)
+ }
+
+ val now = System.currentTimeMillis()
+ unusedApps.keys.forEach { (packageName, user) ->
+ val userPackage = packageName to user
+
+ // If we didn't find the stat for a package in our usageStats search, it is more
+ // than
+ // 6 months old, or the app has never been opened. Then use first install date
+ // instead.
+ var lastUsageTime =
+ lastUsedDataUnusedApps[userPackage]
+ ?: firstInstallDataUnusedApps[userPackage] ?: 0L
+
+ val period = UnusedPeriod.findLongestValidPeriod(now - lastUsageTime)
+ categorizedApps[period]!!.add(
+ UnusedPackageInfo(
+ packageName,
+ user,
+ systemApps.contains(userPackage),
+ unusedApps[userPackage]!!
+ )
)
- )
- }
+ }
- postValue(categorizedApps)
+ postValue(categorizedApps)
+ }
}
- }
// Extract UserPackage information for unused system apps from source map.
private fun getUnusedSystemApps(
userPackages: Map<UserHandle, List<LightPackageInfo>>,
- unusedApps: Map<UserPackage, Set<String>>,
+ unusedApps: Map<UserPackage, Set<String>>,
): List<UserPackage> {
- return userPackages.flatMap { (userHandle, packageList) ->
- packageList.filter { (it.appFlags and ApplicationInfo.FLAG_SYSTEM) != 0 }
- .map { it.packageName to userHandle }
- }.filter { unusedApps.contains(it) }
+ return userPackages
+ .flatMap { (userHandle, packageList) ->
+ packageList
+ .filter { (it.appFlags and ApplicationInfo.FLAG_SYSTEM) != 0 }
+ .map { it.packageName to userHandle }
+ }
+ .filter { unusedApps.contains(it) }
}
/**
@@ -187,9 +191,11 @@ class UnusedAppsViewModel(private val app: Application, private val sessionId: L
unusedApps: Map<UserPackage, Set<String>>,
extractUsageData: (fullData: PackageData) -> PackageLastUsageTime,
): Map<UserPackage, Long> {
- return userPackages.flatMap { (userHandle, fullData) ->
- fullData.map { userHandle to extractUsageData(it) }
- }.associate { (handle, appData) -> (appData.packageName to handle) to appData.usageTime }
+ return userPackages
+ .flatMap { (userHandle, fullData) ->
+ fullData.map { userHandle to extractUsageData(it) }
+ }
+ .associate { (handle, appData) -> (appData.packageName to handle) to appData.usageTime }
.filterKeys { unusedApps.contains(it) }
}
@@ -215,37 +221,57 @@ class UnusedAppsViewModel(private val app: Application, private val sessionId: L
Log.i(LOG_TAG, "sessionId: $sessionId, Disabling $packageName, $user")
logAppInteraction(packageName, user, AUTO_REVOKED_APP_INTERACTION__ACTION__REMOVE)
val userContext = Utils.getUserContext(app, user)
- userContext.packageManager.setApplicationEnabledSetting(packageName,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0)
+ userContext.packageManager.setApplicationEnabledSetting(
+ packageName,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER,
+ 0
+ )
}
private fun logAppInteraction(packageName: String, user: UserHandle, action: Int) {
GlobalScope.launch(IPC) {
// If we are logging an app interaction, then the AllPackageInfosLiveData is not stale.
- val uid = AllPackageInfosLiveData.value?.get(user)
- ?.find { info -> info.packageName == packageName }?.uid
+ val uid =
+ AllPackageInfosLiveData.value
+ ?.get(user)
+ ?.find { info -> info.packageName == packageName }
+ ?.uid
if (uid != null) {
- PermissionControllerStatsLog.write(AUTO_REVOKED_APP_INTERACTION, sessionId,
- uid, packageName, action)
+ PermissionControllerStatsLog.write(
+ AUTO_REVOKED_APP_INTERACTION,
+ sessionId,
+ uid,
+ packageName,
+ action
+ )
}
}
}
fun logAppView(packageName: String, user: UserHandle, groupName: String, isNew: Boolean) {
GlobalScope.launch(IPC) {
- val uid = AllPackageInfosLiveData.value!![user]!!.find { info ->
- info.packageName == packageName
- }?.uid
+ val uid =
+ AllPackageInfosLiveData.value!![user]!!.find { info ->
+ info.packageName == packageName
+ }
+ ?.uid
if (uid != null) {
- val bucket = if (isNew) {
- AUTO_REVOKE_FRAGMENT_APP_VIEWED__AGE__NEWER_BUCKET
- } else {
- AUTO_REVOKE_FRAGMENT_APP_VIEWED__AGE__OLDER_BUCKET
- }
- PermissionControllerStatsLog.write(AUTO_REVOKE_FRAGMENT_APP_VIEWED, sessionId,
- uid, packageName, groupName, bucket)
+ val bucket =
+ if (isNew) {
+ AUTO_REVOKE_FRAGMENT_APP_VIEWED__AGE__NEWER_BUCKET
+ } else {
+ AUTO_REVOKE_FRAGMENT_APP_VIEWED__AGE__OLDER_BUCKET
+ }
+ PermissionControllerStatsLog.write(
+ AUTO_REVOKE_FRAGMENT_APP_VIEWED,
+ sessionId,
+ uid,
+ packageName,
+ groupName,
+ bucket
+ )
}
}
}
@@ -259,7 +285,6 @@ class UnusedAppsViewModelFactory(
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
- @Suppress("UNCHECKED_CAST")
- return UnusedAppsViewModel(app, sessionId) as T
+ @Suppress("UNCHECKED_CAST") return UnusedAppsViewModel(app, sessionId) as T
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BackgroundGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BackgroundGrantBehavior.kt
new file mode 100644
index 000000000..6234b2755
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BackgroundGrantBehavior.kt
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.model.grantPermissions
+
+import android.os.Build
+import android.permission.PermissionManager
+import android.util.Log
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
+import com.android.permissioncontroller.permission.ui.model.DenyButton
+import com.android.permissioncontroller.permission.ui.model.Prompt
+import com.android.permissioncontroller.permission.utils.PermissionMapping
+
+/**
+ * This behavior handles groups that respect the difference between foreground and background
+ * access. At present, this includes all one-time permissions, in addition to those with explicit
+ * background permissions.
+ *
+ * The behavior is split based on the target SDK when the app split into foreground and background
+ * (or android R, whichever is newer). If the app targets prior to the split, we show a dialog with
+ * a link to permission settings. Once the app targets after the split, we no longer allow the app
+ * to request background and foreground at the same time. If they try, we reject it. An app has to
+ * request foreground, get it granted, then request background only, we send the user to settings.
+ */
+object BackgroundGrantBehavior : GrantBehavior() {
+
+ private val splitPermissionSdkMap = buildMap {
+ for (splitPerm in
+ PermissionControllerApplication.get()
+ .getSystemService(PermissionManager::class.java)!!
+ .splitPermissions) {
+ put(splitPerm.splitPermission, splitPerm.targetSdk)
+ }
+ }
+
+ // Redundant "if" conditions are suppressed, because the conditions are clearer
+ @Suppress("KotlinConstantConditions")
+ override fun getPrompt(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ isSystemTriggeredPrompt: Boolean
+ ): Prompt {
+ val requestsBg = hasBgPerms(group, requestedPerms)
+ val requestsFg = requestedPerms.any { it !in group.backgroundPermNames }
+ val isOneTimeGroup = PermissionMapping.supportsOneTimeGrant(group.permGroupName)
+ val isFgGranted = group.foreground.isGrantedExcludingRWROrAllRWR
+ val isFgOneTime = group.foreground.isOneTime
+ val splitSdk = getSdkGroupWasSplitToBg(requestedPerms)
+ val isAppIsOlderThanSplitToBg = group.packageInfo.targetSdkVersion < splitSdk
+
+ if (!requestsBg && !isOneTimeGroup) {
+ return Prompt.FG_ONLY
+ } else if (!requestsBg) {
+ return Prompt.ONE_TIME_FG
+ }
+
+ if (requestsBg && !requestsFg && !isFgGranted) {
+ Log.w(
+ LOG_TAG,
+ "Cannot grant ${group.permGroupName} as the foreground permissions" +
+ " are not requested or already granted."
+ )
+ return Prompt.NO_UI_REJECT_THIS_GROUP
+ }
+
+ return if (isAppIsOlderThanSplitToBg) {
+ getPromptForOlderApp(isOneTimeGroup, requestsFg, isFgGranted, isFgOneTime)
+ } else {
+ getPromptForNewerApp(group.permGroupName, splitSdk, requestsFg, isFgGranted)
+ }
+ }
+
+ /**
+ * Get the prompt for an app that targets before the sdk level where the permission group was
+ * split into foreground and background.
+ */
+ private fun getPromptForOlderApp(
+ isOneTimeGroup: Boolean,
+ requestsFg: Boolean,
+ isFgGranted: Boolean,
+ isFgOneTime: Boolean
+ ): Prompt {
+ if (requestsFg && !isFgGranted) {
+ if (isOneTimeGroup) {
+ return Prompt.SETTINGS_LINK_WITH_OT
+ }
+ return Prompt.SETTINGS_LINK_FOR_BG
+ }
+
+ if (isFgGranted) {
+ if (isFgOneTime) {
+ return Prompt.OT_UPGRADE_SETTINGS_LINK
+ }
+ return Prompt.UPGRADE_SETTINGS_LINK
+ }
+ return Prompt.NO_UI_REJECT_ALL_GROUPS
+ }
+
+ /**
+ * Get the prompt for an app that targets at least the sdk level where the permission group was
+ * split into foreground and background.
+ */
+ private fun getPromptForNewerApp(
+ groupName: String,
+ splitSdk: Int,
+ requestsFg: Boolean,
+ isFgGranted: Boolean
+ ): Prompt {
+ if (!requestsFg && isFgGranted) {
+ return Prompt.NO_UI_SETTINGS_REDIRECT
+ }
+
+ if (requestsFg) {
+ Log.e(
+ LOG_TAG,
+ "For SDK $splitSdk+ apps requesting $groupName, " +
+ "background permissions must be requested alone after foreground permissions " +
+ "are already granted"
+ )
+ return Prompt.NO_UI_REJECT_ALL_GROUPS
+ } else if (!isFgGranted) {
+ Log.e(
+ LOG_TAG,
+ "For SDK $splitSdk+ apps requesting, $groupName, " +
+ "background permissions must be requested after foreground permissions are " +
+ "already granted"
+ )
+ Prompt.NO_UI_REJECT_THIS_GROUP
+ }
+ return Prompt.NO_UI_REJECT_ALL_GROUPS
+ }
+
+ override fun getDenyButton(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ prompt: Prompt
+ ): DenyButton {
+ val basicDenyBehavior = BasicGrantBehavior.getDenyButton(group, requestedPerms, prompt)
+ if (prompt == Prompt.UPGRADE_SETTINGS_LINK || prompt == Prompt.OT_UPGRADE_SETTINGS_LINK) {
+ if (basicDenyBehavior == DenyButton.DENY) {
+ return if (prompt == Prompt.UPGRADE_SETTINGS_LINK) {
+ DenyButton.NO_UPGRADE
+ } else {
+ DenyButton.NO_UPGRADE_OT
+ }
+ }
+ return if (prompt == Prompt.UPGRADE_SETTINGS_LINK) {
+ DenyButton.NO_UPGRADE_AND_DONT_ASK_AGAIN
+ } else {
+ DenyButton.NO_UPGRADE_AND_DONT_ASK_AGAIN_OT
+ }
+ }
+ return basicDenyBehavior
+ }
+
+ override fun isGroupFullyGranted(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>
+ ): Boolean {
+ return (!hasBgPerms(group, requestedPerms) ||
+ group.background.isGrantedExcludingRWROrAllRWR) &&
+ group.foreground.isGrantedExcludingRWROrAllRWR
+ }
+
+ override fun isForegroundFullyGranted(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>
+ ): Boolean {
+ return group.foreground.isGrantedExcludingRWROrAllRWR
+ }
+
+ override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean {
+ if (perm in group.backgroundPermNames) {
+ return group.background.isUserFixed
+ }
+ return group.foreground.isUserFixed
+ }
+
+ private fun hasBgPerms(group: LightAppPermGroup, requestedPerms: Set<String>): Boolean {
+ return requestedPerms.any { it in group.backgroundPermNames }
+ }
+
+ private fun getSdkGroupWasSplitToBg(requestedPerms: Set<String>): Int {
+ val splitSdks = requestedPerms.mapNotNull { perm -> splitPermissionSdkMap[perm] }
+
+ if (splitSdks.isEmpty()) {
+ // If there was no split found, assume the split happened in R. This applies to
+ // Mic and Camera, which technically split in S, but were treated as foreground-only
+ // in R
+ return Build.VERSION_CODES.R
+ }
+ // The background permission request UI changed in R, so if a split happened before R,
+ // treat it as if it happened in R
+ return maxOf(splitSdks.min(), Build.VERSION_CODES.R)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BasicGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BasicGrantBehavior.kt
new file mode 100644
index 000000000..d73e459be
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BasicGrantBehavior.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.model.grantPermissions
+
+import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
+import com.android.permissioncontroller.permission.ui.model.DenyButton
+import com.android.permissioncontroller.permission.ui.model.Prompt
+
+/** A basic group. Shows "allow" and "deny", does not allow fixed permissions to be re-requested */
+object BasicGrantBehavior : GrantBehavior() {
+
+ override fun getPrompt(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ isSystemTriggeredPrompt: Boolean
+ ): Prompt {
+ return Prompt.BASIC
+ }
+
+ override fun getDenyButton(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ prompt: Prompt
+ ): DenyButton {
+ if (prompt in noDenyButtonPrompts) {
+ return DenyButton.NONE
+ }
+ if (group.isUserSet) {
+ return DenyButton.DENY_DONT_ASK_AGAIN
+ }
+ return DenyButton.DENY
+ }
+
+ // A list of prompts without any deny behavior
+ private val noDenyButtonPrompts =
+ listOf(
+ Prompt.NO_UI_SETTINGS_REDIRECT,
+ Prompt.NO_UI_PHOTO_PICKER_REDIRECT,
+ Prompt.NO_UI_HEALTH_REDIRECT,
+ Prompt.NO_UI_REJECT_THIS_GROUP,
+ Prompt.NO_UI_REJECT_ALL_GROUPS,
+ Prompt.NO_UI_FILTER_THIS_GROUP
+ )
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/GrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/GrantBehavior.kt
new file mode 100644
index 000000000..3b3619084
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/GrantBehavior.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.model.grantPermissions
+
+import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
+import com.android.permissioncontroller.permission.ui.model.DenyButton
+import com.android.permissioncontroller.permission.ui.model.Prompt
+
+/** The base behavior all grant behavior objects inherit from. */
+abstract class GrantBehavior {
+ val LOG_TAG = "GrantPermissionsViewModel"
+
+ /**
+ * Get the prompt type for the given set of requested permissions
+ *
+ * @param group The LightAppPermGroup representing the state of the app and its permissions
+ * @param requestedPerms The permissions requested by the app, after filtering
+ * @param isSystemTriggeredPrompt Whether the prompt was triggered by the system, instead of by
+ * the app.
+ */
+ abstract fun getPrompt(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ isSystemTriggeredPrompt: Boolean = false
+ ): Prompt
+
+ /**
+ * Get the deny button type for the given set of requested permissions. This is separate from
+ * the prompt, because the same prompt can have multiple deny behaviors, based on if the user
+ * has seen it before.
+ *
+ * @param group The LightAppPermGroup representing the state of the app and its permissions
+ * @param requestedPerms The permissions requested by the app, after filtering
+ * @param prompt The prompt determined by the behavior.
+ */
+ abstract fun getDenyButton(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ prompt: Prompt
+ ): DenyButton
+
+ /**
+ * Whether the group is considered "fully granted". If it is, any remaining permissions in the
+ * group not already granted will be granted.
+ */
+ open fun isGroupFullyGranted(group: LightAppPermGroup, requestedPerms: Set<String>): Boolean {
+ return group.foreground.isGrantedExcludingRWROrAllRWR
+ }
+
+ /**
+ * Whether or not all foreground permissions in the group are granted. Only different in groups
+ * that respect background and foreground permissions.
+ */
+ open fun isForegroundFullyGranted(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>
+ ): Boolean {
+ return isGroupFullyGranted(group, requestedPerms)
+ }
+
+ /**
+ * Whether or not the permission should be considered as "user fixed". If it is, it is removed
+ * from the request.
+ */
+ open fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean {
+ return group.isUserFixed
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/HealthGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/HealthGrantBehavior.kt
new file mode 100644
index 000000000..8e540701a
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/HealthGrantBehavior.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.model.grantPermissions
+
+import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
+import com.android.permissioncontroller.permission.ui.model.DenyButton
+import com.android.permissioncontroller.permission.ui.model.Prompt
+import com.android.permissioncontroller.permission.utils.Utils
+
+/** Health permissions always redirect to the health connect UI. */
+object HealthGrantBehavior : GrantBehavior() {
+ override fun getPrompt(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ isSystemTriggeredPrompt: Boolean
+ ): Prompt {
+ return if (Utils.isHealthPermissionUiEnabled()) {
+ Prompt.NO_UI_HEALTH_REDIRECT
+ } else {
+ Prompt.NO_UI_REJECT_THIS_GROUP
+ }
+ }
+
+ override fun getDenyButton(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ prompt: Prompt
+ ): DenyButton {
+ return DenyButton.NONE
+ }
+
+ override fun isGroupFullyGranted(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>
+ ): Boolean {
+ return requestedPerms.all { group.permissions[it]?.isGrantedIncludingAppOp != false }
+ }
+
+ override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean {
+ return group.permissions[perm]?.isUserFixed == true
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/LocationGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/LocationGrantBehavior.kt
new file mode 100644
index 000000000..2c5e2b732
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/LocationGrantBehavior.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.model.grantPermissions
+
+import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.os.Build
+import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
+import com.android.permissioncontroller.permission.ui.model.DenyButton
+import com.android.permissioncontroller.permission.ui.model.Prompt
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+
+/**
+ * The Location Grant behavior is the same as the Background group behavior, up until S. After S,
+ * the fine and coarse location permissions were allowed to be granted separately, and this created
+ * a new set of grant dialogs.
+ */
+object LocationGrantBehavior : GrantBehavior() {
+ override fun getPrompt(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ isSystemTriggeredPrompt: Boolean
+ ): Prompt {
+ val backgroundPrompt = BackgroundGrantBehavior.getPrompt(group, requestedPerms)
+ val requestsBackground = requestedPerms.any { it in group.backgroundPermNames }
+ val coarseGranted =
+ group.permissions[ACCESS_COARSE_LOCATION]?.isGrantedIncludingAppOp == true
+ return if (!supportsLocationAccuracy(group) || requestsBackground) {
+ backgroundPrompt
+ } else if (requestedPerms.contains(ACCESS_FINE_LOCATION)) {
+ if (coarseGranted) {
+ Prompt.LOCATION_FINE_UPGRADE
+ } else if (isFineLocationHighlighted(group)) {
+ Prompt.LOCATION_TWO_BUTTON_FINE_HIGHLIGHT
+ } else {
+ Prompt.LOCATION_TWO_BUTTON_COARSE_HIGHLIGHT
+ }
+ } else if (requestedPerms.contains(ACCESS_COARSE_LOCATION) && !coarseGranted) {
+ Prompt.LOCATION_COARSE_ONLY
+ } else {
+ backgroundPrompt
+ }
+ }
+
+ override fun getDenyButton(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ prompt: Prompt
+ ): DenyButton {
+ return BackgroundGrantBehavior.getDenyButton(group, requestedPerms, prompt)
+ }
+
+ override fun isGroupFullyGranted(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>
+ ): Boolean {
+ val requestsBackground = requestedPerms.any { it in group.backgroundPermNames }
+ if (!supportsLocationAccuracy(group) || requestsBackground) {
+ return BackgroundGrantBehavior.isGroupFullyGranted(group, requestedPerms)
+ }
+ return isForegroundFullyGranted(group, requestedPerms)
+ }
+
+ override fun isForegroundFullyGranted(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>
+ ): Boolean {
+ if (!supportsLocationAccuracy(group)) {
+ return BackgroundGrantBehavior.isForegroundFullyGranted(group, requestedPerms)
+ }
+
+ if (requestedPerms.contains(ACCESS_FINE_LOCATION)) {
+ return group.permissions[ACCESS_FINE_LOCATION]?.isGrantedIncludingAppOp == true
+ }
+
+ return group.foreground.isGrantedExcludingRWROrAllRWR
+ }
+
+ override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean {
+ if (!supportsLocationAccuracy(group) || perm != ACCESS_COARSE_LOCATION) {
+ return BackgroundGrantBehavior.isPermissionFixed(group, perm)
+ }
+
+ // If the location group is user fixed but ACCESS_COARSE_LOCATION is not, then
+ // ACCESS_FINE_LOCATION must be user fixed. In this case ACCESS_COARSE_LOCATION
+ // is still grantable.
+ return group.foreground.isUserFixed && group.permissions[perm]?.isUserFixed == true
+ }
+
+ private fun supportsLocationAccuracy(group: LightAppPermGroup): Boolean {
+ return KotlinUtils.isLocationAccuracyEnabled() &&
+ group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.S
+ }
+
+ private fun isFineLocationHighlighted(group: LightAppPermGroup): Boolean {
+ // Steps to decide location accuracy default state
+ // 1. If none of the FINE and COARSE isSelectedLocationAccuracy
+ // flags is set, then use default precision from device config.
+ // 2. Otherwise set to whichever isSelectedLocationAccuracy is true.
+ val coarseLocationPerm = group.allPermissions[ACCESS_COARSE_LOCATION]
+ val fineLocationPerm = group.allPermissions[ACCESS_FINE_LOCATION]
+ return if (
+ coarseLocationPerm?.isSelectedLocationAccuracy == false &&
+ fineLocationPerm?.isSelectedLocationAccuracy == false
+ ) {
+ // default location precision is true, indicates FINE
+ return true
+ } else {
+ fineLocationPerm?.isSelectedLocationAccuracy == true
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/NotificationGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/NotificationGrantBehavior.kt
new file mode 100644
index 000000000..3867e8646
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/NotificationGrantBehavior.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.model.grantPermissions
+
+import android.os.Build.VERSION_CODES.TIRAMISU
+import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
+import com.android.permissioncontroller.permission.ui.model.DenyButton
+import com.android.permissioncontroller.permission.ui.model.Prompt
+
+/**
+ * The Notification permission behavior is similar to basic, except:
+ *
+ * It can be triggered by the system. If it's system triggered we only show it until the user makes
+ * one decision. We don't make the user show it twice.
+ *
+ * It can't be explicitly requested from apps that don't yet target android T. If they try, we
+ * remove it entirely from the request, do not return a result, and take no action on it.
+ */
+object NotificationGrantBehavior : GrantBehavior() {
+ override fun getPrompt(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ isSystemTriggeredPrompt: Boolean
+ ): Prompt {
+ val isPreT = group.packageInfo.targetSdkVersion < TIRAMISU
+ if (!isSystemTriggeredPrompt && isPreT) {
+ // Apps targeting below T cannot manually request Notifications
+ return Prompt.NO_UI_FILTER_THIS_GROUP
+ } else if (isPreT && group.isUserSet) {
+ // If the user has seen the system-triggered prompt once, don't show it again
+ return Prompt.NO_UI_FILTER_THIS_GROUP
+ }
+ return BasicGrantBehavior.getPrompt(group, requestedPerms, isSystemTriggeredPrompt)
+ }
+
+ override fun getDenyButton(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ prompt: Prompt
+ ): DenyButton {
+ return BasicGrantBehavior.getDenyButton(group, requestedPerms, prompt)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/StorageGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/StorageGrantBehavior.kt
new file mode 100644
index 000000000..a690f5f59
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/StorageGrantBehavior.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.model.grantPermissions
+
+import android.Manifest.permission.ACCESS_MEDIA_LOCATION
+import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+import android.Manifest.permission_group.READ_MEDIA_VISUAL
+import android.Manifest.permission_group.STORAGE
+import android.os.Build
+import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
+import com.android.permissioncontroller.permission.ui.model.DenyButton
+import com.android.permissioncontroller.permission.ui.model.Prompt
+import com.android.permissioncontroller.permission.utils.KotlinUtils.isPhotoPickerPromptEnabled
+import com.android.permissioncontroller.permission.utils.KotlinUtils.isPhotoPickerPromptSupported
+
+/**
+ * Storage split from one group (STORAGE) into two (READ_MEDIA_VISUAL and READ_MEDIA_AURAL) in T.
+ * There are special dialogs to deal with a pre-T app requesting STORAGE on a post-T device. In U,
+ * the READ_MEDIA_VISUAL group was augmented with the option to select photos, which led to several
+ * new dialogs to handle that.
+ */
+object StorageGrantBehavior : GrantBehavior() {
+ override fun getPrompt(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ isSystemTriggeredPrompt: Boolean
+ ): Prompt {
+ val appSupportsSplitStoragePermissions = appSupportsSplitStoragePermissions(group)
+ if (!SdkLevel.isAtLeastT()) {
+ return Prompt.BASIC
+ } else if (appSupportsSplitStoragePermissions && group.permGroupName == STORAGE) {
+ return Prompt.NO_UI_REJECT_THIS_GROUP
+ }
+
+ if (appSupportsSplitStoragePermissions && !shouldShowPhotoPickerPromptForApp(group)) {
+ return Prompt.BASIC
+ }
+
+ if (!appSupportsSplitStoragePermissions) {
+ if (group.packageInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+ return Prompt.STORAGE_SUPERGROUP_PRE_Q
+ } else {
+ return Prompt.STORAGE_SUPERGROUP_Q_TO_S
+ }
+ }
+
+ // Else, app supports the new photo picker dialog
+ if (requestedPerms.all { it in getPartialGrantPermissions(group) }) {
+ // Do not allow apps to request only READ_MEDIA_VISUAL_USER_SELECTED
+ return Prompt.NO_UI_REJECT_THIS_GROUP
+ }
+
+ val userSelectedPerm = group.permissions[READ_MEDIA_VISUAL_USER_SELECTED]
+ if (userSelectedPerm?.isUserFixed == true && userSelectedPerm.isGrantedIncludingAppOp) {
+ return Prompt.NO_UI_PHOTO_PICKER_REDIRECT
+ }
+
+ if (userSelectedPerm?.isGrantedIncludingAppOp == true) {
+ return Prompt.SELECT_MORE_PHOTOS
+ } else {
+ return Prompt.SELECT_PHOTOS
+ }
+ }
+
+ override fun getDenyButton(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>,
+ prompt: Prompt
+ ): DenyButton {
+ if (prompt == Prompt.SELECT_MORE_PHOTOS) {
+ return DenyButton.DONT_SELECT_MORE
+ }
+ return BasicGrantBehavior.getDenyButton(group, requestedPerms, prompt)
+ }
+
+ override fun isGroupFullyGranted(
+ group: LightAppPermGroup,
+ requestedPerms: Set<String>
+ ): Boolean {
+ if (!isPhotoPickerPromptSupported() || group.permGroupName != READ_MEDIA_VISUAL) {
+ return super.isGroupFullyGranted(group, requestedPerms)
+ }
+
+ return group.permissions.values.any {
+ it.name !in getPartialGrantPermissions(group) && it.isGrantedIncludingAppOp
+ }
+ }
+
+ override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean {
+ val userSelectedPerm = group.permissions[READ_MEDIA_VISUAL_USER_SELECTED]
+ if (
+ userSelectedPerm != null &&
+ userSelectedPerm.isGrantedIncludingAppOp &&
+ userSelectedPerm.isUserFixed
+ ) {
+ // If the user selected permission is fixed and granted, we immediately show the
+ // photo picker, rather than filtering
+ return false
+ }
+ return super.isPermissionFixed(group, perm)
+ }
+
+ private fun appSupportsSplitStoragePermissions(group: LightAppPermGroup) =
+ SdkLevel.isAtLeastT() && group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU
+
+ private fun shouldShowPhotoPickerPromptForApp(group: LightAppPermGroup) =
+ isPhotoPickerPromptEnabled() &&
+ group.permGroupName == READ_MEDIA_VISUAL &&
+ (group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE ||
+ appSupportsPhotoPicker(group))
+
+ private fun appSupportsPhotoPicker(group: LightAppPermGroup) =
+ group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU &&
+ group.permissions[READ_MEDIA_VISUAL_USER_SELECTED]?.isImplicit == false
+
+ private fun getPartialGrantPermissions(group: LightAppPermGroup): Set<String> {
+ return if (appSupportsPhotoPicker(group) && shouldShowPhotoPickerPromptForApp(group)) {
+ setOf(READ_MEDIA_VISUAL_USER_SELECTED, ACCESS_MEDIA_LOCATION)
+ } else {
+ setOf(READ_MEDIA_VISUAL_USER_SELECTED)
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageControlPreferenceUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageControlPreferenceUtils.kt
index db79165c3..cd046ec73 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageControlPreferenceUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageControlPreferenceUtils.kt
@@ -36,11 +36,12 @@ import com.android.permissioncontroller.permission.utils.StringUtils
@RequiresApi(Build.VERSION_CODES.S)
object PermissionUsageControlPreferenceUtils {
- private val SENSOR_DATA_PERMISSIONS: List<String> = listOf(
- Manifest.permission_group.LOCATION,
- Manifest.permission_group.CAMERA,
- Manifest.permission_group.MICROPHONE
- )
+ private val SENSOR_DATA_PERMISSIONS: List<String> =
+ listOf(
+ Manifest.permission_group.LOCATION,
+ Manifest.permission_group.CAMERA,
+ Manifest.permission_group.MICROPHONE
+ )
@JvmStatic
fun initPreference(
@@ -56,19 +57,28 @@ object PermissionUsageControlPreferenceUtils {
return preference.apply {
title = permGroupLabel
icon = KotlinUtils.getPermGroupIcon(context, groupName)
- summary = StringUtils.getIcuPluralsString(context,
- R.string.permission_usage_preference_label, count)
+ summary =
+ StringUtils.getIcuPluralsString(
+ context,
+ R.string.permission_usage_preference_label,
+ count
+ )
if (count == 0) {
isEnabled = false
- val permissionUsageSummaryNotUsed = if (show7Days) {
- StringUtils.getIcuPluralsString(context,
+ val permissionUsageSummaryNotUsed =
+ if (show7Days) {
+ StringUtils.getIcuPluralsString(
+ context,
R.string.permission_usage_preference_summary_not_used_in_past_n_days,
- 7)
- } else {
- StringUtils.getIcuPluralsString(context,
+ 7
+ )
+ } else {
+ StringUtils.getIcuPluralsString(
+ context,
R.string.permission_usage_preference_summary_not_used_in_past_n_hours,
- 24)
- }
+ 24
+ )
+ }
setSummary(permissionUsageSummaryNotUsed)
} else if (SENSOR_DATA_PERMISSIONS.contains(groupName)) {
onPreferenceClickListener = OnPreferenceClickListener {
@@ -92,18 +102,19 @@ object PermissionUsageControlPreferenceUtils {
}
private fun logSensorDataTimelineViewed(groupName: String, sessionId: Long) {
- val act = when (groupName) {
- Manifest.permission_group.LOCATION -> {
- PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__LOCATION_ACCESS_TIMELINE_VIEWED
- }
- Manifest.permission_group.CAMERA -> {
- PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__CAMERA_ACCESS_TIMELINE_VIEWED
- }
- Manifest.permission_group.MICROPHONE -> {
- PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__MICROPHONE_ACCESS_TIMELINE_VIEWED
+ val act =
+ when (groupName) {
+ Manifest.permission_group.LOCATION -> {
+ PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__LOCATION_ACCESS_TIMELINE_VIEWED
+ }
+ Manifest.permission_group.CAMERA -> {
+ PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__CAMERA_ACCESS_TIMELINE_VIEWED
+ }
+ Manifest.permission_group.MICROPHONE -> {
+ PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__MICROPHONE_ACCESS_TIMELINE_VIEWED
+ }
+ else -> 0
}
- else -> 0
- }
PermissionControllerStatsLog.write(PERMISSION_USAGE_FRAGMENT_INTERACTION, sessionId, act)
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
index f77bfff3b..826e57ece 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
@@ -28,6 +28,7 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Resources
+import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.os.UserHandle
@@ -37,12 +38,12 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.savedstate.SavedStateRegistryOwner
import com.android.modules.utils.build.SdkLevel
-import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.compat.IntentCompat
import com.android.permissioncontroller.permission.data.AppPermGroupUiInfoLiveData
import com.android.permissioncontroller.permission.data.LightPackageInfoLiveData
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
+import com.android.permissioncontroller.permission.data.get
import com.android.permissioncontroller.permission.data.v31.AllLightHistoricalPackageOpsLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.model.livedatatypes.v31.AppPermissionId
@@ -54,7 +55,6 @@ import com.android.permissioncontroller.permission.model.livedatatypes.v31.Light
import com.android.permissioncontroller.permission.ui.handheld.v31.getDurationUsedStr
import com.android.permissioncontroller.permission.ui.handheld.v31.shouldShowSubattributionInPermissionsDashboard
import com.android.permissioncontroller.permission.utils.KotlinUtils
-import com.android.permissioncontroller.permission.utils.KotlinUtils.getPackageLabel
import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
@@ -80,6 +80,9 @@ class PermissionUsageDetailsViewModel(
val showSystemLiveData = state.getLiveData(SHOULD_SHOW_SYSTEM_KEY, false)
val show7DaysLiveData = state.getLiveData(SHOULD_SHOW_7_DAYS_KEY, false)
+ private val packageIconCache: MutableMap<Pair<String, UserHandle>, Drawable> = mutableMapOf()
+ private val packageLabelCache: MutableMap<String, String> = mutableMapOf()
+
private val roleManager =
Utils.getSystemServiceSafe(application.applicationContext, RoleManager::class.java)
@@ -109,14 +112,19 @@ class PermissionUsageDetailsViewModel(
}
val startTime =
(System.currentTimeMillis() - showPermissionUsagesDuration).coerceAtLeast(
- Instant.EPOCH.toEpochMilli())
+ Instant.EPOCH.toEpochMilli()
+ )
return PermissionUsageDetailsUiInfo(
show7Days,
showSystem,
buildAppPermissionAccessUiInfoList(
- allLightHistoricalPackageOpsLiveData, startTime, showSystem),
- containsSystemAppUsages(allLightHistoricalPackageOpsLiveData, startTime))
+ allLightHistoricalPackageOpsLiveData,
+ startTime,
+ showSystem
+ ),
+ containsSystemAppUsages(allLightHistoricalPackageOpsLiveData, startTime)
+ )
}
/**
@@ -162,9 +170,11 @@ class PermissionUsageDetailsViewModel(
// The Telecom doesn't request microphone or camera permissions. However, telecom app may
// use these permissions and they are considered system app permissions, so we return true
// even if the AppPermGroupUiInfo is unavailable.
- if (appPermissionId.packageName == TELECOM_PACKAGE &&
- (appPermissionId.permissionGroup == Manifest.permission_group.CAMERA ||
- appPermissionId.permissionGroup == Manifest.permission_group.MICROPHONE)) {
+ if (
+ appPermissionId.packageName == TELECOM_PACKAGE &&
+ (appPermissionId.permissionGroup == Manifest.permission_group.CAMERA ||
+ appPermissionId.permissionGroup == Manifest.permission_group.MICROPHONE)
+ ) {
return true
}
return false
@@ -244,7 +254,8 @@ class PermissionUsageDetailsViewModel(
it.appPermissionId,
it.attributionLabel,
it.attributionTags,
- updatedDiscreteAccesses)
+ updatedDiscreteAccesses
+ )
}
/** Filters out data for apps and permissions that don't need to be displayed in the UI. */
@@ -268,7 +279,8 @@ class PermissionUsageDetailsViewModel(
this.appPermissionId,
Resources.ID_NULL,
attributionTags = emptyList(),
- this.discreteAccesses)
+ this.discreteAccesses
+ )
/** Groups tag-attributed accesses for the provided app and permission by attribution label. */
private fun AttributedAppPermissionDiscreteAccesses.groupAccessesByLabel(
@@ -307,7 +319,9 @@ class PermissionUsageDetailsViewModel(
appPermissionId,
label,
tags,
- discreteAccesses.sortedBy { -1 * it.accessTimeMs }))
+ discreteAccesses.sortedBy { -1 * it.accessTimeMs }
+ )
+ )
}
return appPermissionDiscreteAccessWithLabels
@@ -334,7 +348,9 @@ class PermissionUsageDetailsViewModel(
appPermAccesses.appPermissionId,
appPermAccesses.attributionLabel,
appPermAccesses.attributionTags,
- currentDiscreteAccesses.toMutableList()))
+ currentDiscreteAccesses.toMutableList()
+ )
+ )
currentDiscreteAccesses.clear()
currentDiscreteAccesses.add(discreteAccess)
} else {
@@ -348,7 +364,9 @@ class PermissionUsageDetailsViewModel(
appPermAccesses.appPermissionId,
appPermAccesses.attributionLabel,
appPermAccesses.attributionTags,
- currentDiscreteAccesses.toMutableList()))
+ currentDiscreteAccesses.toMutableList()
+ )
+ )
}
return clusters
}
@@ -384,12 +402,15 @@ class PermissionUsageDetailsViewModel(
return AppPermissionAccessUiInfo(
this.appPermissionId.userHandle,
this.appPermissionId.packageName,
+ getPackageLabel(this.appPermissionId.packageName, this.appPermissionId.userHandle),
permissionGroup,
this.discreteAccesses.last().accessTimeMs,
this.discreteAccesses.first().accessTimeMs,
summary,
showingSubAttribution,
- ArrayList(this.attributionTags))
+ ArrayList(this.attributionTags),
+ getBadgedPackageIcon(this.appPermissionId.packageName, this.appPermissionId.userHandle)
+ )
}
/** Builds a summary of the permission access. */
@@ -410,10 +431,14 @@ class PermissionUsageDetailsViewModel(
R.string.history_preference_subtext_3,
subTextStrings[0],
subTextStrings[1],
- subTextStrings[2])
+ subTextStrings[2]
+ )
2 ->
context.getString(
- R.string.history_preference_subtext_2, subTextStrings[0], subTextStrings[1])
+ R.string.history_preference_subtext_2,
+ subTextStrings[0],
+ subTextStrings[1]
+ )
1 -> subTextStrings[0]
else -> null
}
@@ -462,7 +487,6 @@ class PermissionUsageDetailsViewModel(
.firstOrNull { it.proxy?.packageName != null }
?.let {
getPackageLabel(
- PermissionControllerApplication.get(),
it.proxy!!.packageName!!,
UserHandle.getUserHandleForUid(it.proxy.uid))
}
@@ -492,13 +516,15 @@ class PermissionUsageDetailsViewModel(
/** Data used to create a preference for an app's permission usage. */
data class AppPermissionAccessUiInfo(
val userHandle: UserHandle,
- val pkgName: String,
+ val packageName: String,
+ val packageLabel: String,
val permissionGroup: String,
val accessStartTime: Long,
val accessEndTime: Long,
val summaryText: CharSequence?,
val showingAttribution: Boolean,
val attributionTags: ArrayList<String>,
+ val badgedPackageIcon: Drawable?,
)
/**
@@ -593,13 +619,17 @@ class PermissionUsageDetailsViewModel(
setSourcesToDifference(
appPermissionIds,
appPermGroupUiInfoLiveDataList,
- getAppPermGroupUiInfoLiveData) {
- update()
- }
+ getAppPermGroupUiInfoLiveData
+ ) {
+ update()
+ }
setSourcesToDifference(
- allPackages, lightPackageInfoLiveDataMap, getLightPackageInfoLiveData) {
- update()
- }
+ allPackages,
+ lightPackageInfoLiveDataMap,
+ getLightPackageInfoLiveData
+ ) {
+ update()
+ }
if (appPermGroupUiInfoLiveDataList.any { it.value.isStale }) {
return
@@ -613,6 +643,36 @@ class PermissionUsageDetailsViewModel(
}
}
+ /**
+ * Returns the icon for the provided package name and user, by first searching the cache
+ * otherwise retrieving it from the app's [android.content.pm.ApplicationInfo].
+ */
+ private fun getBadgedPackageIcon(packageName: String, userHandle: UserHandle): Drawable? {
+ val packageNameWithUser: Pair<String, UserHandle> = Pair(packageName, userHandle)
+ if (packageIconCache.containsKey(packageNameWithUser)) {
+ return requireNotNull(packageIconCache[packageNameWithUser])
+ }
+ val packageIcon = KotlinUtils.getBadgedPackageIcon(application, packageName, userHandle)
+ if (packageIcon != null) packageIconCache[packageNameWithUser] = packageIcon
+
+ return packageIcon
+ }
+
+ /**
+ * Returns the label for the provided package name, by first searching the cache otherwise
+ * retrieving it from the app's [android.content.pm.ApplicationInfo].
+ */
+ private fun getPackageLabel(packageName: String, user: UserHandle): String {
+ if (packageLabelCache.containsKey(packageName)) {
+ return requireNotNull(packageLabelCache[packageName])
+ }
+
+ val packageLabel = KotlinUtils.getPackageLabel(application, packageName, user)
+ packageLabelCache[packageName] = packageLabel
+
+ return packageLabel
+ }
+
/** Companion object for [PermissionUsageDetailsViewModel]. */
companion object {
private const val ONE_HOUR_MS = 3_600_000
@@ -629,7 +689,8 @@ class PermissionUsageDetailsViewModel(
listOf(
Manifest.permission_group.CAMERA,
Manifest.permission_group.LOCATION,
- Manifest.permission_group.MICROPHONE)
+ Manifest.permission_group.MICROPHONE
+ )
.flatMap { group -> PermissionMapping.getPlatformPermissionNamesOfGroup(group) }
.mapNotNull { permName -> AppOpsManager.permissionToOp(permName) }
.toMutableSet()
@@ -659,7 +720,8 @@ class PermissionUsageDetailsViewModel(
accessStartTime,
accessEndTime,
showingAttribution,
- attributionTags)
+ attributionTags
+ )
?: getDefaultManageAppPermissionsIntent(packageName, userHandle)
}
@@ -692,11 +754,16 @@ class PermissionUsageDetailsViewModel(
}
val resolveInfo =
context.packageManager.resolveActivity(
- intent, PackageManager.ResolveInfoFlags.of(0))
- if (resolveInfo?.activityInfo == null ||
- !Objects.equals(
- resolveInfo.activityInfo.permission,
- Manifest.permission.START_VIEW_PERMISSION_USAGE)) {
+ intent,
+ PackageManager.ResolveInfoFlags.of(0)
+ )
+ if (
+ resolveInfo?.activityInfo == null ||
+ !Objects.equals(
+ resolveInfo.activityInfo.permission,
+ Manifest.permission.START_VIEW_PERMISSION_USAGE
+ )
+ ) {
return null
}
intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModel.kt
index eeac22124..fa5b1b685 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModel.kt
@@ -32,6 +32,7 @@ import com.android.permissioncontroller.permission.data.AppPermGroupUiInfoLiveDa
import com.android.permissioncontroller.permission.data.LightPackageInfoLiveData
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
import com.android.permissioncontroller.permission.data.StandardPermGroupNamesLiveData
+import com.android.permissioncontroller.permission.data.get
import com.android.permissioncontroller.permission.data.v31.AllLightPackageOpsLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.v31.AppPermissionId
import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightPackageOps
@@ -98,7 +99,8 @@ class PermissionUsageViewModel(
showSystem,
show7Days,
mAllLightPackageOpsLiveData.containsSystemAppUsages(startTime),
- mAllLightPackageOpsLiveData.buildPermissionGroupsWithUsageCounts(startTime, showSystem))
+ mAllLightPackageOpsLiveData.buildPermissionGroupsWithUsageCounts(startTime, showSystem)
+ )
}
/** Builds a map of permission groups to the number of apps that recently accessed them. */
@@ -119,9 +121,14 @@ class PermissionUsageViewModel(
lightPackageOps.lastPermissionGroupAccessTimesMs.entries
.filterOutExemptedPermissionGroupsFromKeys()
.filterOutPermissionsNotRequestedByApp(
- lightPackageOps.packageName, lightPackageOps.userHandle)
+ lightPackageOps.packageName,
+ lightPackageOps.userHandle
+ )
.filterOutSystemAppPermissionsIfNecessary(
- showSystem, lightPackageOps.packageName, lightPackageOps.userHandle)
+ showSystem,
+ lightPackageOps.packageName,
+ lightPackageOps.userHandle
+ )
.filterAccessTimeLaterThan(startTime)
val recentlyUsedPermissions: List<String> = permGroupsToLastAccess.map { it.key }
@@ -147,10 +154,14 @@ class PermissionUsageViewModel(
.filterAccessTimeLaterThan(startTime)
.map { it.key }
.toSet()
- if (recentlyUsedPermissions
- .filterOutExemptedPermissionGroups()
- .containsSystemAppPermission(
- lightPackageOps.packageName, lightPackageOps.userHandle)) {
+ if (
+ recentlyUsedPermissions
+ .filterOutExemptedPermissionGroups()
+ .containsSystemAppPermission(
+ lightPackageOps.packageName,
+ lightPackageOps.userHandle
+ )
+ ) {
return true
}
}
@@ -186,9 +197,11 @@ class PermissionUsageViewModel(
// The Telecom doesn't request microphone or camera permissions. However, telecom app may
// use these permissions and they are considered system app permissions, so we return true
// even if the AppPermGroupUiInfo is unavailable.
- if (appPermissionId.packageName == TELECOM_PACKAGE &&
- (appPermissionId.permissionGroup == Manifest.permission_group.CAMERA ||
- appPermissionId.permissionGroup == Manifest.permission_group.MICROPHONE)) {
+ if (
+ appPermissionId.packageName == TELECOM_PACKAGE &&
+ (appPermissionId.permissionGroup == Manifest.permission_group.CAMERA ||
+ appPermissionId.permissionGroup == Manifest.permission_group.MICROPHONE)
+ ) {
return true
}
return false
@@ -302,37 +315,56 @@ class PermissionUsageViewModel(
if (mAllLightPackageOpsLiveData.isStale) {
return
}
+ if (
+ appPermGroupUiInfoLiveDataList.any {
+ !it.value.isInitialized || it.value.isStale
+ }
+ ) {
+ return
+ }
+ if (
+ lightPackageInfoLiveDataMap.any { !it.value.isInitialized || it.value.isStale }
+ ) {
+ return
+ }
+ val packageOps: Map<Pair<String, UserHandle>, LightPackageOps> =
+ mAllLightPackageOpsLiveData.value ?: emptyMap()
val appPermissionIds = mutableListOf<AppPermissionId>()
- val allPackages = mAllLightPackageOpsLiveData.value?.keys ?: setOf()
- for (packageWithUserHandle: Pair<String, UserHandle> in allPackages) {
- for (permissionGroup in getAllEligiblePermissionGroups()) {
+ val allPackages = packageOps.keys
+
+ packageOps.forEach { (packageWithUserHandle, pkgOps) ->
+ pkgOps.lastPermissionGroupAccessTimesMs.keys.forEach { permissionGroup ->
appPermissionIds.add(
AppPermissionId(
packageWithUserHandle.first,
packageWithUserHandle.second,
permissionGroup,
- ))
+ )
+ )
}
}
setSourcesToDifference(
appPermissionIds,
appPermGroupUiInfoLiveDataList,
- getAppPermGroupUiInfoLiveData) {
- update()
- }
+ getAppPermGroupUiInfoLiveData
+ ) {
+ update()
+ }
setSourcesToDifference(
- allPackages, lightPackageInfoLiveDataMap, getLightPackageInfoLiveData) {
- update()
- }
+ allPackages,
+ lightPackageInfoLiveDataMap,
+ getLightPackageInfoLiveData
+ ) {
+ update()
+ }
if (lightPackageInfoLiveDataMap.any { it.value.isStale }) {
return
}
-
if (appPermGroupUiInfoLiveDataList.any { it.value.isStale }) {
return
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/ReviewOngoingUsageViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/ReviewOngoingUsageViewModel.kt
index d6efd38a6..d3b46defb 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/ReviewOngoingUsageViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/ReviewOngoingUsageViewModel.kt
@@ -14,6 +14,7 @@
* limitations under the License.
*/
@file:Suppress("DEPRECATION")
+
package com.android.permissioncontroller.permission.ui.model.v31
import android.Manifest
@@ -51,7 +52,6 @@ import com.android.permissioncontroller.permission.ui.handheld.v31.ReviewOngoing
import com.android.permissioncontroller.permission.ui.handheld.v31.ReviewOngoingUsageFragment.VIDEO_CALL
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.KotlinUtils.shouldShowLocationIndicators
-import com.android.permissioncontroller.permission.utils.KotlinUtils.shouldShowPermissionsDashboard
import com.android.permissioncontroller.permission.utils.Utils
import java.time.Instant
import kotlin.math.max
@@ -62,16 +62,11 @@ private const val CALL_OP_USAGE_KEY = "CALL_OP_USAGE"
private const val USAGES_KEY = "USAGES_KEY"
private const val MIC_MUTED_KEY = "MIC_MUTED_KEY"
-/**
- * ViewModel for {@link ReviewOngoingUsageFragment}
- */
-class ReviewOngoingUsageViewModel(
- state: SavedStateHandle,
- extraDurationMills: Long
-) : ViewModel() {
+/** ViewModel for {@link ReviewOngoingUsageFragment} */
+class ReviewOngoingUsageViewModel(state: SavedStateHandle, extraDurationMills: Long) : ViewModel() {
/** Time of oldest usages considered */
- private val startTime = max(state.get<Long>(FIRST_OPENED_KEY)!! - extraDurationMills,
- Instant.EPOCH.toEpochMilli())
+ private val startTime =
+ max(state.get<Long>(FIRST_OPENED_KEY)!! - extraDurationMills, Instant.EPOCH.toEpochMilli())
private val SYSTEM_PKG = "android"
@@ -80,8 +75,10 @@ class ReviewOngoingUsageViewModel(
val appUsages: Map<PackageAttribution, Set<String>>,
/** Op-names of phone call accesses */
val callUsages: Collection<String>,
- /** A map of attribution, packageName and user -> list of attribution labels to show with
- * microphone*/
+ /**
+ * A map of attribution, packageName and user -> list of attribution labels to show with
+ * microphone
+ */
val shownAttributions: Map<PackageAttribution, List<CharSequence>> = emptyMap()
)
@@ -101,292 +98,355 @@ class ReviewOngoingUsageViewModel(
*
* <p>Note: This does not use a cached live-data to avoid getting stale data
*/
- private val permGroupUsages = LoadAndFreezeLifeData(state, USAGES_KEY,
- PermGroupUsageLiveData(PermissionControllerApplication.get(),
- if (shouldShowPermissionsDashboard() || shouldShowLocationIndicators()) {
- listOf(CAMERA, LOCATION, MICROPHONE)
- } else {
- listOf(CAMERA, MICROPHONE)
- }, System.currentTimeMillis() - startTime))
+ private val permGroupUsages =
+ LoadAndFreezeLifeData(
+ state,
+ USAGES_KEY,
+ PermGroupUsageLiveData(
+ PermissionControllerApplication.get(),
+ if (shouldShowLocationIndicators()) {
+ listOf(CAMERA, LOCATION, MICROPHONE)
+ } else {
+ listOf(CAMERA, MICROPHONE)
+ },
+ System.currentTimeMillis() - startTime
+ )
+ )
- /**
- * Whether the mic is muted
- */
+ /** Whether the mic is muted */
private val isMicMuted = LoadAndFreezeLifeData(state, MIC_MUTED_KEY, micMutedLiveData)
/** App runtime permission usages */
- private val appUsagesLiveData = object : SmartUpdateMediatorLiveData<Map<PackageAttribution,
- Set<String>>>() {
- private val app = PermissionControllerApplication.get()
-
- init {
- addSource(permGroupUsages) {
- update()
- }
+ private val appUsagesLiveData =
+ object : SmartUpdateMediatorLiveData<Map<PackageAttribution, Set<String>>>() {
+ private val app = PermissionControllerApplication.get()
- addSource(isMicMuted) {
- update()
- }
- }
+ init {
+ addSource(permGroupUsages) { update() }
- override fun onUpdate() {
- if (!permGroupUsages.isInitialized || !isMicMuted.isInitialized) {
- return
+ addSource(isMicMuted) { update() }
}
- if (permGroupUsages.value == null) {
- value = null
- return
- }
+ override fun onUpdate() {
+ if (!permGroupUsages.isInitialized || !isMicMuted.isInitialized) {
+ return
+ }
- // Filter out system package
- val filteredUsages = mutableMapOf<PackageAttribution, MutableSet<String>>()
- for ((permGroupName, usages) in permGroupUsages.value!!) {
- if (permGroupName == MICROPHONE && isMicMuted.value == true) {
- continue
+ if (permGroupUsages.value == null) {
+ value = null
+ return
}
- for (usage in usages) {
- if (usage.packageName != SYSTEM_PKG) {
- filteredUsages.getOrPut(getPackageAttr(usage),
- { mutableSetOf() }).add(permGroupName)
+ // Filter out system package
+ val filteredUsages = mutableMapOf<PackageAttribution, MutableSet<String>>()
+ for ((permGroupName, usages) in permGroupUsages.value!!) {
+ if (permGroupName == MICROPHONE && isMicMuted.value == true) {
+ continue
+ }
+
+ for (usage in usages) {
+ if (usage.packageName != SYSTEM_PKG) {
+ filteredUsages
+ .getOrPut(getPackageAttr(usage), { mutableSetOf() })
+ .add(permGroupName)
+ }
}
}
- }
- value = filteredUsages
- }
+ value = filteredUsages
+ }
- // TODO ntmyren: Replace this with better check if this moves beyond teamfood
- private fun isAppPredictor(usage: OpAccess): Boolean {
- return Utils.getUserContext(app, usage.user).packageManager.checkPermission(
- Manifest.permission.MANAGE_APP_PREDICTIONS, usage.packageName) ==
- PackageManager.PERMISSION_GRANTED
+ // TODO ntmyren: Replace this with better check if this moves beyond teamfood
+ private fun isAppPredictor(usage: OpAccess): Boolean {
+ return Utils.getUserContext(app, usage.user)
+ .packageManager
+ .checkPermission(
+ Manifest.permission.MANAGE_APP_PREDICTIONS,
+ usage.packageName
+ ) == PackageManager.PERMISSION_GRANTED
+ }
}
- }
/**
- * Gets all trusted proxied voice IME and voice recognition microphone uses, and get the
- * label needed to display with it, as well as information about the proxy whose label is being
- * shown, if applicable.
+ * Gets all trusted proxied voice IME and voice recognition microphone uses, and get the label
+ * needed to display with it, as well as information about the proxy whose label is being shown,
+ * if applicable.
*/
- private val trustedAttrsLiveData = object : SmartAsyncMediatorLiveData<
- Map<PackageAttribution, CharSequence>>() {
- private val VOICE_IME_SUBTYPE = "voice"
+ private val trustedAttrsLiveData =
+ object : SmartAsyncMediatorLiveData<Map<PackageAttribution, CharSequence>>() {
+ private val VOICE_IME_SUBTYPE = "voice"
- private val attributionLabelLiveDatas =
- mutableMapOf<Triple<String?, String, UserHandle>, AttributionLabelLiveData>()
+ private val attributionLabelLiveDatas =
+ mutableMapOf<Triple<String?, String, UserHandle>, AttributionLabelLiveData>()
- init {
- addSource(permGroupUsages) {
- updateAsync()
+ init {
+ addSource(permGroupUsages) { updateAsync() }
}
- }
- override suspend fun loadDataAndPostValue(job: Job) {
- if (!permGroupUsages.isInitialized) {
- return
- }
- val usages = permGroupUsages.value?.get(MICROPHONE) ?: run {
- postValue(emptyMap())
- return
- }
- val proxies = usages.mapNotNull { it.proxyAccess }
-
- val proxyLabelLiveDatas = proxies.map {
- Triple(it.attributionTag, it.packageName, it.user) }
- val toAddLabelLiveDatas = (usages.map { Triple(it.attributionTag, it.packageName,
- it.user) } + proxyLabelLiveDatas).distinct()
- val getLiveDataFun = { key: Triple<String?, String, UserHandle> ->
- AttributionLabelLiveData[key] }
- setSourcesToDifference(toAddLabelLiveDatas, attributionLabelLiveDatas, getLiveDataFun)
-
- if (attributionLabelLiveDatas.any { !it.value.isInitialized }) {
- return
- }
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (!permGroupUsages.isInitialized) {
+ return
+ }
+ val usages =
+ permGroupUsages.value?.get(MICROPHONE)
+ ?: run {
+ postValue(emptyMap())
+ return
+ }
+ val proxies = usages.mapNotNull { it.proxyAccess }
+
+ val proxyLabelLiveDatas =
+ proxies.map { Triple(it.attributionTag, it.packageName, it.user) }
+ val toAddLabelLiveDatas =
+ (usages.map { Triple(it.attributionTag, it.packageName, it.user) } +
+ proxyLabelLiveDatas)
+ .distinct()
+ val getLiveDataFun = { key: Triple<String?, String, UserHandle> ->
+ AttributionLabelLiveData[key]
+ }
+ setSourcesToDifference(
+ toAddLabelLiveDatas,
+ attributionLabelLiveDatas,
+ getLiveDataFun
+ )
+
+ if (attributionLabelLiveDatas.any { !it.value.isInitialized }) {
+ return
+ }
- val approvedAttrs = mutableMapOf<PackageAttribution, String>()
- for (user in usages.map { it.user }.distinct()) {
- val userContext = Utils.getUserContext(PermissionControllerApplication.get(), user)
-
- // TODO ntmyren: Observe changes, possibly split into separate LiveDatas
- val voiceInputs = mutableMapOf<String, CharSequence>()
- userContext.getSystemService(InputMethodManager::class.java)!!
- .enabledInputMethodList.forEach {
- for (i in 0 until it.subtypeCount) {
- if (it.getSubtypeAt(i).mode == VOICE_IME_SUBTYPE) {
- voiceInputs[it.packageName] =
- it.serviceInfo.loadSafeLabel(userContext.packageManager,
- Float.MAX_VALUE, 0)
- break
+ val approvedAttrs = mutableMapOf<PackageAttribution, String>()
+ for (user in usages.map { it.user }.distinct()) {
+ val userContext =
+ Utils.getUserContext(PermissionControllerApplication.get(), user)
+
+ // TODO ntmyren: Observe changes, possibly split into separate LiveDatas
+ val voiceInputs = mutableMapOf<String, CharSequence>()
+ userContext
+ .getSystemService(InputMethodManager::class.java)!!
+ .enabledInputMethodList
+ .forEach {
+ for (i in 0 until it.subtypeCount) {
+ if (it.getSubtypeAt(i).mode == VOICE_IME_SUBTYPE) {
+ voiceInputs[it.packageName] =
+ it.serviceInfo.loadSafeLabel(
+ userContext.packageManager,
+ Float.MAX_VALUE,
+ 0
+ )
+ break
+ }
}
}
+
+ // Get the currently selected recognizer from the secure setting.
+ val recognitionPackageName =
+ Settings.Secure.getString(
+ userContext.contentResolver,
+ // Settings.Secure.VOICE_RECOGNITION_SERVICE
+ "voice_recognition_service"
+ )
+ ?.let(ComponentName::unflattenFromString)
+ ?.packageName
+
+ val recognizers = mutableMapOf<String, CharSequence>()
+ val availableRecognizers =
+ userContext.packageManager.queryIntentServices(
+ Intent(RecognitionService.SERVICE_INTERFACE),
+ PackageManager.GET_META_DATA
+ )
+ availableRecognizers.forEach {
+ val sI = it.serviceInfo
+ if (sI.packageName == recognitionPackageName) {
+ recognizers[sI.packageName] =
+ sI.loadSafeLabel(userContext.packageManager, Float.MAX_VALUE, 0)
+ }
}
- // Get the currently selected recognizer from the secure setting.
- val recognitionPackageName = Settings.Secure.getString(userContext.contentResolver,
- // Settings.Secure.VOICE_RECOGNITION_SERVICE
- "voice_recognition_service")
- ?.let(ComponentName::unflattenFromString)?.packageName
-
- val recognizers = mutableMapOf<String, CharSequence>()
- val availableRecognizers = userContext.packageManager.queryIntentServices(
- Intent(RecognitionService.SERVICE_INTERFACE), PackageManager.GET_META_DATA)
- availableRecognizers.forEach {
- val sI = it.serviceInfo
- if (sI.packageName == recognitionPackageName) {
- recognizers[sI.packageName] = sI.loadSafeLabel(userContext.packageManager,
- Float.MAX_VALUE, 0)
+ val recognizerIntents = mutableMapOf<String, CharSequence>()
+ val availableRecognizerIntents =
+ userContext.packageManager.queryIntentActivities(
+ Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH),
+ PackageManager.GET_META_DATA
+ )
+ availableRecognizers.forEach { rI ->
+ val servicePkg = rI.serviceInfo.packageName
+ if (
+ servicePkg == recognitionPackageName &&
+ availableRecognizerIntents.any {
+ it.activityInfo.packageName == servicePkg
+ }
+ ) {
+ // If this recognizer intent is also a recognizer service, and is
+ // trusted,
+ // Then attribute to voice recognition
+ recognizerIntents[servicePkg] =
+ rI.serviceInfo.loadSafeLabel(
+ userContext.packageManager,
+ Float.MAX_VALUE,
+ 0
+ )
+ }
}
- }
- val recognizerIntents = mutableMapOf<String, CharSequence>()
- val availableRecognizerIntents = userContext.packageManager.queryIntentActivities(
- Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), PackageManager.GET_META_DATA)
- availableRecognizers.forEach { rI ->
- val servicePkg = rI.serviceInfo.packageName
- if (servicePkg == recognitionPackageName && availableRecognizerIntents.any {
- it.activityInfo.packageName == servicePkg }) {
- // If this recognizer intent is also a recognizer service, and is trusted,
- // Then attribute to voice recognition
- recognizerIntents[servicePkg] =
- rI.serviceInfo.loadSafeLabel(userContext.packageManager,
- Float.MAX_VALUE, 0)
+ // get attribution labels for voice IME, recognition intents, and recognition
+ // services
+ for (opAccess in usages) {
+ setTrustedAttrsForAccess(
+ userContext,
+ opAccess,
+ user,
+ false,
+ voiceInputs,
+ approvedAttrs
+ )
+ setTrustedAttrsForAccess(
+ userContext,
+ opAccess,
+ user,
+ false,
+ recognizerIntents,
+ approvedAttrs
+ )
+ setTrustedAttrsForAccess(
+ userContext,
+ opAccess,
+ user,
+ true,
+ recognizers,
+ approvedAttrs
+ )
}
}
+ postValue(approvedAttrs)
+ }
+
+ private fun setTrustedAttrsForAccess(
+ context: Context,
+ opAccess: OpAccess,
+ currUser: UserHandle,
+ getProxyLabel: Boolean,
+ trustedMap: Map<String, CharSequence>,
+ toSetMap: MutableMap<PackageAttribution, String>
+ ) {
+ val access =
+ if (getProxyLabel) {
+ opAccess.proxyAccess
+ } else {
+ opAccess
+ }
- // get attribution labels for voice IME, recognition intents, and recognition
- // services
- for (opAccess in usages) {
- setTrustedAttrsForAccess(userContext, opAccess, user, false, voiceInputs,
- approvedAttrs)
- setTrustedAttrsForAccess(userContext, opAccess, user, false, recognizerIntents,
- approvedAttrs)
- setTrustedAttrsForAccess(userContext, opAccess, user, true, recognizers,
- approvedAttrs)
+ if (
+ access == null || access.user != currUser || access.packageName !in trustedMap
+ ) {
+ return
}
- }
- postValue(approvedAttrs)
- }
-
- private fun setTrustedAttrsForAccess(
- context: Context,
- opAccess: OpAccess,
- currUser: UserHandle,
- getProxyLabel: Boolean,
- trustedMap: Map<String, CharSequence>,
- toSetMap: MutableMap<PackageAttribution, String>
- ) {
- val access = if (getProxyLabel) {
- opAccess.proxyAccess
- } else {
- opAccess
- }
- if (access == null || access.user != currUser || access.packageName !in trustedMap) {
- return
- }
-
- val appAttr = getPackageAttr(access)
- val packageName = access.packageName
-
- val labelResId = attributionLabelLiveDatas[Triple(access.attributionTag,
- access.packageName, access.user)]?.value ?: 0
- val label = try {
- context.createPackageContext(packageName, 0)
- .getString(labelResId)
- } catch (e: Exception) {
- return
- }
- if (trustedMap[packageName] == label) {
- toSetMap[appAttr] = label
+ val appAttr = getPackageAttr(access)
+ val packageName = access.packageName
+
+ val labelResId =
+ attributionLabelLiveDatas[
+ Triple(access.attributionTag, access.packageName, access.user)]
+ ?.value
+ ?: 0
+ val label =
+ try {
+ context.createPackageContext(packageName, 0).getString(labelResId)
+ } catch (e: Exception) {
+ return
+ }
+ if (trustedMap[packageName] == label) {
+ toSetMap[appAttr] = label
+ }
}
}
- }
/**
* Get all chains of proxy usages. A proxy chain is defined as one usage at the root, then
* further proxy usages, where the app and attribution tag of the proxy matches the previous
* usage in the chain.
*/
- private val proxyChainsLiveData = object : SmartUpdateMediatorLiveData<Set<List<OpAccess>>>() {
- init {
- addSource(permGroupUsages) {
- update()
- }
- }
- override fun onUpdate() {
- if (!permGroupUsages.isInitialized) {
- return
- }
- val usages = permGroupUsages.value?.get(MICROPHONE) ?: emptyList()
- // a map of chain start -> in progress chain
- val proxyChains = mutableMapOf<PackageAttribution, MutableList<OpAccess>>()
-
- val remainingProxyChainUsages = mutableMapOf<PackageAttribution, OpAccess>()
- for (usage in usages) {
- remainingProxyChainUsages[getPackageAttr(usage)] = usage
+ private val proxyChainsLiveData =
+ object : SmartUpdateMediatorLiveData<Set<List<OpAccess>>>() {
+ init {
+ addSource(permGroupUsages) { update() }
}
- // find all one-link chains (that is, all proxied apps whose proxy is not included in
- // the usage list)
- for (usage in usages) {
- val usageAttr = getPackageAttr(usage)
- val proxyAttr = getPackageAttr(usage.proxyAccess ?: continue)
- if (!usages.any { getPackageAttr(it) == proxyAttr }) {
- proxyChains[usageAttr] = mutableListOf(usage)
- remainingProxyChainUsages.remove(usageAttr)
+ override fun onUpdate() {
+ if (!permGroupUsages.isInitialized) {
+ return
}
- }
+ val usages = permGroupUsages.value?.get(MICROPHONE) ?: emptyList()
+ // a map of chain start -> in progress chain
+ val proxyChains = mutableMapOf<PackageAttribution, MutableList<OpAccess>>()
- // find all possible starting points for chains
- for ((usageAttr, usage) in remainingProxyChainUsages.toMap()) {
- // If this usage has a proxy, but is not a proxy, it is the start of a chain.
- // If it has no proxy, and isn't a proxy, remove it.
- if (!remainingProxyChainUsages.values.any { it.proxyAccess != null &&
- getPackageAttr(it.proxyAccess) == usageAttr }) {
- if (usage.proxyAccess != null) {
+ val remainingProxyChainUsages = mutableMapOf<PackageAttribution, OpAccess>()
+ for (usage in usages) {
+ remainingProxyChainUsages[getPackageAttr(usage)] = usage
+ }
+ // find all one-link chains (that is, all proxied apps whose proxy is not included
+ // in
+ // the usage list)
+ for (usage in usages) {
+ val usageAttr = getPackageAttr(usage)
+ val proxyAttr = getPackageAttr(usage.proxyAccess ?: continue)
+ if (!usages.any { getPackageAttr(it) == proxyAttr }) {
proxyChains[usageAttr] = mutableListOf(usage)
- } else {
remainingProxyChainUsages.remove(usageAttr)
}
}
- }
- // assemble the chains
- for ((startUsageAttr, proxyChain) in proxyChains) {
- var currentUsage = remainingProxyChainUsages[startUsageAttr] ?: continue
- while (currentUsage.proxyAccess != null) {
- val currPackageAttr = getPackageAttr(currentUsage.proxyAccess!!)
- currentUsage = remainingProxyChainUsages[currPackageAttr] ?: break
- if (proxyChain.any { it == currentUsage }) {
- // we have a cycle, and should break
- break
+ // find all possible starting points for chains
+ for ((usageAttr, usage) in remainingProxyChainUsages.toMap()) {
+ // If this usage has a proxy, but is not a proxy, it is the start of a chain.
+ // If it has no proxy, and isn't a proxy, remove it.
+ if (
+ !remainingProxyChainUsages.values.any {
+ it.proxyAccess != null && getPackageAttr(it.proxyAccess) == usageAttr
+ }
+ ) {
+ if (usage.proxyAccess != null) {
+ proxyChains[usageAttr] = mutableListOf(usage)
+ } else {
+ remainingProxyChainUsages.remove(usageAttr)
+ }
}
- proxyChain.add(currentUsage)
}
- // invert the lists, so the element without a proxy is first on the list
- proxyChain.reverse()
- }
- value = proxyChains.values.toSet()
+ // assemble the chains
+ for ((startUsageAttr, proxyChain) in proxyChains) {
+ var currentUsage = remainingProxyChainUsages[startUsageAttr] ?: continue
+ while (currentUsage.proxyAccess != null) {
+ val currPackageAttr = getPackageAttr(currentUsage.proxyAccess!!)
+ currentUsage = remainingProxyChainUsages[currPackageAttr] ?: break
+ if (proxyChain.any { it == currentUsage }) {
+ // we have a cycle, and should break
+ break
+ }
+ proxyChain.add(currentUsage)
+ }
+ // invert the lists, so the element without a proxy is first on the list
+ proxyChain.reverse()
+ }
+
+ value = proxyChains.values.toSet()
+ }
}
- }
/** Phone call usages */
private val callOpUsageLiveData =
object : SmartUpdateMediatorLiveData<Collection<String>>() {
- private val rawOps = LoadAndFreezeLifeData(state, CALL_OP_USAGE_KEY,
- OpUsageLiveData[listOf(PHONE_CALL, VIDEO_CALL),
- System.currentTimeMillis() - startTime])
+ private val rawOps =
+ LoadAndFreezeLifeData(
+ state,
+ CALL_OP_USAGE_KEY,
+ OpUsageLiveData[
+ listOf(PHONE_CALL, VIDEO_CALL), System.currentTimeMillis() - startTime]
+ )
init {
- addSource(rawOps) {
- update()
- }
+ addSource(rawOps) { update() }
- addSource(isMicMuted) {
- update()
- }
+ addSource(isMicMuted) { update() }
}
override fun onUpdate() {
@@ -394,145 +454,152 @@ class ReviewOngoingUsageViewModel(
return
}
- value = if (isMicMuted.value == true) {
- rawOps.value!!.keys.filter { it != PHONE_CALL }
- } else {
- rawOps.value!!.keys
- }
+ value =
+ if (isMicMuted.value == true) {
+ rawOps.value!!.keys.filter { it != PHONE_CALL }
+ } else {
+ rawOps.value!!.keys
+ }
}
}
/** App, system, and call usages in a single, nice, handy package */
- val usages = object : SmartAsyncMediatorLiveData<Usages>() {
- private val app = PermissionControllerApplication.get()
+ val usages =
+ object : SmartAsyncMediatorLiveData<Usages>() {
+ private val app = PermissionControllerApplication.get()
- init {
- addSource(appUsagesLiveData) {
- update()
- }
-
- addSource(callOpUsageLiveData) {
- update()
- }
-
- addSource(trustedAttrsLiveData) {
- update()
- }
+ init {
+ addSource(appUsagesLiveData) { update() }
- addSource(proxyChainsLiveData) {
- update()
- }
- }
+ addSource(callOpUsageLiveData) { update() }
- override suspend fun loadDataAndPostValue(job: Job) {
- if (job.isCancelled) {
- return
- }
+ addSource(trustedAttrsLiveData) { update() }
- if (!callOpUsageLiveData.isInitialized || !appUsagesLiveData.isInitialized ||
- !trustedAttrsLiveData.isInitialized || !proxyChainsLiveData.isInitialized) {
- return
+ addSource(proxyChainsLiveData) { update() }
}
- val callOpUsages = callOpUsageLiveData.value?.toMutableSet()
- val appUsages = appUsagesLiveData.value?.toMutableMap()
- val approvedAttrs = trustedAttrsLiveData.value?.toMutableMap() ?: mutableMapOf()
- val proxyChains = proxyChainsLiveData.value ?: emptySet()
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (job.isCancelled) {
+ return
+ }
- if (callOpUsages == null || appUsages == null) {
- postValue(null)
- return
- }
+ if (
+ !callOpUsageLiveData.isInitialized ||
+ !appUsagesLiveData.isInitialized ||
+ !trustedAttrsLiveData.isInitialized ||
+ !proxyChainsLiveData.isInitialized
+ ) {
+ return
+ }
- // If there is nothing to show the dialog should be closed, hence return a "invalid"
- // value
- if (appUsages.isEmpty() && callOpUsages.isEmpty()) {
- postValue(null)
- return
- }
+ val callOpUsages = callOpUsageLiveData.value?.toMutableSet()
+ val appUsages = appUsagesLiveData.value?.toMutableMap()
+ val approvedAttrs = trustedAttrsLiveData.value?.toMutableMap() ?: mutableMapOf()
+ val proxyChains = proxyChainsLiveData.value ?: emptySet()
- // If we are in a VOIP call (aka MODE_IN_COMMUNICATION), and have a carrier privileged
- // app using the mic, hide phone usage.
- val audioManager = app.getSystemService(AudioManager::class.java)!!
- if (callOpUsages.isNotEmpty() && audioManager.mode == MODE_IN_COMMUNICATION) {
- val telephonyManager = app.getSystemService(TelephonyManager::class.java)!!
- for ((pkg, usages) in appUsages) {
- if (telephonyManager.checkCarrierPrivilegesForPackage(pkg.packageName) ==
- CARRIER_PRIVILEGE_STATUS_HAS_ACCESS && usages.contains(MICROPHONE)) {
- callOpUsages.clear()
- continue
- }
+ if (callOpUsages == null || appUsages == null) {
+ postValue(null)
+ return
}
- }
- // Find labels for proxies, and assign them to the proper app, removing other usages
- val approvedLabels = mutableMapOf<PackageAttribution, List<CharSequence>>()
- for (chain in proxyChains) {
- // if the final link in the chain is not user sensitive, do not show the chain
- if (getPackageAttr(chain[chain.size - 1]) !in appUsages) {
- continue
+ // If there is nothing to show the dialog should be closed, hence return a "invalid"
+ // value
+ if (appUsages.isEmpty() && callOpUsages.isEmpty()) {
+ postValue(null)
+ return
}
- // if the proxy access is missing, for some reason, do not show the proxy
- if (chain.size == 1) {
- continue
+ // If we are in a VOIP call (aka MODE_IN_COMMUNICATION), and have a carrier
+ // privileged
+ // app using the mic, hide phone usage.
+ val audioManager = app.getSystemService(AudioManager::class.java)!!
+ if (callOpUsages.isNotEmpty() && audioManager.mode == MODE_IN_COMMUNICATION) {
+ val telephonyManager = app.getSystemService(TelephonyManager::class.java)!!
+ for ((pkg, usages) in appUsages) {
+ if (
+ telephonyManager.checkCarrierPrivilegesForPackage(pkg.packageName) ==
+ CARRIER_PRIVILEGE_STATUS_HAS_ACCESS && usages.contains(MICROPHONE)
+ ) {
+ callOpUsages.clear()
+ continue
+ }
+ }
}
- val labels = mutableListOf<CharSequence>()
- for ((idx, opAccess) in chain.withIndex()) {
- val appAttr = getPackageAttr(opAccess)
- // If this is the last link in the proxy chain, assign it the series of labels
- // Else, if it has a special label, add that label
- // Else, if there are no other apps in the remaining part of the chain which
- // have the same package name, add the app label
- // If it is not the last link in the chain, remove its attribution
- if (idx == chain.size - 1) {
- approvedLabels[appAttr] = labels
+ // Find labels for proxies, and assign them to the proper app, removing other usages
+ val approvedLabels = mutableMapOf<PackageAttribution, List<CharSequence>>()
+ for (chain in proxyChains) {
+ // if the final link in the chain is not user sensitive, do not show the chain
+ if (getPackageAttr(chain[chain.size - 1]) !in appUsages) {
continue
- } else if (appAttr in approvedAttrs) {
- labels.add(approvedAttrs[appAttr]!!)
- approvedAttrs.remove(appAttr)
- } else if (chain.subList(idx + 1, chain.size).all {
- it.packageName != opAccess.packageName } &&
- opAccess.packageName != SYSTEM_PKG) {
- labels.add(KotlinUtils.getPackageLabel(app, opAccess.packageName,
- opAccess.user))
}
- appUsages.remove(appAttr)
+
+ // if the proxy access is missing, for some reason, do not show the proxy
+ if (chain.size == 1) {
+ continue
+ }
+
+ val labels = mutableListOf<CharSequence>()
+ for ((idx, opAccess) in chain.withIndex()) {
+ val appAttr = getPackageAttr(opAccess)
+ // If this is the last link in the proxy chain, assign it the series of
+ // labels
+ // Else, if it has a special label, add that label
+ // Else, if there are no other apps in the remaining part of the chain which
+ // have the same package name, add the app label
+ // If it is not the last link in the chain, remove its attribution
+ if (idx == chain.size - 1) {
+ approvedLabels[appAttr] = labels
+ continue
+ } else if (appAttr in approvedAttrs) {
+ labels.add(approvedAttrs[appAttr]!!)
+ approvedAttrs.remove(appAttr)
+ } else if (
+ chain.subList(idx + 1, chain.size).all {
+ it.packageName != opAccess.packageName
+ } && opAccess.packageName != SYSTEM_PKG
+ ) {
+ labels.add(
+ KotlinUtils.getPackageLabel(
+ app,
+ opAccess.packageName,
+ opAccess.user
+ )
+ )
+ }
+ appUsages.remove(appAttr)
+ }
}
- }
- // Any remaining truested attributions must be for non-proxy usages, so add them
- for ((packageAttr, label) in approvedAttrs) {
- approvedLabels[packageAttr] = listOf(label)
- }
+ // Any remaining truested attributions must be for non-proxy usages, so add them
+ for ((packageAttr, label) in approvedAttrs) {
+ approvedLabels[packageAttr] = listOf(label)
+ }
- removeDuplicates(appUsages, approvedLabels.keys)
+ removeDuplicates(appUsages, approvedLabels.keys)
- postValue(Usages(appUsages, callOpUsages, approvedLabels))
- }
+ postValue(Usages(appUsages, callOpUsages, approvedLabels))
+ }
- /**
- * Merge any usages for the same app which don't have a special attribution
- */
- private fun removeDuplicates(
- appUsages: MutableMap<PackageAttribution, Set<String>>,
- approvedUsages: Collection<PackageAttribution>
- ) {
- // Iterate over all non-special attribution keys
- for (packageAttr in appUsages.keys.minus(approvedUsages)) {
- var groupSet = appUsages[packageAttr] ?: continue
-
- for (otherAttr in appUsages.keys.minus(approvedUsages)) {
- if (otherAttr.pkgEq(packageAttr)) {
- groupSet = groupSet.plus(appUsages[otherAttr] ?: emptySet())
- appUsages.remove(otherAttr)
+ /** Merge any usages for the same app which don't have a special attribution */
+ private fun removeDuplicates(
+ appUsages: MutableMap<PackageAttribution, Set<String>>,
+ approvedUsages: Collection<PackageAttribution>
+ ) {
+ // Iterate over all non-special attribution keys
+ for (packageAttr in appUsages.keys.minus(approvedUsages)) {
+ var groupSet = appUsages[packageAttr] ?: continue
+
+ for (otherAttr in appUsages.keys.minus(approvedUsages)) {
+ if (otherAttr.pkgEq(packageAttr)) {
+ groupSet = groupSet.plus(appUsages[otherAttr] ?: emptySet())
+ appUsages.remove(otherAttr)
+ }
}
+ appUsages[packageAttr] = groupSet
}
- appUsages[packageAttr] = groupSet
}
}
- }
private fun getPackageAttr(usage: OpAccess): PackageAttribution {
return PackageAttribution(usage.attributionTag, usage.packageName, usage.user)
@@ -556,8 +623,10 @@ class ReviewOngoingUsageViewModelFactory(
modelClass: Class<T>,
handle: SavedStateHandle
): T {
- handle.set(FIRST_OPENED_KEY, handle.get<Long>(FIRST_OPENED_KEY)
- ?: System.currentTimeMillis())
+ handle.set(
+ FIRST_OPENED_KEY,
+ handle.get<Long>(FIRST_OPENED_KEY) ?: System.currentTimeMillis()
+ )
@Suppress("UNCHECKED_CAST")
return ReviewOngoingUsageViewModel(handle, extraDurationMillis) as T
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/ReviewPermissionDecisionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/ReviewPermissionDecisionsViewModel.kt
index 69709264b..bb3c44675 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/ReviewPermissionDecisionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/ReviewPermissionDecisionsViewModel.kt
@@ -28,7 +28,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.android.permissioncontroller.DumpableLog
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
import com.android.permissioncontroller.permission.data.UserPackageInfosLiveData
import com.android.permissioncontroller.permission.data.v33.PermissionDecision
@@ -37,9 +36,10 @@ import com.android.permissioncontroller.permission.model.livedatatypes.LightPack
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
import com.android.permissioncontroller.permission.ui.auto.AutoReviewPermissionDecisionsFragment
import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.StringUtils
-import kotlinx.coroutines.Job
import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.Job
/** Viewmodel for [ReviewPermissionDecisionsFragment] */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@@ -50,82 +50,94 @@ class ReviewPermissionDecisionsViewModel(val app: Application, val user: UserHan
private val recentPermissionsLiveData = RecentPermissionDecisionsLiveData()
private val userPackageInfosLiveData = UserPackageInfosLiveData[user]
- val recentPermissionDecisionsLiveData = object
- : SmartAsyncMediatorLiveData<List<PermissionDecision>>(
- alwaysUpdateOnActive = false
- ) {
+ val recentPermissionDecisionsLiveData =
+ object :
+ SmartAsyncMediatorLiveData<List<PermissionDecision>>(alwaysUpdateOnActive = false) {
- init {
- addSource(recentPermissionsLiveData) {
- onUpdate()
- }
+ init {
+ addSource(recentPermissionsLiveData) { onUpdate() }
- addSource(userPackageInfosLiveData) {
- onUpdate()
- }
- }
-
- override suspend fun loadDataAndPostValue(job: Job) {
- if (!recentPermissionsLiveData.isInitialized ||
- !userPackageInfosLiveData.isInitialized) {
- return
+ addSource(userPackageInfosLiveData) { onUpdate() }
}
- // create package info lookup map for performance
- val packageToLightPackageInfo: MutableMap<String, LightPackageInfo> = mutableMapOf()
- for (lightPackageInfo in userPackageInfosLiveData.value!!) {
- packageToLightPackageInfo[lightPackageInfo.packageName] = lightPackageInfo
- }
-
- // verify that permission state is still correct. Will also filter out any apps that
- // were uninstalled
- val decisionsToReview: MutableList<PermissionDecision> = mutableListOf()
- for (recentDecision in recentPermissionsLiveData.value!!) {
- val lightPackageInfo = packageToLightPackageInfo[recentDecision.packageName]
- if (lightPackageInfo == null) {
- DumpableLog.e(LOG_TAG, "Package $recentDecision.packageName " +
- "is no longer installed")
- continue
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (
+ !recentPermissionsLiveData.isInitialized ||
+ !userPackageInfosLiveData.isInitialized
+ ) {
+ return
}
- val grantedGroups: List<String?> = lightPackageInfo.grantedPermissions.map {
- PermissionMapping.getGroupOfPermission(
- app.packageManager.getPermissionInfo(it, /* flags= */ 0))
+
+ // create package info lookup map for performance
+ val packageToLightPackageInfo: MutableMap<String, LightPackageInfo> = mutableMapOf()
+ for (lightPackageInfo in userPackageInfosLiveData.value!!) {
+ packageToLightPackageInfo[lightPackageInfo.packageName] = lightPackageInfo
}
- val currentlyGranted = grantedGroups.contains(recentDecision.permissionGroupName)
- if (currentlyGranted && recentDecision.isGranted) {
- decisionsToReview.add(recentDecision)
- } else if (!currentlyGranted && !recentDecision.isGranted) {
- decisionsToReview.add(recentDecision)
- } else {
- // It's okay for this to happen - the state could change due to role changes,
- // app hibernation, or other non-user-driven actions.
- DumpableLog.d(LOG_TAG,
- "Permission decision grant state (${recentDecision.isGranted}) " +
- "for ${recentDecision.packageName} access to " +
- "${recentDecision.permissionGroupName} does not match current " +
- "grant state $currentlyGranted")
+
+ // verify that permission state is still correct. Will also filter out any apps that
+ // were uninstalled
+ val decisionsToReview: MutableList<PermissionDecision> = mutableListOf()
+ for (recentDecision in recentPermissionsLiveData.value!!) {
+ val lightPackageInfo = packageToLightPackageInfo[recentDecision.packageName]
+ if (lightPackageInfo == null) {
+ DumpableLog.e(
+ LOG_TAG,
+ "Package $recentDecision.packageName " + "is no longer installed"
+ )
+ continue
+ }
+ val grantedGroups: List<String?> =
+ lightPackageInfo.grantedPermissions.map {
+ PermissionMapping.getGroupOfPermission(
+ app.packageManager.getPermissionInfo(it, /* flags= */ 0)
+ )
+ }
+ val currentlyGranted =
+ grantedGroups.contains(recentDecision.permissionGroupName)
+ if (currentlyGranted && recentDecision.isGranted) {
+ decisionsToReview.add(recentDecision)
+ } else if (!currentlyGranted && !recentDecision.isGranted) {
+ decisionsToReview.add(recentDecision)
+ } else {
+ // It's okay for this to happen - the state could change due to role
+ // changes,
+ // app hibernation, or other non-user-driven actions.
+ DumpableLog.d(
+ LOG_TAG,
+ "Permission decision grant state (${recentDecision.isGranted}) " +
+ "for ${recentDecision.packageName} access to " +
+ "${recentDecision.permissionGroupName} does not match current " +
+ "grant state $currentlyGranted"
+ )
+ }
}
- }
- postValue(decisionsToReview)
+ postValue(decisionsToReview)
+ }
}
- }
fun getAppIcon(packageName: String): Drawable? {
return KotlinUtils.getBadgedPackageIcon(app, packageName, user)
}
fun createPreferenceTitle(permissionDecision: PermissionDecision): String {
- val packageLabel = BidiFormatter.getInstance().unicodeWrap(
- KotlinUtils.getPackageLabel(app, permissionDecision.packageName, user))
- val permissionGroupLabel = KotlinUtils.getPermGroupLabel(app,
- permissionDecision.permissionGroupName).toString()
+ val packageLabel =
+ BidiFormatter.getInstance()
+ .unicodeWrap(KotlinUtils.getPackageLabel(app, permissionDecision.packageName, user))
+ val permissionGroupLabel =
+ KotlinUtils.getPermGroupLabel(app, permissionDecision.permissionGroupName).toString()
return if (permissionDecision.isGranted) {
- app.getString(R.string.granted_permission_decision, packageLabel,
- UCharacter.toLowerCase(permissionGroupLabel))
+ app.getString(
+ R.string.granted_permission_decision,
+ packageLabel,
+ UCharacter.toLowerCase(permissionGroupLabel)
+ )
} else {
- app.getString(R.string.denied_permission_decision, packageLabel,
- UCharacter.toLowerCase(permissionGroupLabel))
+ app.getString(
+ R.string.denied_permission_decision,
+ packageLabel,
+ UCharacter.toLowerCase(permissionGroupLabel)
+ )
}
}
@@ -134,8 +146,10 @@ class ReviewPermissionDecisionsViewModel(val app: Application, val user: UserHan
putExtra(Intent.EXTRA_PACKAGE_NAME, permissionDecision.packageName)
putExtra(Intent.EXTRA_PERMISSION_NAME, permissionDecision.permissionGroupName)
putExtra(Intent.EXTRA_USER, user)
- putExtra(ManagePermissionsActivity.EXTRA_CALLER_NAME,
- AutoReviewPermissionDecisionsFragment::class.java.name)
+ putExtra(
+ ManagePermissionsActivity.EXTRA_CALLER_NAME,
+ AutoReviewPermissionDecisionsFragment::class.java.name
+ )
}
}
@@ -146,15 +160,12 @@ class ReviewPermissionDecisionsViewModel(val app: Application, val user: UserHan
}
}
-/**
- * Factory for a [ReviewPermissionDecisionsViewModel]
- */
+/** Factory for a [ReviewPermissionDecisionsViewModel] */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class ReviewPermissionDecisionsViewModelFactory(val app: Application, val user: UserHandle) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
- @Suppress("UNCHECKED_CAST")
- return ReviewPermissionDecisionsViewModel(app, user) as T
+ @Suppress("UNCHECKED_CAST") return ReviewPermissionDecisionsViewModel(app, user) as T
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt
index 304dc3db4..7bc0e1e1f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt
@@ -32,14 +32,14 @@ import androidx.lifecycle.ViewModelProvider
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.PermissionControllerStatsLog
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED
-import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__INSTALL_SOURCE
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__HELP_CENTER
+import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__INSTALL_SOURCE
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_SETTINGS
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_RATIONALE_DIALOG_VIEWED
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
import com.android.permissioncontroller.permission.data.get
+import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT
@@ -75,8 +75,8 @@ class PermissionRationaleViewModel(
/**
* Should be invoked by base activity when a valid onActivityResult is received
*
- * @param data [Intent] which may contain result data from a started Activity
- * (various data can be attached to Intent "extras")
+ * @param data [Intent] which may contain result data from a started Activity (various data
+ * can be attached to Intent "extras")
* @return {@code true} if Activity should finish after processing this result
*/
fun shouldFinishActivityForResult(data: Intent?): Boolean
@@ -88,12 +88,12 @@ class PermissionRationaleViewModel(
* should be shown with it.
*/
data class PermissionRationaleInfo(
- val groupName: String,
- val isPreloadedApp: Boolean,
- val installSourcePackageName: String?,
- val installSourceLabel: String?,
- val purposeSet: Set<Int>
- )
+ val groupName: String,
+ val isPreloadedApp: Boolean,
+ val installSourcePackageName: String?,
+ val installSourceLabel: String?,
+ val purposeSet: Set<Int>
+ )
/** A [LiveData] which holds the currently pending PermissionRationaleInfo */
val permissionRationaleInfoLiveData =
@@ -126,8 +126,11 @@ class PermissionRationaleViewModel(
KotlinUtils.getPackageLabel(app, it, Process.myUserHandle())
}
- val purposes = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(
- safetyLabelInfo.safetyLabel, permissionGroupName)
+ val purposes =
+ SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(
+ safetyLabelInfo.safetyLabel,
+ permissionGroupName
+ )
if (value == null) {
logPermissionRationaleDialogViewed(purposes)
}
@@ -137,7 +140,8 @@ class PermissionRationaleViewModel(
safetyLabelInfo.installSourceInfo.isPreloadedApp,
installSourcePackageName,
installSourceLabel,
- purposes)
+ purposes
+ )
}
}
@@ -147,7 +151,8 @@ class PermissionRationaleViewModel(
fun sendToAppStore(context: Context, installSourcePackageName: String) {
logPermissionRationaleDialogActionReported(
- PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__INSTALL_SOURCE)
+ PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__INSTALL_SOURCE
+ )
val storeIntent = getAppStoreIntent(context, installSourcePackageName, packageName)
context.startActivity(storeIntent)
}
@@ -162,14 +167,17 @@ class PermissionRationaleViewModel(
if (activityResultCallback != null) {
return
}
- activityResultCallback = object : ActivityResultCallback {
- override fun shouldFinishActivityForResult(data: Intent?): Boolean {
- val returnGroupName = data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED)
- return (returnGroupName != null) && data.hasExtra(EXTRA_RESULT_PERMISSION_RESULT)
+ activityResultCallback =
+ object : ActivityResultCallback {
+ override fun shouldFinishActivityForResult(data: Intent?): Boolean {
+ val returnGroupName = data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED)
+ return (returnGroupName != null) &&
+ data.hasExtra(EXTRA_RESULT_PERMISSION_RESULT)
+ }
}
- }
logPermissionRationaleDialogActionReported(
- PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_SETTINGS)
+ PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_SETTINGS
+ )
startAppPermissionFragment(activity, groupName)
}
@@ -192,11 +200,13 @@ class PermissionRationaleViewModel(
// Add in some extra locale query parameters
val fullUri =
HelpUtils.uriWithAddedParameters(activity, Uri.parse(getHelpCenterUrlString(activity)))
- val intent = Intent(Intent.ACTION_VIEW, fullUri).apply {
- setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
- }
+ val intent =
+ Intent(Intent.ACTION_VIEW, fullUri).apply {
+ setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ }
logPermissionRationaleDialogActionReported(
- PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__HELP_CENTER)
+ PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__HELP_CENTER
+ )
try {
activity.startActivity(intent)
} catch (e: ActivityNotFoundException) {
@@ -206,14 +216,17 @@ class PermissionRationaleViewModel(
}
private fun startAppPermissionFragment(activity: Activity, groupName: String) {
- val intent = Intent(Intent.ACTION_MANAGE_APP_PERMISSION)
- .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
- .putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
- .putExtra(Intent.EXTRA_USER, user)
- .putExtra(ManagePermissionsActivity.EXTRA_CALLER_NAME,
- PermissionRationaleActivity::class.java.name)
- .putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ val intent =
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSION)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
+ .putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
+ .putExtra(Intent.EXTRA_USER, user)
+ .putExtra(
+ ManagePermissionsActivity.EXTRA_CALLER_NAME,
+ PermissionRationaleActivity::class.java.name
+ )
+ .putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
activity.startActivityForResult(intent, APP_PERMISSION_REQUEST_CODE)
}
@@ -225,14 +238,24 @@ class PermissionRationaleViewModel(
purposes.forEach { purposeInt ->
purposesPresented = purposesPresented or 1.shl(purposeInt)
}
- PermissionControllerStatsLog.write(PERMISSION_RATIONALE_DIALOG_VIEWED, sessionId, uid,
- permissionGroupName, purposesPresented)
+ PermissionControllerStatsLog.write(
+ PERMISSION_RATIONALE_DIALOG_VIEWED,
+ sessionId,
+ uid,
+ permissionGroupName,
+ purposesPresented
+ )
}
fun logPermissionRationaleDialogActionReported(buttonPressed: Int) {
val uid = KotlinUtils.getPackageUid(app, packageName, user) ?: return
- PermissionControllerStatsLog.write(PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED, sessionId,
- uid, permissionGroupName, buttonPressed)
+ PermissionControllerStatsLog.write(
+ PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED,
+ sessionId,
+ uid,
+ permissionGroupName,
+ buttonPressed
+ )
}
private fun getHelpCenterUrlString(context: Context): String? {
@@ -257,7 +280,12 @@ class PermissionRationaleViewModelFactory(
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return PermissionRationaleViewModel(
- app, packageName, permissionGroupName, sessionId, savedState)
+ app,
+ packageName,
+ permissionGroupName,
+ sessionId,
+ savedState
+ )
as T
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AllAppPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AllAppPermissionsFragment.java
index e5c63f5ab..43cad8335 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AllAppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AllAppPermissionsFragment.java
@@ -228,7 +228,7 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
if (pref == null) {
pref = new PreferenceCategory(getActivity());
pref.setKey(group.name);
- pref.setLayoutResource(R.layout.preference_category_material);
+ pref.setLayoutResource(androidx.preference.R.layout.preference_category_material);
pref.setTitle(group.loadLabel(pm));
prefs.add(pref);
getPreferenceScreen().addPreference(pref);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
index e2df47009..399a694d0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
@@ -289,7 +289,7 @@ public class AppPermissionFragment extends SettingsWithHeader
});
mAllowAlwaysButton.setOnPreferenceClickListener((v) -> {
if (mIsStorageGroup) {
- showConfirmDialog(ChangeRequest.GRANT_All_FILE_ACCESS,
+ showConfirmDialog(ChangeRequest.GRANT_ALL_FILE_ACCESS,
R.string.special_file_access_dialog, -1, false);
} else {
mViewModel.requestChange(false, this, this, ChangeRequest.GRANT_BOTH,
@@ -464,7 +464,7 @@ public class AppPermissionFragment extends SettingsWithHeader
public Dialog onCreateDialog(Bundle savedInstanceState) {
AppPermissionFragment fragment = (AppPermissionFragment) getTargetFragment();
boolean isGrantFileAccess = getArguments().getSerializable(CHANGE_REQUEST)
- == ChangeRequest.GRANT_All_FILE_ACCESS;
+ == ChangeRequest.GRANT_ALL_FILE_ACCESS;
int positiveButtonStringResId = R.string.grant_dialog_button_deny_anyway;
if (isGrantFileAccess) {
positiveButtonStringResId = R.string.grant_dialog_button_allow;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/GrantPermissionsViewHandlerImpl.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
index 45dd4c1f2..da0b28b4d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
@@ -194,25 +194,19 @@ public final class GrantPermissionsViewHandlerImpl implements GrantPermissionsVi
@Override
public void onClick(View view) {
- switch (view.getId()) {
- case R.id.permission_allow_button:
- mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
- break;
- case R.id.permission_allow_always_button:
- mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
- break;
- case R.id.permission_allow_foreground_only_button:
- mResultListener.onPermissionGrantResult(mGroupName, GRANTED_FOREGROUND_ONLY);
- break;
- case R.id.permission_allow_one_time_button:
- mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ONE_TIME);
- break;
- case R.id.permission_deny_button:
- mResultListener.onPermissionGrantResult(mGroupName, DENIED);
- break;
- case R.id.permission_deny_dont_ask_again_button:
- mResultListener.onPermissionGrantResult(mGroupName, DENIED_DO_NOT_ASK_AGAIN);
- break;
+ final int id = view.getId();
+ if (id == R.id.permission_allow_button) {
+ mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
+ } else if (id == R.id.permission_allow_always_button) {
+ mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
+ } else if (id == R.id.permission_allow_foreground_only_button) {
+ mResultListener.onPermissionGrantResult(mGroupName, GRANTED_FOREGROUND_ONLY);
+ } else if (id == R.id.permission_allow_one_time_button) {
+ mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ONE_TIME);
+ } else if (id == R.id.permission_deny_button) {
+ mResultListener.onPermissionGrantResult(mGroupName, DENIED);
+ } else if (id == R.id.permission_deny_dont_ask_again_button) {
+ mResultListener.onPermissionGrantResult(mGroupName, DENIED_DO_NOT_ASK_AGAIN);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionsFrameFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionsFrameFragment.java
index b3a473914..8a4638839 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionsFrameFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionsFrameFragment.java
@@ -140,7 +140,7 @@ public abstract class PermissionsFrameFragment extends PreferenceFragmentCompat
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
VerticalGridView verticalGridView = (VerticalGridView) inflater.inflate(
- R.layout.leanback_preferences_list, parent, false);
+ androidx.leanback.preference.R.layout.leanback_preferences_list, parent, false);
verticalGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
verticalGridView.setFocusScrollStrategy(VerticalGridView.FOCUS_SCROLL_ALIGNED);
mGridView = verticalGridView;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsFragment.kt
index 07e2ab08f..6797f5dff 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsFragment.kt
@@ -27,16 +27,14 @@ import com.android.permissioncontroller.hibernation.isHibernationEnabled
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment.Companion.INFO_MSG_CATEGORY
-/**
- * TV wrapper, with customizations, around [UnusedAppsFragment].
- */
-class TvUnusedAppsFragment : SettingsWithHeader(),
- UnusedAppsFragment.Parent<TvUnusedAppsPreference> {
+/** TV wrapper, with customizations, around [UnusedAppsFragment]. */
+class TvUnusedAppsFragment :
+ SettingsWithHeader(), UnusedAppsFragment.Parent<TvUnusedAppsPreference> {
companion object {
private const val UNUSED_PREFERENCE_KEY = "unused_pref_row_key"
- /** Create a new instance of this fragment. */
+ /** Create a new instance of this fragment. */
@JvmStatic
fun newInstance(): TvUnusedAppsFragment {
return TvUnusedAppsFragment()
@@ -50,15 +48,12 @@ class TvUnusedAppsFragment : SettingsWithHeader(),
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null) {
- val fragment:
- UnusedAppsFragment<TvUnusedAppsFragment, TvUnusedAppsPreference> =
+ val fragment: UnusedAppsFragment<TvUnusedAppsFragment, TvUnusedAppsPreference> =
UnusedAppsFragment.newInstance()
fragment.arguments = arguments
// child fragment does not have its own UI - it will add to the preferences of this
// parent fragment
- childFragmentManager.beginTransaction()
- .add(fragment, null)
- .commit()
+ childFragmentManager.beginTransaction().add(fragment, null).commit()
}
}
@@ -67,8 +62,7 @@ class TvUnusedAppsFragment : SettingsWithHeader(),
if (isHibernationEnabled()) {
preference.summary = getString(R.string.unused_apps_page_tv_summary)
} else {
- preference.summary =
- getString(R.string.auto_revoked_apps_page_summary)
+ preference.summary = getString(R.string.auto_revoked_apps_page_summary)
}
preference.setIcon(R.drawable.ic_info_outline)
preference.isSelectable = false
@@ -93,9 +87,9 @@ class TvUnusedAppsFragment : SettingsWithHeader(),
override fun setEmptyState(empty: Boolean) {
val infoMsgCategory =
- preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
+ preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
val noUnusedAppsPreference: Preference? =
- infoMsgCategory.findPreference<Preference>(UNUSED_PREFERENCE_KEY)
+ infoMsgCategory.findPreference<Preference>(UNUSED_PREFERENCE_KEY)
if (empty && noUnusedAppsPreference == null) {
infoMsgCategory.addPreference(createNoUnusedAppsPreference())
} else if (noUnusedAppsPreference != null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsPreference.kt
index 905aa30d1..bc29e928f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/TvUnusedAppsPreference.kt
@@ -16,10 +16,10 @@
package com.android.permissioncontroller.permission.ui.television
-import androidx.preference.Preference
import android.app.Application
import android.content.Context
import android.os.UserHandle
+import androidx.preference.Preference
import com.android.permissioncontroller.permission.ui.RemovablePref
import com.android.permissioncontroller.permission.utils.KotlinUtils
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt
index b841f3aeb..a2505312d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt
@@ -28,8 +28,7 @@ data class AdvancedConfirmDialogArgs(
@StringRes val messageId: Int,
@StringRes val negativeButtonTextId: Int,
@StringRes val positiveButtonTextId: Int,
-
val changeRequest: AppPermissionViewModel.ChangeRequest? = null,
val setOneTime: Boolean? = null,
val buttonClicked: Int? = null
-) \ No newline at end of file
+)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/widget/SafetyProtectionSectionView.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/widget/SafetyProtectionSectionView.kt
index daea1c198..9f91f3c18 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/widget/SafetyProtectionSectionView.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/widget/SafetyProtectionSectionView.kt
@@ -49,11 +49,12 @@ class SafetyProtectionSectionView : LinearLayout {
init {
gravity = Gravity.CENTER
orientation = HORIZONTAL
- visibility = if (KotlinUtils.shouldShowSafetyProtectionResources(context)) {
- View.VISIBLE
- } else {
- View.GONE
- }
+ visibility =
+ if (KotlinUtils.shouldShowSafetyProtectionResources(context)) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
}
override fun onFinishInflate() {
@@ -62,8 +63,9 @@ class SafetyProtectionSectionView : LinearLayout {
LayoutInflater.from(context).inflate(R.layout.safety_protection_section, this)
val safetyProtectionDisplayTextView =
requireViewById<TextView>(R.id.safety_protection_display_text)
- safetyProtectionDisplayTextView.setText(Html.fromHtml(
- context.getString(android.R.string.safety_protection_display_text), 0))
+ safetyProtectionDisplayTextView.setText(
+ Html.fromHtml(context.getString(android.R.string.safety_protection_display_text), 0)
+ )
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt
index 0b7537136..02f5e9d41 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt
@@ -38,8 +38,8 @@ interface PermissionRationaleViewHandler {
}
/**
- * Listener interface for getting notified when the user responds to a permission rationale
- * user action.
+ * Listener interface for getting notified when the user responds to a permission rationale user
+ * action.
*/
interface ResultListener {
fun onPermissionRationaleResult(groupName: String?, @Result result: Int)
@@ -60,7 +60,7 @@ interface PermissionRationaleViewHandler {
* @param groupName the name of the permission group
* @param title the title for the dialog
* @param dataSharingSourceMessage the data sharing source data usage comes from message to
- * display the user
+ * display the user
* @param purposeTitle the data usage purposes title to display the user
* @param purposeMessage the data usage purposes message to display the user
* @param learnMoreMessage the more info about safety labels message to display the user
@@ -91,9 +91,7 @@ interface PermissionRationaleViewHandler {
/** Gives a chance for handling the back key. */
fun onBackPressed()
- /**
- * Handles cancel event for the permission rationale dialog.
- */
+ /** Handles cancel event for the permission rationale dialog. */
fun onCancelled() {}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java
deleted file mode 100644
index 843514b4a..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
-* Copyright (C) 2015 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package com.android.permissioncontroller.permission.ui.wear;
-
-import android.app.Activity;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionInfo;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.Log;
-import android.view.View;
-import android.widget.Toast;
-
-import androidx.fragment.app.Fragment;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.SwitchPreference;
-import androidx.wear.ble.view.WearableDialogHelper;
-
-import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.model.AppPermissionGroup;
-import com.android.permissioncontroller.permission.model.AppPermissions;
-import com.android.permissioncontroller.permission.model.Permission;
-import com.android.permissioncontroller.permission.utils.ArrayUtils;
-import com.android.permissioncontroller.permission.utils.LocationUtils;
-import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.permission.utils.legacy.LegacySafetyNetLogger;
-import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public final class AppPermissionsFragmentWear extends PreferenceFragmentCompat {
- private static final String LOG_TAG = "AppPermFragWear";
-
- private static final String KEY_NO_PERMISSIONS = "no_permissions";
-
- public static AppPermissionsFragmentWear newInstance(String packageName) {
- return setPackageName(new AppPermissionsFragmentWear(), packageName);
- }
-
- private static <T extends Fragment> T setPackageName(T fragment, String packageName) {
- Bundle arguments = new Bundle();
- arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
- fragment.setArguments(arguments);
- return fragment;
- }
-
- private PackageManager mPackageManager;
- private ArraySet<AppPermissionGroup> mToggledGroups;
- private AppPermissions mAppPermissions;
-
- private boolean mHasConfirmedRevoke;
-
- /**
- * Provides click behavior for disabled preferences.
- */
- private static class PermissionSwitchPreference extends SwitchPreference {
-
- private final Activity mActivity;
-
- public PermissionSwitchPreference(Activity activity) {
- super(activity);
- this.mActivity = activity;
- }
-
- @Override
- protected void performClick(View view) {
- super.performClick(view);
-
- if (!isEnabled()) {
- // If setting the permission is disabled, it must have been locked
- // by the device or profile owner. So get that info and pass it to
- // the support details dialog.
- EnforcedAdmin deviceOrProfileOwner = RestrictedLockUtils.getProfileOrDeviceOwner(
- mActivity, UserHandle.of(UserHandle.myUserId()));
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
- mActivity, deviceOrProfileOwner);
- }
- }
- }
-
- @Override
- public void onCreatePreferences(Bundle bundle, String s) {
- // empty
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
- Activity activity = getActivity();
- mPackageManager = activity.getPackageManager();
-
- PackageInfo packageInfo;
-
- try {
- packageInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
- } catch (PackageManager.NameNotFoundException e) {
- Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e);
- packageInfo = null;
- }
-
- if (packageInfo == null) {
- Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show();
- activity.finish();
- return;
- }
-
- mAppPermissions = new AppPermissions(
- activity, packageInfo, true, () -> getActivity().finish());
-
- addPreferencesFromResource(R.xml.watch_permissions);
- initializePermissionGroupList();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mAppPermissions.refresh();
-
- // Also refresh the UI
- for (final AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
- if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) {
- for (PermissionInfo perm : getPermissionInfosFromGroup(group)) {
- setPreferenceCheckedIfPresent(perm.name,
- group.areRuntimePermissionsGranted(new String[]{ perm.name }));
- }
- } else {
- setPreferenceCheckedIfPresent(group.getName(), group.areRuntimePermissionsGranted());
- }
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- logAndClearToggledGroups();
- }
-
- private void initializePermissionGroupList() {
- List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups();
- List<SwitchPreference> nonSystemPreferences = new ArrayList<>();
-
- if (!groups.isEmpty()) {
- getPreferenceScreen().removePreference(findPreference(KEY_NO_PERMISSIONS));
- }
-
- for (final AppPermissionGroup group : groups) {
- if (!Utils.shouldShowPermission(getContext(), group)) {
- continue;
- }
-
- boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG);
-
- if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) {
- // If permission is controlled individually, we show all requested permission
- // inside this group.
- for (PermissionInfo perm : getPermissionInfosFromGroup(group)) {
- final SwitchPreference pref = createSwitchPreferenceForPermission(group, perm);
- showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform);
- }
- } else {
- final SwitchPreference pref = createSwitchPreferenceForGroup(group);
- showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform);
- }
- }
-
- // Now add the non-system settings to the end of the list
- for (SwitchPreference nonSystemPreference : nonSystemPreferences) {
- getPreferenceScreen().addPreference(nonSystemPreference);
- }
- }
-
- private void showOrAddToNonSystemPreferences(SwitchPreference pref,
- List<SwitchPreference> nonSystemPreferences, // Mutate
- boolean isPlatform) {
- // The UI shows System settings first, then non-system settings
- if (isPlatform) {
- getPreferenceScreen().addPreference(pref);
- } else {
- nonSystemPreferences.add(pref);
- }
- }
-
- private SwitchPreference createSwitchPreferenceForPermission(AppPermissionGroup group,
- PermissionInfo perm) {
- final SwitchPreference pref = new PermissionSwitchPreference(getActivity());
- pref.setKey(perm.name);
- pref.setTitle(perm.loadLabel(mPackageManager));
- pref.setChecked(group.areRuntimePermissionsGranted(new String[]{ perm.name }));
- pref.setOnPreferenceChangeListener((p, newVal) -> {
- if((Boolean) newVal) {
- group.grantRuntimePermissions(true, false, new String[]{ perm.name });
-
- if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())
- && group.doesSupportRuntimePermissions()) {
- // We are granting a permission from a group but since this is an
- // individual permission control other permissions in the group may
- // be revoked, hence we need to mark them user fixed to prevent the
- // app from requesting a non-granted permission and it being granted
- // because another permission in the group is granted. This applies
- // only to apps that support runtime permissions.
- String[] revokedPermissionsToFix = null;
- final int permissionCount = group.getPermissions().size();
-
- for (int i = 0; i < permissionCount; i++) {
- Permission current = group.getPermissions().get(i);
- if (!current.isGranted() && !current.isUserFixed()) {
- revokedPermissionsToFix = ArrayUtils.appendString(
- revokedPermissionsToFix, current.getName());
- }
- }
-
- if (revokedPermissionsToFix != null) {
- // If some permissions were not granted then they should be fixed.
- group.revokeRuntimePermissions(true, revokedPermissionsToFix);
- }
- }
- } else {
- final Permission appPerm = getPermissionFromGroup(group, perm.name);
- if (appPerm == null) {
- return false;
- }
-
- final boolean grantedByDefault = appPerm.isGrantedByDefault();
- if (grantedByDefault
- || (!group.doesSupportRuntimePermissions() && !mHasConfirmedRevoke)) {
- showRevocationWarningDialog(
- (dialog, which) -> {
- revokePermissionInGroup(group, perm.name);
- pref.setChecked(false);
- if (!appPerm.isGrantedByDefault()) {
- mHasConfirmedRevoke = true;
- }
- },
- grantedByDefault
- ? R.string.system_warning
- : R.string.old_sdk_deny_warning);
- return false;
- } else {
- revokePermissionInGroup(group, perm.name);
- }
- }
-
- return true;
- });
- return pref;
- }
-
- private void showRevocationWarningDialog(
- DialogInterface.OnClickListener confirmListener,
- int warningMessageId) {
- new WearableDialogHelper.DialogBuilder(getContext())
- .setNegativeIcon(R.drawable.confirm_button)
- .setPositiveIcon(R.drawable.cancel_button)
- .setNegativeButton(R.string.grant_dialog_button_deny_anyway, confirmListener)
- .setPositiveButton(R.string.cancel, null)
- .setMessage(warningMessageId)
- .show();
- }
-
- private static Permission getPermissionFromGroup(AppPermissionGroup group, String permName) {
- final int permissionCount = group.getPermissions().size();
-
- for (int i = 0; i < permissionCount; i++) {
- Permission currentPerm = group.getPermissions().get(i);
- if(currentPerm.getName().equals(permName)) {
- return currentPerm;
- };
- }
-
- if ("user".equals(Build.TYPE)) {
- Log.e(LOG_TAG, String.format("The impossible happens, permission %s is not in group %s.",
- permName, group.getName()));
- return null;
- } else {
- // This is impossible, throw a fatal error in non-user build.
- throw new IllegalArgumentException(
- String.format("Permission %s is not in group %s", permName, group.getName()));
- }
- }
-
- private void revokePermissionInGroup(AppPermissionGroup group, String permName) {
- group.revokeRuntimePermissions(true, new String[]{ permName });
-
- if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())
- && group.doesSupportRuntimePermissions()
- && !group.areRuntimePermissionsGranted()) {
- // If we just revoked the last permission we need to clear
- // the user fixed state as now the app should be able to
- // request them at runtime if supported.
- group.revokeRuntimePermissions(false);
- }
- }
-
- private SwitchPreference createSwitchPreferenceForGroup(AppPermissionGroup group) {
- final SwitchPreference pref = new PermissionSwitchPreference(getActivity());
-
- pref.setKey(group.getName());
- pref.setTitle(group.getLabel());
- pref.setChecked(group.areRuntimePermissionsGranted());
-
- if (group.isSystemFixed() || group.isPolicyFixed()) {
- pref.setEnabled(false);
- } else {
- pref.setOnPreferenceChangeListener((p, newVal) -> {
- if (LocationUtils.isLocationGroupAndProvider(getContext(),
- group.getName(), group.getApp().packageName)) {
- LocationUtils.showLocationDialog(
- getContext(), mAppPermissions.getAppLabel());
- return false;
- }
-
- if ((Boolean) newVal) {
- setPermission(group, pref, true);
- } else {
- final boolean grantedByDefault = group.hasGrantedByDefaultPermission();
- if (grantedByDefault
- || (!group.doesSupportRuntimePermissions() && !mHasConfirmedRevoke)) {
- showRevocationWarningDialog(
- (dialog, which) -> {
- setPermission(group, pref, false);
- if (!group.hasGrantedByDefaultPermission()) {
- mHasConfirmedRevoke = true;
- }
- },
- grantedByDefault
- ? R.string.system_warning
- : R.string.old_sdk_deny_warning);
- return false;
- } else {
- setPermission(group, pref, false);
- }
- }
-
- return true;
- });
- }
- return pref;
- }
-
- private void setPermission(AppPermissionGroup group, SwitchPreference pref, boolean grant) {
- if (grant) {
- group.grantRuntimePermissions(true, false);
- } else {
- group.revokeRuntimePermissions(false);
- }
- addToggledGroup(group);
- pref.setChecked(grant);
- }
-
- private void addToggledGroup(AppPermissionGroup group) {
- if (mToggledGroups == null) {
- mToggledGroups = new ArraySet<>();
- }
-
- mToggledGroups.add(group);
- }
-
- private void logAndClearToggledGroups() {
- if (mToggledGroups != null) {
- LegacySafetyNetLogger.logPermissionsToggled(mToggledGroups);
- mToggledGroups = null;
- }
- }
-
- private List<PermissionInfo> getPermissionInfosFromGroup(AppPermissionGroup group) {
- ArrayList<PermissionInfo> permInfos = new ArrayList<>(group.getPermissions().size());
- for(Permission perm : group.getPermissions()) {
- try {
- permInfos.add(mPackageManager.getPermissionInfo(perm.getName(), 0));
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(LOG_TAG, "No permission:" + perm.getName());
- }
- }
- return permInfos;
- }
-
- private void setPreferenceCheckedIfPresent(String preferenceKey, boolean checked) {
- Preference pref = findPreference(preferenceKey);
- if (pref instanceof SwitchPreference) {
- ((SwitchPreference) pref).setChecked(checked);
- }
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/GrantPermissionsWearViewHandler.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/GrantPermissionsWearViewHandler.java
index ccd1ed42e..cc32c5f02 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/GrantPermissionsWearViewHandler.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/GrantPermissionsWearViewHandler.java
@@ -16,62 +16,99 @@
package com.android.permissioncontroller.permission.ui.wear;
-import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_AND_DONT_ASK_AGAIN_BUTTON;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.TypedArray;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.Drawable;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ALWAYS_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_FOREGROUND_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ONE_TIME_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_AND_DONT_ASK_AGAIN_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_BOTH_LOCATIONS;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_COARSE_LOCATION_ONLY;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_FINE_LOCATION_ONLY;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.FINE_RADIO_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NEXT_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NEXT_LOCATION_DIALOG;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_BUTTON;
+
+import android.app.Activity;
import android.graphics.drawable.Icon;
import android.os.Bundle;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextUtils;
-import android.text.style.TextAppearanceSpan;
-import android.util.Log;
+import android.util.SparseIntArray;
import android.view.View;
-import android.view.WindowManager;
-import android.widget.Space;
+import android.view.WindowManager.LayoutParams;
-import androidx.wear.ble.view.AcceptDenyDialog;
-import androidx.wear.ble.view.WearableDialogHelper;
+import androidx.annotation.Nullable;
+import androidx.compose.ui.platform.ComposeView;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
+import com.android.permissioncontroller.permission.ui.wear.model.WearGrantPermissionsViewModel;
+import com.android.permissioncontroller.permission.ui.wear.model.WearGrantPermissionsViewModelFactory;
+
+import kotlin.Unit;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
- * Watch-specific view handler for the grant permissions activity.
+ * Wear-specific view handler for the grant permissions activity.
*/
-public final class GrantPermissionsWearViewHandler implements GrantPermissionsViewHandler,
- DialogInterface.OnClickListener {
- private static final String TAG = "GrantPermsWatchViewH";
-
- private static final String WATCH_HANDLER_BUNDLE = "watch_handler_bundle";
- private static final String DIALOG_BUNDLE = "dialog_bundle";
- private static final String GROUP_NAME = "group_name";
- private static final String SHOW_DO_NOT_ASK = "show_do_not_ask";
- private static final String ICON = "icon";
- private static final String MESSAGE = "message";
- private static final String CURRENT_PAGE_TEXT = "current_page_text";
+public class GrantPermissionsWearViewHandler implements GrantPermissionsViewHandler {
+
+ public static final String ARG_GROUP_NAME = "ARG_GROUP_NAME";
+ public static final String ARG_GROUP_COUNT = "ARG_GROUP_COUNT";
+ public static final String ARG_GROUP_INDEX = "ARG_GROUP_INDEX";
+ public static final String ARG_GROUP_ICON = "ARG_GROUP_ICON";
+ public static final String ARG_GROUP_MESSAGE = "ARG_GROUP_MESSAGE";
+ private static final String ARG_GROUP_DETAIL_MESSAGE = "ARG_GROUP_DETAIL_MESSAGE";
+ private static final String ARG_DIALOG_BUTTON_VISIBILITIES = "ARG_DIALOG_BUTTON_VISIBILITIES";
+ private static final String ARG_DIALOG_LOCATION_VISIBILITIES =
+ "ARG_DIALOG_LOCATION_VISIBILITIES";
+
+ public static final SparseIntArray BUTTON_RES_ID_TO_NUM = new SparseIntArray();
+ static {
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_button, ALLOW_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_always_button,
+ ALLOW_ALWAYS_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_foreground_only_button,
+ ALLOW_FOREGROUND_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_deny_button, DENY_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_deny_and_dont_ask_again_button,
+ DENY_AND_DONT_ASK_AGAIN_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_one_time_button, ALLOW_ONE_TIME_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_button, NO_UPGRADE_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_and_dont_ask_again_button,
+ NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_one_time_button, NO_UPGRADE_OT_BUTTON);
+ BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_one_time_and_dont_ask_again_button,
+ NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON);
+ }
- private final Context mContext;
+ private final Activity mActivity;
private ResultListener mResultListener;
- private Dialog mDialog;
-
+ // Configuration of the current dialog
private String mGroupName;
- private boolean mShowDoNotAsk;
-
- private CharSequence mMessage;
- private String mCurrentPageText;
- private Icon mIcon;
-
- public GrantPermissionsWearViewHandler(Context context) {
- mContext = context;
+ private int mGroupCount;
+ private int mGroupIndex;
+ private Icon mGroupIcon;
+ private CharSequence mGroupMessage;
+ private CharSequence mDetailMessage;
+ private final boolean[] mButtonVisibilities = new boolean[NEXT_BUTTON];
+ private final boolean[] mLocationVisibilities = new boolean[NEXT_LOCATION_DIALOG];
+ // View model to update WearGrantPermissionsScreen elements
+ private WearGrantPermissionsViewModel mViewModel;
+
+ public GrantPermissionsWearViewHandler(Activity activity) {
+ mActivity = activity;
}
@Override
@@ -81,17 +118,30 @@ public final class GrantPermissionsWearViewHandler implements GrantPermissionsVi
}
@Override
- public View createView() {
- return new Space(mContext);
+ public void saveInstanceState(Bundle arguments) {
+ arguments.putString(ARG_GROUP_NAME, mGroupName);
+ arguments.putInt(ARG_GROUP_COUNT, mGroupCount);
+ arguments.putInt(ARG_GROUP_INDEX, mGroupIndex);
+ arguments.putParcelable(ARG_GROUP_ICON, mGroupIcon);
+ arguments.putCharSequence(ARG_GROUP_MESSAGE, mGroupMessage);
+ arguments.putCharSequence(ARG_GROUP_DETAIL_MESSAGE, mDetailMessage);
+ arguments.putBooleanArray(ARG_DIALOG_BUTTON_VISIBILITIES, mButtonVisibilities);
+ arguments.putBooleanArray(ARG_DIALOG_LOCATION_VISIBILITIES, mLocationVisibilities);
}
@Override
- public void updateWindowAttributes(WindowManager.LayoutParams outLayoutParams) {
- outLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
- outLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
- outLayoutParams.format = PixelFormat.OPAQUE;
- outLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
- outLayoutParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ public void loadInstanceState(Bundle savedInstanceState) {
+ mGroupName = savedInstanceState.getString(ARG_GROUP_NAME);
+ mGroupMessage = savedInstanceState.getCharSequence(ARG_GROUP_MESSAGE);
+ mGroupIcon = savedInstanceState.getParcelable(ARG_GROUP_ICON);
+ mGroupCount = savedInstanceState.getInt(ARG_GROUP_COUNT);
+ mGroupIndex = savedInstanceState.getInt(ARG_GROUP_INDEX);
+ mDetailMessage = savedInstanceState.getCharSequence(ARG_GROUP_DETAIL_MESSAGE);
+ setButtonVisibilities(savedInstanceState.getBooleanArray(ARG_DIALOG_BUTTON_VISIBILITIES));
+ setLocationVisibilities(
+ savedInstanceState.getBooleanArray(ARG_DIALOG_LOCATION_VISIBILITIES));
+
+ updateScreen();
}
@Override
@@ -100,140 +150,166 @@ public final class GrantPermissionsWearViewHandler implements GrantPermissionsVi
CharSequence permissionRationaleMessage, boolean[] buttonVisibilities,
boolean[] locationVisibilities) {
// permissionRationaleMessage ignored by wear
-
- // TODO: Handle detailMessage
-
- boolean showDoNotAsk = buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON];
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "updateUi() - groupName: " + groupName
- + ", groupCount: " + groupCount
- + ", groupIndex: " + groupIndex
- + ", icon: " + icon
- + ", message: " + message
- + ", showDoNotAsk: " + showDoNotAsk);
+ if (mActivity.isFinishing()) {
+ return;
}
-
mGroupName = groupName;
- mShowDoNotAsk = showDoNotAsk;
- mMessage = message;
- mIcon = icon;
- mCurrentPageText = groupCount > 1
- ? mContext.getString(R.string.current_permission_template,
- groupIndex + 1, groupCount)
- : null;
- showDialog(null);
+ mGroupCount = groupCount;
+ mGroupIndex = groupIndex;
+ mGroupIcon = icon;
+ mGroupMessage = message;
+ mDetailMessage = detailMessage;
+ setButtonVisibilities(buttonVisibilities);
+ setLocationVisibilities(locationVisibilities);
+
+ updateScreen();
}
- private void showDialog(Bundle savedInstanceState) {
- TypedArray a = mContext.obtainStyledAttributes(
- new int[] { android.R.attr.textColorPrimary });
- int color = a.getColor(0, mContext.getColor(android.R.color.white));
- a.recycle();
- Drawable drawable = mIcon == null ? null : mIcon.setTint(color).loadDrawable(mContext);
-
- SpannableStringBuilder ssb = new SpannableStringBuilder();
- if (!TextUtils.isEmpty(mCurrentPageText)) {
- ssb.append(mCurrentPageText, new TextAppearanceSpan(mContext, R.style.BreadcrumbText),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- ssb.append('\n');
+ private void updateScreen() {
+ mViewModel.getIconLiveData().setValue(
+ mGroupIcon == null ? null : mGroupIcon.loadDrawable(mActivity));
+ mViewModel.getGroupMessageLiveData().setValue(mGroupMessage.toString());
+ mViewModel.getDetailMessageLiveData().setValue(mDetailMessage);
+ int numButtons = BUTTON_RES_ID_TO_NUM.size();
+ List<Boolean> buttonVisibilityList = Arrays.asList(new Boolean[NEXT_BUTTON]);
+ for (int i = 0; i < numButtons; i++) {
+ int pos = BUTTON_RES_ID_TO_NUM.valueAt(i);
+ buttonVisibilityList.set(pos, mButtonVisibilities[pos] ? Boolean.TRUE : Boolean.FALSE);
}
- if (!TextUtils.isEmpty(mMessage)) {
- ssb.append(mMessage, new TextAppearanceSpan(mContext, R.style.TitleText),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ mViewModel.getButtonVisibilitiesLiveData().setValue(buttonVisibilityList);
+ List<Boolean> locationVisibilityList = Arrays.asList(new Boolean[NEXT_LOCATION_DIALOG]);
+ for (int i = 0; i < locationVisibilityList.size(); i++) {
+ locationVisibilityList.set(i, mLocationVisibilities[i] ? Boolean.TRUE : Boolean.FALSE);
}
-
- if (mDialog != null) {
- mDialog.dismiss();
- mDialog = null;
+ mViewModel.getLocationVisibilitiesLiveData().setValue(locationVisibilityList);
+ if (mLocationVisibilities[DIALOG_WITH_BOTH_LOCATIONS]) {
+ mViewModel.getPreciseLocationCheckedLiveData()
+ .setValue(mLocationVisibilities[FINE_RADIO_BUTTON]);
+ } else if (mLocationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]
+ || mLocationVisibilities[DIALOG_WITH_COARSE_LOCATION_ONLY]) {
+ mViewModel.getPreciseLocationCheckedLiveData().setValue(false);
}
+ }
- if (mShowDoNotAsk) {
- AlertDialog alertDialog = new WearableDialogHelper.DialogBuilder(mContext)
- .setPositiveIcon(R.drawable.confirm_button)
- .setNeutralIcon(R.drawable.cancel_button)
- .setNegativeIcon(R.drawable.deny_button)
- .setTitle(ssb)
- .setIcon(drawable)
- .setPositiveButton(R.string.grant_dialog_button_allow, this)
- .setNeutralButton(R.string.grant_dialog_button_deny, this)
- .setNegativeButton(R.string.grant_dialog_button_deny_dont_ask_again, this)
- .show();
- alertDialog.getButton(DialogInterface.BUTTON_POSITIVE)
- .setId(R.id.permission_allow_button);
- alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL)
- .setId(R.id.permission_deny_button);
- alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE)
- .setId(R.id.permission_deny_dont_ask_again_button);
-
- mDialog = alertDialog;
- } else {
- AcceptDenyDialog acceptDenyDialog = new AcceptDenyDialog(mContext);
- acceptDenyDialog.setTitle(ssb);
- acceptDenyDialog.setIcon(drawable);
- acceptDenyDialog.setPositiveButton(this);
- acceptDenyDialog.setNegativeButton(this);
- acceptDenyDialog.show();
- acceptDenyDialog.getButton(DialogInterface.BUTTON_POSITIVE)
- .setId(R.id.permission_allow_button);
- acceptDenyDialog.getButton(DialogInterface.BUTTON_NEGATIVE)
- .setId(R.id.permission_deny_button);
-
- mDialog = acceptDenyDialog;
+ private void onLocationSwitchChanged(boolean checked) {
+ mViewModel.getPreciseLocationCheckedLiveData().setValue(checked);
+ }
+
+ private void onButtonClicked(int id) {
+ List<String> affectedForegroundPermissions = null;
+ if (mLocationVisibilities[DIALOG_WITH_BOTH_LOCATIONS]) {
+ if (Boolean.TRUE.equals(mViewModel.getPreciseLocationCheckedLiveData().getValue())) {
+ affectedForegroundPermissions = Arrays.asList(
+ ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION);
+ } else {
+ affectedForegroundPermissions = Collections.singletonList(ACCESS_COARSE_LOCATION);
+ }
+ } else if (mLocationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]) {
+ affectedForegroundPermissions = Collections.singletonList(ACCESS_FINE_LOCATION);
+ } else if (mLocationVisibilities[DIALOG_WITH_COARSE_LOCATION_ONLY]) {
+ affectedForegroundPermissions = Collections.singletonList(ACCESS_COARSE_LOCATION);
}
- mDialog.setCancelable(false);
- if (savedInstanceState != null) {
- mDialog.onRestoreInstanceState(savedInstanceState);
+ int button = -1;
+ try {
+ button = BUTTON_RES_ID_TO_NUM.get(id);
+ } catch (NullPointerException e) {
+ // Clicked a view which is not one of the defined buttons
+ return;
+ }
+ // TODO (b/297534305): Research on performAccessibilityAction().
+ switch (button) {
+ case ALLOW_BUTTON:
+ if (mResultListener != null) {
+ mResultListener.onPermissionGrantResult(mGroupName,
+ affectedForegroundPermissions, GRANTED_ALWAYS);
+ }
+ break;
+ case ALLOW_FOREGROUND_BUTTON:
+ if (mResultListener != null) {
+ mResultListener.onPermissionGrantResult(mGroupName,
+ affectedForegroundPermissions, GRANTED_FOREGROUND_ONLY);
+ }
+ break;
+ case ALLOW_ALWAYS_BUTTON:
+ if (mResultListener != null) {
+ mResultListener.onPermissionGrantResult(mGroupName,
+ affectedForegroundPermissions, GRANTED_ALWAYS);
+ }
+ break;
+ case ALLOW_ONE_TIME_BUTTON:
+ if (mResultListener != null) {
+ mResultListener.onPermissionGrantResult(mGroupName,
+ affectedForegroundPermissions, GRANTED_ONE_TIME);
+ }
+ break;
+ case DENY_BUTTON:
+ case NO_UPGRADE_BUTTON:
+ case NO_UPGRADE_OT_BUTTON:
+ if (mResultListener != null) {
+ mResultListener.onPermissionGrantResult(mGroupName,
+ affectedForegroundPermissions, DENIED);
+ }
+ break;
+ case DENY_AND_DONT_ASK_AGAIN_BUTTON:
+ case NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON:
+ case NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON:
+ if (mResultListener != null) {
+ mResultListener.onPermissionGrantResult(mGroupName,
+ affectedForegroundPermissions, DENIED_DO_NOT_ASK_AGAIN);
+ }
+ break;
}
}
@Override
- public void saveInstanceState(Bundle outState) {
- Bundle b = new Bundle();
- b.putByte(SHOW_DO_NOT_ASK, (byte) (mShowDoNotAsk ? 1 : 0));
- b.putString(GROUP_NAME, mGroupName);
- b.putBundle(DIALOG_BUNDLE, mDialog.onSaveInstanceState());
+ public View createView() {
+ WearGrantPermissionsViewModelFactory factory = new WearGrantPermissionsViewModelFactory();
+ mViewModel = factory.create(WearGrantPermissionsViewModel.class);
+ ComposeView root = new ComposeView(mActivity);
+
+ WearGrantPermissionsScreenKt.setContent(root,
+ mViewModel,
+ id -> {
+ onButtonClicked(id);
+ return Unit.INSTANCE;
+ },
+ checked -> {
+ onLocationSwitchChanged(checked);
+ return Unit.INSTANCE;
+ });
+ if (mGroupName != null) {
+ updateScreen();
+ }
- outState.putBundle(WATCH_HANDLER_BUNDLE, b);
+ return root;
}
@Override
- public void loadInstanceState(Bundle savedInstanceState) {
- Bundle b = savedInstanceState.getBundle(WATCH_HANDLER_BUNDLE);
- mShowDoNotAsk = b.getByte(SHOW_DO_NOT_ASK) == 1;
- mGroupName = b.getString(GROUP_NAME);
- showDialog(b.getBundle(DIALOG_BUNDLE));
+ public void updateWindowAttributes(LayoutParams outLayoutParams) {
+ // No-op
}
- @Override
- public void onBackPressed() {
- notifyListener(DENIED);
+ private void setButtonVisibilities(@Nullable boolean[] visibilities) {
+ for (int i = 0; i < mButtonVisibilities.length; i++) {
+ mButtonVisibilities[i] =
+ visibilities != null && i < visibilities.length && visibilities[i];
+ }
}
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- notifyListener(GRANTED_ALWAYS);
- break;
- case DialogInterface.BUTTON_NEUTRAL:
- notifyListener(DENIED);
- break;
- case DialogInterface.BUTTON_NEGATIVE:
- /* In AlertDialog, the negative button is also a don't ask again button. */
- if (dialog instanceof AlertDialog) {
- notifyListener(DENIED_DO_NOT_ASK_AGAIN);
- } else {
- notifyListener(DENIED);
- }
- break;
+ private void setLocationVisibilities(@Nullable boolean[] visibilities) {
+ for (int i = 0; i < mLocationVisibilities.length; i++) {
+ mLocationVisibilities[i] =
+ visibilities != null && i < visibilities.length && visibilities[i];
}
}
- private void notifyListener(@Result int result) {
+ @Override
+ public void onBackPressed() {
if (mResultListener != null) {
- mResultListener.onPermissionGrantResult(mGroupName, result);
+ mResultListener.onPermissionGrantResult(mGroupName, CANCELED);
+ } else {
+ mActivity.finish();
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/ReviewPermissionsWearFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/ReviewPermissionsWearFragment.java
index c31aa5d63..fdeb2ed2a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/ReviewPermissionsWearFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/ReviewPermissionsWearFragment.java
@@ -16,13 +16,21 @@
package com.android.permissioncontroller.permission.ui.wear;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+
import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
import android.os.RemoteCallback;
+import android.os.UserHandle;
import android.text.Html;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
@@ -43,8 +51,8 @@ import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.AppPermissions;
import com.android.permissioncontroller.permission.utils.Utils;
-import java.util.List;
import java.util.ArrayList;
+import java.util.List;
public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
implements Preference.OnPreferenceChangeListener {
@@ -91,11 +99,6 @@ public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
mAppPermissions = new AppPermissions(activity, packageInfo, false,
() -> getActivity().finish());
- if (mAppPermissions.getPermissionGroups().isEmpty()) {
- activity.finish();
- return;
- }
-
boolean reviewRequired = false;
for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
if (group.isReviewRequired()) {
@@ -105,6 +108,7 @@ public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
}
if (!reviewRequired) {
+ confirmPermissionsReview();
activity.finish();
}
}
@@ -137,19 +141,22 @@ public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
final boolean isPackageUpdated = isPackageUpdated();
int permOrder = ORDER_PERM_OFFSET_START;
+ PackageInfo pkg = mAppPermissions.getPackageInfo();
+ ApplicationInfo appInfo = pkg.applicationInfo;
+
for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
if (!Utils.shouldShowPermission(getContext(), group)
|| !Utils.OS_PKG.equals(group.getDeclaringPackage())) {
continue;
}
- final SwitchPreference preference;
+ final PermissionSwitchPreference preference;
Preference cachedPreference = oldNewPermissionsCategory != null
? oldNewPermissionsCategory.findPreference(group.getName()) : null;
- if (cachedPreference instanceof SwitchPreference) {
- preference = (SwitchPreference) cachedPreference;
+ if (cachedPreference instanceof PermissionSwitchPreference) {
+ preference = (PermissionSwitchPreference) cachedPreference;
} else {
- preference = new SwitchPreference(getActivity());
+ preference = new PermissionSwitchPreference(getActivity());
preference.setKey(group.getName());
preference.setTitle(group.getLabel());
@@ -159,7 +166,8 @@ public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
preference.setOnPreferenceChangeListener(this);
}
- if (group.isReviewRequired() ) {
+ if (appInfo.targetSdkVersion < Build.VERSION_CODES.M &&
+ group.isReviewRequired() ) {
preference.setChecked(true);
} else {
preference.setChecked(group.areRuntimePermissionsGranted());
@@ -213,14 +221,16 @@ public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- Log.d(TAG, "onPreferenceChange " + preference.getTitle());
+ Log.d(TAG, "onPreferenceChange " + preference.getTitle());
if (mHasConfirmedRevoke) {
return true;
}
- if (preference instanceof SwitchPreference) {
- SwitchPreference switchPreference = (SwitchPreference) preference;
- if (switchPreference.isChecked()) {
- showWarnRevokeDialog(switchPreference);
+ if (preference instanceof PermissionSwitchPreference) {
+ PermissionSwitchPreference permPreference = (PermissionSwitchPreference)
+ preference;
+ permPreference.setChanged();
+ if (permPreference.isChecked()) {
+ showWarnRevokeDialog(permPreference);
} else {
return true;
}
@@ -257,26 +267,58 @@ public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
}
}
- if (preferenceGroups.isEmpty()) {
- return;
- }
for (PreferenceGroup preferenceGroup: preferenceGroups) {
final int preferenceCount = preferenceGroup.getPreferenceCount();
for (int i = 0; i < preferenceCount; i++) {
Preference preference = preferenceGroup.getPreference(i);
- if (preference instanceof TwoStatePreference) {
- TwoStatePreference twoStatePreference = (TwoStatePreference) preference;
+ if (preference instanceof PermissionSwitchPreference) {
+ PermissionSwitchPreference permPreference = (PermissionSwitchPreference)
+ preference;
String groupName = preference.getKey();
AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName);
- if (twoStatePreference.isChecked()) {
- group.grantRuntimePermissions(true, false);
- } else {
- group.revokeRuntimePermissions(false);
+ if (group.isReviewRequired() || permPreference.wasChanged()) {
+ if (permPreference.isChecked()) {
+ Log.i(TAG, groupName + " permPreference.isChecked()");
+ group.grantRuntimePermissions(true, false);
+ } else {
+ Log.i(TAG, groupName + " !permPreference.isChecked()");
+ group.revokeRuntimePermissions(false);
+ }
+ }
+
+ AppPermissionGroup backgroundGroup = group.getBackgroundPermissions();
+ if (backgroundGroup != null) {
+ // If the preference wasn't toggled we show it as "fully granted"
+ if (backgroundGroup.isReviewRequired() && !permPreference.wasChanged()) {
+ backgroundGroup.grantRuntimePermissions(true, false);
+ }
+ backgroundGroup.unsetReviewRequired();
}
- group.unsetReviewRequired();
}
}
}
+
+ // Some permission might be restricted and hence there is no AppPermissionGroup for it.
+ // Manually unset all review-required flags, regardless of restriction.
+ PackageManager pm = getContext().getPackageManager();
+ PackageInfo pkg = mAppPermissions.getPackageInfo();
+ UserHandle user = UserHandle.getUserHandleForUid(pkg.applicationInfo.uid);
+
+ if (pkg.requestedPermissions == null) {
+ // No flag updating to do
+ return;
+ }
+
+ for (String perm : pkg.requestedPermissions) {
+ try {
+ pm.updatePermissionFlags(perm, pkg.packageName,
+ FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_USER_SET,
+ FLAG_PERMISSION_USER_SET, user);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Cannot unmark " + perm + " requested by " + pkg.packageName
+ + " as review required", e);
+ }
+ }
}
private void addTitlePreferenceToScreen(PreferenceScreen screen) {
@@ -290,7 +332,7 @@ public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
titlePref.setIcon(icon);
// Set message
- String appLabel = mAppPermissions.getAppLabel().toString();
+ String appLabel = Html.escapeHtml(mAppPermissions.getAppLabel().toString());
final int labelTemplateResId = isPackageUpdated()
? R.string.permission_review_title_template_update
: R.string.permission_review_title_template_install;
@@ -379,4 +421,32 @@ public class ReviewPermissionsWearFragment extends PreferenceFragmentCompat
callback.sendResult(result);
}
}
+
+ /**
+ * Extend the {@link SwitchPreference}:
+ * <ul>
+ * <li>Monitor the changed state</li>
+ * </ul>
+ */
+ private static class PermissionSwitchPreference extends SwitchPreference {
+ private boolean mWasChanged = false;
+
+ PermissionSwitchPreference(Context context) {
+ super(context);
+ }
+
+ /**
+ * Mark the permission as changed by the user
+ */
+ void setChanged() {
+ mWasChanged = true;
+ }
+
+ /**
+ * @return {@code true} iff the permission was changed by the user
+ */
+ boolean wasChanged() {
+ return mWasChanged;
+ }
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionFragment.kt
new file mode 100644
index 000000000..3936e54d4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionFragment.kt
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.Manifest
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.StringRes
+import androidx.compose.ui.platform.ComposeView
+import androidx.core.os.BundleCompat
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ALLOW
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ALLOW_ALWAYS
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ALLOW_FOREGROUND
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ASK_EVERY_TIME
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__DENY
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__DENY_FOREGROUND
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__GRANT_FINE_LOCATION
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__REVOKE_FINE_LOCATION
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_DO_NOT_ASK_AGAIN
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_ALWAYS
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_FOREGROUND_ONLY
+import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
+import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ChangeRequest
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ConfirmDialogShowingFragment
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModelFactory
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs
+import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionConfirmDialogViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionConfirmDialogViewModelFactory
+import com.android.permissioncontroller.permission.ui.wear.model.ConfirmDialogArgs
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
+import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
+import com.android.settingslib.RestrictedLockUtils
+
+/**
+ * Show and manage a single permission group for an app.
+ *
+ * <p>Allows the user to control whether the app is granted the permission
+ *
+ * <p>
+ * Based on AppPermissionFragment in handheld code.
+ */
+class WearAppPermissionFragment : Fragment(), ConfirmDialogShowingFragment {
+
+ private lateinit var confirmDialogViewModel: AppPermissionConfirmDialogViewModel
+
+ companion object {
+ private const val GRANT_CATEGORY = "grant_category"
+
+ /**
+ * Create a bundle with the arguments needed by this fragment
+ *
+ * @param packageName The name of the package
+ * @param permName The name of the permission whose group this fragment is for (optional)
+ * @param groupName The name of the permission group (required if permName not specified)
+ * @param userHandle The user of the app permission group
+ * @param caller The name of the fragment we called from
+ * @param sessionId The current session ID
+ * @param grantCategory The grant status of this app permission group. Used to initially set
+ * the button state
+ * @return A bundle with all of the args placed
+ */
+ @JvmStatic
+ fun createArgs(
+ packageName: String?,
+ permName: String?,
+ groupName: String?,
+ userHandle: UserHandle?,
+ caller: String?,
+ sessionId: Long,
+ grantCategory: String?
+ ): Bundle {
+ val arguments = Bundle()
+ arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName)
+ if (groupName == null) {
+ arguments.putString(Intent.EXTRA_PERMISSION_NAME, permName)
+ } else {
+ arguments.putString(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
+ }
+ arguments.putParcelable(Intent.EXTRA_USER, userHandle)
+ arguments.putString(EXTRA_CALLER_NAME, caller)
+ arguments.putLong(EXTRA_SESSION_ID, sessionId)
+ arguments.putString(GRANT_CATEGORY, grantCategory)
+ return arguments
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val activity = requireActivity()
+ val packageName =
+ arguments?.getString(Intent.EXTRA_PACKAGE_NAME)
+ ?: throw RuntimeException("Package name must not be null.")
+ val permGroupName =
+ arguments?.getString(Intent.EXTRA_PERMISSION_GROUP_NAME)
+ ?: arguments?.getString(Intent.EXTRA_PERMISSION_NAME)
+ ?: throw RuntimeException("Permission name must not be null.")
+
+ val isStorageGroup = permGroupName == Manifest.permission_group.STORAGE
+
+ val user =
+ arguments?.let {
+ BundleCompat.getParcelable(it, Intent.EXTRA_USER, UserHandle::class.java)
+ }
+ ?: UserHandle.SYSTEM
+ val permGroupLabel = getPermGroupLabel(activity, permGroupName).toString()
+
+ val sessionId = arguments?.getLong(EXTRA_SESSION_ID) ?: Constants.INVALID_SESSION_ID
+
+ val factory =
+ AppPermissionViewModelFactory(
+ activity.getApplication(),
+ packageName,
+ permGroupName,
+ user,
+ sessionId
+ )
+ val viewModel = ViewModelProvider(this, factory).get(AppPermissionViewModel::class.java)
+ confirmDialogViewModel =
+ ViewModelProvider(this, AppPermissionConfirmDialogViewModelFactory())
+ .get(AppPermissionConfirmDialogViewModel::class.java)
+
+ @Suppress("ktlint:standard:max-line-length")
+ val onLocationSwitchChanged: (Boolean) -> Unit = { checked ->
+ run {
+ val changeRequest =
+ if (checked) {
+ ChangeRequest.GRANT_FINE_LOCATION
+ } else {
+ ChangeRequest.REVOKE_FINE_LOCATION
+ }
+ val buttonClicked =
+ if (checked) {
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__GRANT_FINE_LOCATION
+ } else {
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__REVOKE_FINE_LOCATION
+ }
+ viewModel.requestChange(false, this, this, changeRequest, buttonClicked)
+ }
+ }
+ val onGrantedStateChanged: (ButtonType, Boolean) -> Unit = { buttonType, checked ->
+ run {
+ if (!checked) {
+ return@run
+ }
+ val param = getGrantedStateChangeParam(buttonType)
+ if (!isStorageGroup || !param.requiresCustomStorageBehavior) {
+ viewModel.requestChange(
+ param.setOneTime,
+ this,
+ this,
+ param.request,
+ param.buttonClickAction
+ )
+ } else {
+ showConfirmDialog(
+ ChangeRequest.GRANT_ALL_FILE_ACCESS,
+ R.string.special_file_access_dialog,
+ -1,
+ false
+ )
+ }
+ setResult(param.result, permGroupName)
+ }
+ }
+ val onFooterClicked: (RestrictedLockUtils.EnforcedAdmin) -> Unit = { admin ->
+ run { RestrictedLockUtils.sendShowAdminSupportDetailsIntent(requireContext(), admin) }
+ }
+ val onConfirmDialogOkButtonClick: (ConfirmDialogArgs) -> Unit = { args ->
+ run {
+ if (args.changeRequest == ChangeRequest.GRANT_ALL_FILE_ACCESS) {
+ viewModel.setAllFilesAccess(true)
+ viewModel.requestChange(
+ false,
+ this,
+ this,
+ ChangeRequest.GRANT_BOTH,
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ALLOW
+ )
+ } else {
+ viewModel.onDenyAnyWay(args.changeRequest, args.buttonPressed, args.oneTime)
+ }
+ confirmDialogViewModel.showConfirmDialogLiveData.value = false
+ }
+ }
+ val onConfirmDialogCancelButtonClick: () -> Unit = {
+ confirmDialogViewModel.showConfirmDialogLiveData.value = false
+ }
+ val onAdvancedConfirmDialogOkButtonClick: (AdvancedConfirmDialogArgs) -> Unit = { args ->
+ run {
+ viewModel.requestChange(
+ args.setOneTime!!,
+ this,
+ this,
+ args.changeRequest!!,
+ args.buttonClicked!!
+ )
+ confirmDialogViewModel.showAdvancedConfirmDialogLiveData.value = false
+ }
+ }
+ val onAdvancedConfirmDialogCancelButtonClick: () -> Unit = {
+ confirmDialogViewModel.showAdvancedConfirmDialogLiveData.value = false
+ }
+
+ return ComposeView(activity).apply {
+ setContent {
+ WearPermissionTheme {
+ WearAppPermissionScreen(
+ permGroupLabel,
+ viewModel,
+ confirmDialogViewModel,
+ onLocationSwitchChanged,
+ onGrantedStateChanged,
+ onFooterClicked,
+ onConfirmDialogOkButtonClick,
+ onConfirmDialogCancelButtonClick,
+ onAdvancedConfirmDialogOkButtonClick,
+ onAdvancedConfirmDialogCancelButtonClick
+ )
+ }
+ }
+ }
+ }
+
+ override fun showConfirmDialog(
+ changeRequest: ChangeRequest,
+ @StringRes messageId: Int,
+ buttonPressed: Int,
+ oneTime: Boolean
+ ) {
+ confirmDialogViewModel.confirmDialogArgs =
+ ConfirmDialogArgs(
+ messageId = messageId,
+ changeRequest = changeRequest,
+ buttonPressed = buttonPressed,
+ oneTime = oneTime
+ )
+ confirmDialogViewModel.showConfirmDialogLiveData.value = true
+ }
+
+ override fun showAdvancedConfirmDialog(args: AdvancedConfirmDialogArgs) {
+ confirmDialogViewModel.advancedConfirmDialogArgs = args
+ confirmDialogViewModel.showAdvancedConfirmDialogLiveData.value = true
+ }
+
+ private fun setResult(@GrantPermissionsViewHandler.Result result: Int, permGroupName: String) {
+ val intent: Intent =
+ Intent()
+ .putExtra(
+ ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED,
+ permGroupName
+ )
+ .putExtra(ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT, result)
+ requireActivity().setResult(Activity.RESULT_OK, intent)
+ }
+
+ fun getGrantedStateChangeParam(buttonType: ButtonType) =
+ when (buttonType) {
+ ButtonType.ALLOW ->
+ GrantedStateChangeParam(
+ false,
+ ChangeRequest.GRANT_FOREGROUND,
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ALLOW,
+ GRANTED_ALWAYS,
+ false
+ )
+ ButtonType.ALLOW_ALWAYS ->
+ GrantedStateChangeParam(
+ false,
+ ChangeRequest.GRANT_BOTH,
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ALLOW_ALWAYS,
+ GRANTED_ALWAYS,
+ true
+ )
+ ButtonType.ALLOW_FOREGROUND ->
+ GrantedStateChangeParam(
+ false,
+ ChangeRequest.GRANT_FOREGROUND_ONLY,
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ALLOW_FOREGROUND,
+ GRANTED_FOREGROUND_ONLY,
+ true
+ )
+ ButtonType.ASK ->
+ GrantedStateChangeParam(
+ true,
+ ChangeRequest.REVOKE_BOTH,
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ASK_EVERY_TIME,
+ DENIED,
+ false
+ )
+ ButtonType.DENY ->
+ GrantedStateChangeParam(
+ false,
+ ChangeRequest.REVOKE_BOTH,
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__DENY,
+ DENIED_DO_NOT_ASK_AGAIN,
+ false
+ )
+ ButtonType.DENY_FOREGROUND ->
+ GrantedStateChangeParam(
+ false,
+ ChangeRequest.REVOKE_FOREGROUND,
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__DENY_FOREGROUND,
+ DENIED_DO_NOT_ASK_AGAIN,
+ false
+ )
+ else -> throw RuntimeException("Wrong button type: $buttonType")
+ }
+}
+
+data class GrantedStateChangeParam(
+ val setOneTime: Boolean,
+ val request: ChangeRequest,
+ val buttonClickAction: Int,
+ val result: Int,
+ val requiresCustomStorageBehavior: Boolean
+)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsFragment.kt
new file mode 100644
index 000000000..9b960dfb5
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsFragment.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.app.Activity
+import android.content.Intent
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.os.UserHandle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.annotation.RequiresApi
+import androidx.compose.ui.platform.ComposeView
+import androidx.core.os.BundleCompat
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.model.AppPermissions
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
+import com.android.permissioncontroller.permission.model.v31.PermissionUsages
+import com.android.permissioncontroller.permission.model.v31.PermissionUsages.PermissionsUsagesChangeCallback
+import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel
+import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModelFactory
+import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionGroupsRevokeDialogViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionGroupsRevokeDialogViewModelFactory
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModelFactory
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
+import com.android.permissioncontroller.permission.utils.KotlinUtils.is7DayToggleEnabled
+import java.time.Instant
+import java.util.concurrent.TimeUnit
+
+class WearAppPermissionGroupsFragment : Fragment(), PermissionsUsagesChangeCallback {
+ private lateinit var permissionUsages: PermissionUsages
+ private lateinit var wearViewModel: WearAppPermissionUsagesViewModel
+ private lateinit var helper: WearAppPermissionGroupsHelper
+
+ // Suppress warning of the deprecated class [android.app.LoaderManager] since other form factors
+ // are using the class to load PermissionUsages.
+ @Suppress("DEPRECATION")
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val packageName = arguments?.getString(Intent.EXTRA_PACKAGE_NAME) ?: ""
+ val user =
+ arguments?.let {
+ BundleCompat.getParcelable(it, Intent.EXTRA_USER, UserHandle::class.java)!!
+ }
+ ?: UserHandle.SYSTEM
+
+ val activity: Activity = requireActivity()
+ val packageManager = activity.packageManager
+
+ val packageInfo: PackageInfo? =
+ try {
+ packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e)
+ null
+ }
+
+ if (packageInfo == null) {
+ Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show()
+ activity.finish()
+ return null
+ }
+ val sessionId = arguments?.getLong(EXTRA_SESSION_ID, 0) ?: 0
+ val appPermissions = AppPermissions(activity, packageInfo, true, { activity.finish() })
+ val factory = AppPermissionGroupsViewModelFactory(packageName, user, sessionId)
+ val viewModel =
+ ViewModelProvider(this, factory).get(AppPermissionGroupsViewModel::class.java)
+ wearViewModel =
+ ViewModelProvider(this, WearAppPermissionUsagesViewModelFactory())
+ .get(WearAppPermissionUsagesViewModel::class.java)
+ val revokeDialogViewModel =
+ ViewModelProvider(this, AppPermissionGroupsRevokeDialogViewModelFactory())
+ .get(AppPermissionGroupsRevokeDialogViewModel::class.java)
+
+ val context = requireContext()
+
+ // If the build type is below S, the app ops for permission usage can't be found. Thus, we
+ // shouldn't load permission usages, for them.
+ if (SdkLevel.isAtLeastS()) {
+ permissionUsages = PermissionUsages(context)
+ val aggregateDataFilterBeginDays =
+ (if (is7DayToggleEnabled())
+ AppPermissionGroupsViewModel.AGGREGATE_DATA_FILTER_BEGIN_DAYS_7
+ else AppPermissionGroupsViewModel.AGGREGATE_DATA_FILTER_BEGIN_DAYS_1)
+ .toLong()
+
+ val filterTimeBeginMillis =
+ Math.max(
+ System.currentTimeMillis() -
+ TimeUnit.DAYS.toMillis(aggregateDataFilterBeginDays),
+ Instant.EPOCH.toEpochMilli()
+ )
+ permissionUsages.load(
+ null,
+ null,
+ filterTimeBeginMillis,
+ Long.MAX_VALUE,
+ PermissionUsages.USAGE_FLAG_LAST,
+ requireActivity().getLoaderManager(),
+ false,
+ false,
+ this,
+ false
+ )
+ }
+ helper =
+ WearAppPermissionGroupsHelper(
+ context = context,
+ fragment = this,
+ user = user,
+ packageName = packageName,
+ sessionId = sessionId,
+ appPermissions = appPermissions,
+ viewModel = viewModel,
+ wearViewModel = wearViewModel,
+ revokeDialogViewModel = revokeDialogViewModel
+ )
+
+ return ComposeView(activity).apply {
+ setContent { WearPermissionTheme { WearAppPermissionGroupsScreen(helper) } }
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ helper.logAndClearToggledGroups()
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ override fun onPermissionUsagesChanged() {
+ if (permissionUsages.usages.isEmpty()) {
+ return
+ }
+ if (getContext() == null) {
+ // Async result has come in after our context is gone.
+ return
+ }
+ wearViewModel.appPermissionUsages.value =
+ ArrayList<AppPermissionUsage>(permissionUsages.usages)
+ }
+
+ companion object {
+ const val LOG_TAG = "WearAppPermissionGroups"
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt
new file mode 100644
index 000000000..94f0b0d07
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsHelper.kt
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.PermissionInfo
+import android.os.Build
+import android.os.UserHandle
+import android.util.ArraySet
+import android.util.Log
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
+import com.android.permission.flags.Flags
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.hibernation.isHibernationEnabled
+import com.android.permissioncontroller.permission.model.AppPermissionGroup
+import com.android.permissioncontroller.permission.model.AppPermissions
+import com.android.permissioncontroller.permission.model.Permission
+import com.android.permissioncontroller.permission.model.livedatatypes.HibernationSettingState
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
+import com.android.permissioncontroller.permission.ui.Category
+import com.android.permissioncontroller.permission.ui.LocationProviderInterceptDialog
+import com.android.permissioncontroller.permission.ui.handheld.AppPermissionFragment
+import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel
+import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel.GroupUiInfo
+import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel.PermSubtitle
+import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionGroupsRevokeDialogViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.RevokeDialogArgs
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModel
+import com.android.permissioncontroller.permission.utils.ArrayUtils
+import com.android.permissioncontroller.permission.utils.LocationUtils
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.legacy.LegacySafetyNetLogger
+import com.android.permissioncontroller.permission.utils.navigateSafe
+
+class WearAppPermissionGroupsHelper(
+ val context: Context,
+ val fragment: Fragment,
+ val user: UserHandle,
+ val packageName: String,
+ val sessionId: Long,
+ private val appPermissions: AppPermissions,
+ val viewModel: AppPermissionGroupsViewModel,
+ val wearViewModel: WearAppPermissionUsagesViewModel,
+ val revokeDialogViewModel: AppPermissionGroupsRevokeDialogViewModel,
+ private val toggledGroups: ArraySet<AppPermissionGroup> = ArraySet()
+) {
+ fun getPermissionGroupChipParams(
+ appPermissionUsages: List<AppPermissionUsage>
+ ): List<PermissionGroupChipParam> {
+ if (DEBUG) {
+ Log.d(TAG, "getPermissionGroupChipParams() called")
+ }
+ val groupUsageLastAccessTime: MutableMap<String, Long> = HashMap()
+ viewModel.extractGroupUsageLastAccessTime(
+ groupUsageLastAccessTime,
+ appPermissionUsages,
+ packageName
+ )
+ val groupUiInfos = viewModel.packagePermGroupsLiveData.value
+ val groups: List<AppPermissionGroup> = appPermissions.permissionGroups
+
+ val grantedTypes: MutableMap<String, Category> = HashMap()
+ val bookKeeping: MutableMap<String, GroupUiInfo> = HashMap()
+ if (groupUiInfos != null) {
+ for (category in groupUiInfos.keys) {
+ val groupInfoList: List<GroupUiInfo> = groupUiInfos[category] ?: emptyList()
+ for (groupInfo in groupInfoList) {
+ bookKeeping[groupInfo.groupName] = groupInfo
+ grantedTypes[groupInfo.groupName] = category
+ }
+ }
+ }
+
+ val list: MutableList<PermissionGroupChipParam> = ArrayList()
+
+ groups
+ .filter { Utils.shouldShowPermission(context, it) }
+ .partition { it.declaringPackage == Utils.OS_PKG }
+ .let { it.first.plus(it.second) }
+ .forEach { group ->
+ if (Utils.areGroupPermissionsIndividuallyControlled(context, group.name)) {
+ // If permission is controlled individually, we show all requested permission
+ // inside this group.
+ for (perm in getPermissionInfosFromGroup(group)) {
+ list.add(
+ PermissionGroupChipParam(
+ group = group,
+ perm = perm,
+ label = perm.loadLabel(context.packageManager).toString(),
+ checked = group.areRuntimePermissionsGranted(arrayOf(perm.name)),
+ onCheckedChanged = { checked ->
+ run { onPermissionGrantedStateChanged(group, perm, checked) }
+ }
+ )
+ )
+ }
+ } else {
+ val category = grantedTypes[group.name]
+ if (category != null) {
+ list.add(
+ PermissionGroupChipParam(
+ group = group,
+ label = group.label.toString(),
+ summary =
+ bookKeeping[group.name]?.let {
+ getSummary(
+ category,
+ it,
+ groupUsageLastAccessTime[it.groupName]
+ )
+ },
+ onClick = { onPermissionGroupClicked(group, category.categoryName) }
+ )
+ )
+ }
+ }
+ }
+ return list
+ }
+
+ private fun getSummary(
+ category: Category?,
+ groupUiInfo: GroupUiInfo,
+ lastAccessTime: Long?
+ ): String {
+ val grantSummary =
+ getGrantSummary(category, groupUiInfo)?.let { context.getString(it) } ?: ""
+ val summary = StringBuilder(grantSummary)
+ if (Flags.wearPrivacyDashboardEnabled()) {
+ WearUtils.getPreferenceSummary(context, lastAccessTime).let {
+ if (it.isNotEmpty()) {
+ summary.append(System.lineSeparator()).append(it)
+ }
+ }
+ }
+ return summary.toString()
+ }
+
+ private fun getGrantSummary(category: Category?, groupUiInfo: GroupUiInfo): Int? {
+ val subtitle = groupUiInfo.subtitle
+ if (category != null) {
+ when (category) {
+ Category.ALLOWED ->
+ return if (subtitle == PermSubtitle.BACKGROUND) {
+ R.string.allowed_always_header
+ } else {
+ R.string.allowed_header
+ }
+ Category.ASK -> return R.string.ask_header
+ Category.DENIED -> return R.string.denied_header
+ else -> {
+ /* Fallback though */
+ }
+ }
+ }
+ return when (subtitle) {
+ PermSubtitle.FOREGROUND_ONLY -> R.string.permission_subtitle_only_in_foreground
+ PermSubtitle.MEDIA_ONLY -> R.string.permission_subtitle_media_only
+ PermSubtitle.ALL_FILES -> R.string.permission_subtitle_all_files
+ else -> null
+ }
+ }
+
+ private fun getPermissionInfosFromGroup(group: AppPermissionGroup): List<PermissionInfo> =
+ group.permissions
+ .map {
+ it?.let {
+ try {
+ context.packageManager.getPermissionInfo(it.name, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "No permission:" + it.name)
+ null
+ }
+ }
+ }
+ .filterNotNull()
+ .toList()
+
+ private fun onPermissionGrantedStateChanged(
+ group: AppPermissionGroup,
+ perm: PermissionInfo,
+ checked: Boolean
+ ) {
+ if (checked) {
+ group.grantRuntimePermissions(true, false, arrayOf(perm.name))
+
+ if (
+ Utils.areGroupPermissionsIndividuallyControlled(context, group.name) &&
+ group.doesSupportRuntimePermissions()
+ ) {
+ // We are granting a permission from a group but since this is an
+ // individual permission control other permissions in the group may
+ // be revoked, hence we need to mark them user fixed to prevent the
+ // app from requesting a non-granted permission and it being granted
+ // because another permission in the group is granted. This applies
+ // only to apps that support runtime permissions.
+ var revokedPermissionsToFix: Array<String?>? = null
+ val permissionCount = group.permissions.size
+ for (i in 0 until permissionCount) {
+ val current = group.permissions[i]
+ if (!current.isGranted && !current.isUserFixed) {
+ revokedPermissionsToFix =
+ ArrayUtils.appendString(revokedPermissionsToFix, current.name)
+ }
+ }
+ if (revokedPermissionsToFix != null) {
+ // If some permissions were not granted then they should be fixed.
+ group.revokeRuntimePermissions(true, revokedPermissionsToFix)
+ }
+ }
+ } else {
+ val appPerm: Permission = getPermissionFromGroup(group, perm.name) ?: return
+
+ val grantedByDefault = appPerm.isGrantedByDefault
+ if (
+ grantedByDefault ||
+ (!group.doesSupportRuntimePermissions() &&
+ !revokeDialogViewModel.hasConfirmedRevoke)
+ ) {
+ showRevocationWarningDialog(
+ messageId =
+ if (grantedByDefault) {
+ R.string.system_warning
+ } else {
+ R.string.old_sdk_deny_warning
+ },
+ onOkButtonClick = {
+ revokePermissionInGroup(group, perm.name)
+ if (!appPerm.isGrantedByDefault) {
+ revokeDialogViewModel.hasConfirmedRevoke = true
+ }
+ revokeDialogViewModel.dismissDialog()
+ }
+ )
+ } else {
+ revokePermissionInGroup(group, perm.name)
+ }
+ }
+ }
+
+ private fun getPermissionFromGroup(group: AppPermissionGroup, permName: String): Permission? {
+ return group.permissions.find { it.name == permName }
+ ?: let {
+ if ("user" == Build.TYPE) {
+ Log.e(
+ TAG,
+ "The impossible happens, permission $permName is not in group $group.name."
+ )
+ null
+ } else {
+ // This is impossible, throw a fatal error in non-user build.
+ throw IllegalArgumentException(
+ "Permission $permName is not in group $group.name%s"
+ )
+ }
+ }
+ }
+
+ private fun revokePermissionInGroup(group: AppPermissionGroup, permName: String) {
+ group.revokeRuntimePermissions(true, arrayOf(permName))
+
+ if (
+ Utils.areGroupPermissionsIndividuallyControlled(context, group.name) &&
+ group.doesSupportRuntimePermissions() &&
+ !group.areRuntimePermissionsGranted()
+ ) {
+ // If we just revoked the last permission we need to clear
+ // the user fixed state as now the app should be able to
+ // request them at runtime if supported.
+ group.revokeRuntimePermissions(false)
+ }
+ }
+
+ private fun showRevocationWarningDialog(
+ messageId: Int,
+ onOkButtonClick: () -> Unit,
+ onCancelButtonClick: () -> Unit = { revokeDialogViewModel.dismissDialog() }
+ ) {
+ revokeDialogViewModel.revokeDialogArgs =
+ RevokeDialogArgs(
+ messageId = messageId,
+ onOkButtonClick = onOkButtonClick,
+ onCancelButtonClick = onCancelButtonClick
+ )
+ revokeDialogViewModel.showDialogLiveData.value = true
+ }
+
+ private fun onPermissionGroupClicked(group: AppPermissionGroup, grantCategory: String) {
+ val permGroupName = group.name
+ val packageName = group.app?.packageName ?: ""
+ val caller = WearAppPermissionGroupsFragment::class.java.name
+
+ addToggledGroup(group)
+
+ if (LocationUtils.isLocationGroupAndProvider(context, permGroupName, packageName)) {
+ val intent = Intent(context, LocationProviderInterceptDialog::class.java)
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
+ context.startActivityAsUser(intent, user)
+ } else if (
+ LocationUtils.isLocationGroupAndControllerExtraPackage(
+ context,
+ permGroupName,
+ packageName
+ )
+ ) {
+ // Redirect to location controller extra package settings.
+ LocationUtils.startLocationControllerExtraPackageSettings(context, user)
+ } else {
+ val args =
+ AppPermissionFragment.createArgs(
+ packageName,
+ null,
+ permGroupName,
+ user,
+ caller,
+ sessionId,
+ grantCategory
+ )
+ fragment.findNavController().navigateSafe(R.id.perm_groups_to_app, args)
+ }
+ }
+
+ private fun addToggledGroup(group: AppPermissionGroup) {
+ toggledGroups.add(group)
+ }
+
+ fun logAndClearToggledGroups() {
+ LegacySafetyNetLogger.logPermissionsToggled(toggledGroups)
+ toggledGroups.clear()
+ }
+
+ fun getAutoRevokeChipParam(state: HibernationSettingState?): AutoRevokeChipParam? =
+ state?.let {
+ AutoRevokeChipParam(
+ labelRes =
+ if (isHibernationEnabled()) {
+ R.string.unused_apps_label_v2
+ } else {
+ R.string.auto_revoke_label
+ },
+ visible = it.revocableGroupNames.isNotEmpty(),
+ checked = it.isEligibleForHibernation(),
+ onCheckedChanged = { checked ->
+ run {
+ viewModel.setAutoRevoke(checked)
+ Log.w(TAG, "setAutoRevoke $checked")
+ }
+ }
+ )
+ }
+
+ companion object {
+ const val DEBUG = false
+ const val TAG = WearAppPermissionGroupsFragment.LOG_TAG
+ }
+}
+
+data class PermissionGroupChipParam(
+ val group: AppPermissionGroup,
+ val perm: PermissionInfo? = null,
+ val label: String,
+ val summary: String? = null,
+ val enabled: Boolean = true,
+ val checked: Boolean? = null,
+ val onClick: () -> Unit = {},
+ val onCheckedChanged: (Boolean) -> Unit = {}
+)
+
+data class AutoRevokeChipParam(
+ val labelRes: Int,
+ val visible: Boolean,
+ val checked: Boolean = false,
+ val onCheckedChanged: (Boolean) -> Unit
+)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt
new file mode 100644
index 000000000..bc840bac9
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
+import com.android.permissioncontroller.permission.ui.wear.model.RevokeDialogArgs
+
+@Composable
+fun WearAppPermissionGroupsScreen(helper: WearAppPermissionGroupsHelper) {
+ val packagePermGroups = helper.viewModel.packagePermGroupsLiveData.observeAsState(emptyMap())
+ val autoRevoke = helper.viewModel.autoRevokeLiveData.observeAsState(null)
+ val appPermissionUsages = helper.wearViewModel.appPermissionUsages.observeAsState(emptyList())
+ val showRevokeDialog = helper.revokeDialogViewModel.showDialogLiveData.observeAsState(false)
+ var isLoading by remember { mutableStateOf(true) }
+
+ Box {
+ WearAppPermissionGroupsContent(
+ isLoading,
+ helper.getPermissionGroupChipParams(appPermissionUsages.value),
+ helper.getAutoRevokeChipParam(autoRevoke.value)
+ )
+ RevokeDialog(
+ showDialog = showRevokeDialog.value,
+ args = helper.revokeDialogViewModel.revokeDialogArgs
+ )
+ }
+
+ if (isLoading && packagePermGroups.value.isNotEmpty()) {
+ isLoading = false
+ }
+}
+
+@Composable
+internal fun WearAppPermissionGroupsContent(
+ isLoading: Boolean,
+ permissionGroupChipParams: List<PermissionGroupChipParam>,
+ autoRevokeChipParam: AutoRevokeChipParam?
+) {
+ ScrollableScreen(title = stringResource(R.string.app_permissions), isLoading = isLoading) {
+ if (permissionGroupChipParams.isEmpty()) {
+ item { Chip(label = stringResource(R.string.no_permissions), onClick = {}) }
+ } else {
+ for (info in permissionGroupChipParams) {
+ item {
+ if (info.checked != null) {
+ ToggleChip(
+ checked = info.checked,
+ label = info.label,
+ enabled = info.enabled,
+ toggleControl = ToggleChipToggleControl.Switch,
+ onCheckedChanged = info.onCheckedChanged
+ )
+ } else {
+ Chip(
+ label = info.label,
+ labelMaxLines = Integer.MAX_VALUE,
+ secondaryLabel = info.summary?.let { info.summary },
+ secondaryLabelMaxLines = Integer.MAX_VALUE,
+ enabled = info.enabled,
+ onClick = info.onClick
+ )
+ }
+ }
+ }
+ autoRevokeChipParam?.let {
+ if (it.visible) {
+ item {
+ ToggleChip(
+ checked = it.checked,
+ label = stringResource(it.labelRes),
+ labelMaxLine = 3,
+ toggleControl = ToggleChipToggleControl.Switch,
+ onCheckedChanged = it.onCheckedChanged
+ )
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+internal fun RevokeDialog(showDialog: Boolean, args: RevokeDialogArgs?) {
+ args?.let {
+ AlertDialog(
+ showDialog = showDialog,
+ message = stringResource(it.messageId),
+ onOKButtonClick = it.onOkButtonClick,
+ onCancelButtonClick = it.onCancelButtonClick,
+ scalingLazyListState = rememberScalingLazyListState()
+ )
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt
new file mode 100644
index 000000000..bec633fe7
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonState
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs
+import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
+import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionConfirmDialogViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.ConfirmDialogArgs
+import com.android.settingslib.RestrictedLockUtils
+
+@Composable
+fun WearAppPermissionScreen(
+ title: String,
+ viewModel: AppPermissionViewModel,
+ confirmDialogViewModel: AppPermissionConfirmDialogViewModel,
+ onLocationSwitchChanged: (Boolean) -> Unit,
+ onGrantedStateChanged: (ButtonType, Boolean) -> Unit,
+ onFooterClicked: (RestrictedLockUtils.EnforcedAdmin) -> Unit,
+ onConfirmDialogOkButtonClick: (ConfirmDialogArgs) -> Unit,
+ onConfirmDialogCancelButtonClick: () -> Unit,
+ onAdvancedConfirmDialogOkButtonClick: (AdvancedConfirmDialogArgs) -> Unit,
+ onAdvancedConfirmDialogCancelButtonClick: () -> Unit
+) {
+ val buttonState = viewModel.buttonStateLiveData.observeAsState(emptyMap())
+ val detailResIds = viewModel.detailResIdLiveData.observeAsState(null)
+ val admin = viewModel.showAdminSupportLiveData.observeAsState(null)
+ var isLoading by remember { mutableStateOf(true) }
+ val showConfirmDialog = confirmDialogViewModel.showConfirmDialogLiveData.observeAsState(false)
+ val showAdvancedConfirmDialog =
+ confirmDialogViewModel.showAdvancedConfirmDialogLiveData.observeAsState(false)
+
+ Box {
+ WearAppPermissionContent(
+ title,
+ buttonState.value,
+ detailResIds.value,
+ admin.value,
+ isLoading,
+ onLocationSwitchChanged,
+ onGrantedStateChanged,
+ onFooterClicked,
+ )
+ ConfirmDialog(
+ showDialog = showConfirmDialog.value,
+ args = confirmDialogViewModel.confirmDialogArgs,
+ onOkButtonClick = onConfirmDialogOkButtonClick,
+ onCancelButtonClick = onConfirmDialogCancelButtonClick
+ )
+ AdvancedConfirmDialog(
+ showDialog = showAdvancedConfirmDialog.value,
+ args = confirmDialogViewModel.advancedConfirmDialogArgs,
+ onOkButtonClick = onAdvancedConfirmDialogOkButtonClick,
+ onCancelButtonClick = onAdvancedConfirmDialogCancelButtonClick
+ )
+ }
+ if (isLoading && buttonState.value.isNotEmpty()) {
+ isLoading = false
+ }
+}
+
+@Composable
+internal fun WearAppPermissionContent(
+ title: String,
+ buttonState: Map<ButtonType, ButtonState>,
+ detailResIds: Pair<Int, Int?>?,
+ admin: RestrictedLockUtils.EnforcedAdmin?,
+ isLoading: Boolean,
+ onLocationSwitchChanged: (Boolean) -> Unit,
+ onGrantedStateChanged: (ButtonType, Boolean) -> Unit,
+ onFooterClicked: (RestrictedLockUtils.EnforcedAdmin) -> Unit
+) {
+ ScrollableScreen(title = title, isLoading = isLoading) {
+ buttonState[ButtonType.LOCATION_ACCURACY]?.let {
+ if (it.isShown) {
+ item {
+ ToggleChip(
+ checked = it.isChecked,
+ enabled = it.isEnabled,
+ label = stringResource(R.string.app_permission_location_accuracy),
+ toggleControl = ToggleChipToggleControl.Switch,
+ onCheckedChanged = onLocationSwitchChanged,
+ labelMaxLine = Integer.MAX_VALUE
+ )
+ }
+ }
+ }
+ for (buttonType in buttonTypeOrder) {
+ buttonState[buttonType]?.let {
+ if (it.isShown) {
+ item {
+ ToggleChip(
+ checked = it.isChecked,
+ enabled = it.isEnabled,
+ label = labelsByButton(buttonType),
+ toggleControl = ToggleChipToggleControl.Radio,
+ onCheckedChanged = { checked ->
+ onGrantedStateChanged(buttonType, checked)
+ },
+ labelMaxLine = Integer.MAX_VALUE
+ )
+ }
+ }
+ }
+ }
+ detailResIds?.let {
+ item {
+ ListFooter(
+ description = stringResource(detailResIds.first),
+ iconRes = R.drawable.ic_info,
+ onClick =
+ if (admin != null) {
+ { onFooterClicked(admin) }
+ } else {
+ null
+ }
+ )
+ }
+ }
+ }
+}
+
+internal val buttonTypeOrder =
+ listOf(
+ ButtonType.ALLOW,
+ ButtonType.ALLOW_ALWAYS,
+ ButtonType.ALLOW_FOREGROUND,
+ ButtonType.ASK_ONCE,
+ ButtonType.ASK,
+ ButtonType.DENY,
+ ButtonType.DENY_FOREGROUND
+ )
+
+@Composable
+internal fun labelsByButton(buttonType: ButtonType) =
+ when (buttonType) {
+ ButtonType.ALLOW -> stringResource(R.string.app_permission_button_allow)
+ ButtonType.ALLOW_ALWAYS -> stringResource(R.string.app_permission_button_allow_always)
+ ButtonType.ALLOW_FOREGROUND ->
+ stringResource(R.string.app_permission_button_allow_foreground)
+ ButtonType.ASK_ONCE -> stringResource(R.string.app_permission_button_ask)
+ ButtonType.ASK -> stringResource(R.string.app_permission_button_ask)
+ ButtonType.DENY -> stringResource(R.string.app_permission_button_deny)
+ ButtonType.DENY_FOREGROUND -> stringResource(R.string.app_permission_button_deny)
+ else -> ""
+ }
+
+@Composable
+internal fun ConfirmDialog(
+ showDialog: Boolean,
+ args: ConfirmDialogArgs?,
+ onOkButtonClick: (ConfirmDialogArgs) -> Unit,
+ onCancelButtonClick: () -> Unit
+) {
+ args?.let {
+ AlertDialog(
+ showDialog = showDialog,
+ message = stringResource(it.messageId),
+ onOKButtonClick = { onOkButtonClick(it) },
+ onCancelButtonClick = onCancelButtonClick,
+ scalingLazyListState = rememberScalingLazyListState()
+ )
+ }
+}
+
+@Composable
+internal fun AdvancedConfirmDialog(
+ showDialog: Boolean,
+ args: AdvancedConfirmDialogArgs?,
+ onOkButtonClick: (AdvancedConfirmDialogArgs) -> Unit,
+ onCancelButtonClick: () -> Unit
+) {
+ args?.let {
+ AlertDialog(
+ showDialog = showDialog,
+ title =
+ if (it.titleId != 0) {
+ stringResource(it.titleId)
+ } else {
+ ""
+ },
+ iconRes = it.iconId,
+ message = stringResource(it.messageId),
+ okButtonContentDescription = stringResource(it.positiveButtonTextId),
+ cancelButtonContentDescription = stringResource(it.negativeButtonTextId),
+ onOKButtonClick = { onOkButtonClick(it) },
+ onCancelButtonClick = onCancelButtonClick,
+ scalingLazyListState = rememberScalingLazyListState()
+ )
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt
new file mode 100644
index 000000000..950353f52
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.res.stringResource
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ALWAYS_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_FOREGROUND_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ONE_TIME_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_AND_DONT_ASK_AGAIN_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_BOTH_LOCATIONS
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_FINE_LOCATION_ONLY
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.LOCATION_ACCURACY_LAYOUT
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_BUTTON
+import com.android.permissioncontroller.permission.ui.wear.GrantPermissionsWearViewHandler.BUTTON_RES_ID_TO_NUM
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
+import com.android.permissioncontroller.permission.ui.wear.model.WearGrantPermissionsViewModel
+
+@Composable
+fun WearGrantPermissionsScreen(
+ viewModel: WearGrantPermissionsViewModel,
+ onButtonClicked: (Int) -> Unit,
+ onLocationSwitchChanged: (Boolean) -> Unit
+) {
+ val groupMessage = viewModel.groupMessageLiveData.observeAsState("")
+ val icon = viewModel.iconLiveData.observeAsState(null)
+ val detailMessage = viewModel.detailMessageLiveData.observeAsState(null)
+ val locationVisibilities = viewModel.locationVisibilitiesLiveData.observeAsState(emptyList())
+ val preciseLocationChecked = viewModel.preciseLocationCheckedLiveData.observeAsState(false)
+ val buttonVisibilities = viewModel.buttonVisibilitiesLiveData.observeAsState(emptyList())
+
+ ScrollableScreen(
+ showTimeText = false,
+ image = icon.value,
+ title = groupMessage.value,
+ subtitle = detailMessage.value,
+ titleTestTag = "com.android.permissioncontroller:id/permission_message",
+ subtitleTestTag = "com.android.permissioncontroller:id/detail_message",
+ ) {
+ if (
+ locationVisibilities.value.getOrElse(LOCATION_ACCURACY_LAYOUT) { false } &&
+ locationVisibilities.value.getOrElse(DIALOG_WITH_BOTH_LOCATIONS) { false }
+ ) {
+ item {
+ ToggleChip(
+ checked = preciseLocationChecked.value,
+ onCheckedChanged = { onLocationSwitchChanged(it) },
+ label = stringResource(R.string.app_permission_location_accuracy),
+ toggleControl = ToggleChipToggleControl.Switch,
+ modifier = Modifier.fillMaxWidth(),
+ labelMaxLine = Integer.MAX_VALUE
+ )
+ }
+ }
+ for (i in 0 until BUTTON_RES_ID_TO_NUM.size()) {
+ val pos: Int = BUTTON_RES_ID_TO_NUM.valueAt(i)
+ if (buttonVisibilities.value.size <= pos) {
+ // initial value of buttonVisibilities is empty
+ break
+ }
+ if (buttonVisibilities.value[pos]) {
+ item {
+ Chip(
+ label =
+ getPrimaryText(
+ pos,
+ locationVisibilities.value,
+ labelsByButton(BUTTON_RES_ID_TO_NUM.valueAt(i))
+ ),
+ onClick = { onButtonClicked(BUTTON_RES_ID_TO_NUM.keyAt(i)) },
+ modifier = Modifier.fillMaxWidth(),
+ labelMaxLines = Integer.MAX_VALUE
+ )
+ }
+ }
+ }
+ }
+}
+
+fun setContent(
+ composeView: ComposeView,
+ viewModel: WearGrantPermissionsViewModel,
+ onButtonClicked: (Int) -> Unit,
+ onLocationSwitchChanged: (Boolean) -> Unit
+) {
+ composeView.setContent {
+ WearGrantPermissionsScreen(viewModel, onButtonClicked, onLocationSwitchChanged)
+ }
+}
+
+@Composable
+internal fun labelsByButton(grantPermissionsButtonType: Int) =
+ when (grantPermissionsButtonType) {
+ ALLOW_BUTTON -> stringResource(R.string.grant_dialog_button_allow)
+ ALLOW_ALWAYS_BUTTON -> stringResource(R.string.grant_dialog_button_allow_always)
+ ALLOW_FOREGROUND_BUTTON -> stringResource(R.string.grant_dialog_button_allow_foreground)
+ DENY_BUTTON -> stringResource(R.string.grant_dialog_button_deny)
+ DENY_AND_DONT_ASK_AGAIN_BUTTON -> stringResource(R.string.grant_dialog_button_deny)
+ ALLOW_ONE_TIME_BUTTON -> stringResource(R.string.grant_dialog_button_allow_one_time)
+ NO_UPGRADE_BUTTON -> stringResource(R.string.grant_dialog_button_no_upgrade)
+ NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON ->
+ stringResource(R.string.grant_dialog_button_no_upgrade)
+ NO_UPGRADE_OT_BUTTON -> stringResource(R.string.grant_dialog_button_no_upgrade_one_time)
+ NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON ->
+ stringResource(R.string.grant_dialog_button_no_upgrade_one_time)
+ else -> ""
+ }
+
+@Composable
+private fun getPrimaryText(pos: Int, locationVisibilities: List<Boolean>, default: String): String {
+ val isPreciseLocation: Boolean =
+ locationVisibilities.getOrElse(LOCATION_ACCURACY_LAYOUT) { false } &&
+ locationVisibilities.getOrElse(DIALOG_WITH_FINE_LOCATION_ONLY) { false }
+ var res: String = default
+ if (pos == ALLOW_FOREGROUND_BUTTON && isPreciseLocation) {
+ res = stringResource(R.string.grant_dialog_button_change_to_precise_location)
+ }
+ if ((pos == DENY_BUTTON || pos == DENY_AND_DONT_ASK_AGAIN_BUTTON) && isPreciseLocation) {
+ res = stringResource(R.string.grant_dialog_button_keey_approximate_location)
+ }
+ return res
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageCustomPermissionScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageCustomPermissionScreen.kt
new file mode 100644
index 000000000..1563f6a57
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageCustomPermissionScreen.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.model.ManageCustomPermissionsViewModel
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+
+@Composable
+fun WearManageCustomPermissionScreen(
+ viewModel: ManageCustomPermissionsViewModel,
+ onPermGroupClick: (String) -> Unit
+) {
+ val permissionGroups = viewModel.uiDataLiveData.observeAsState(emptyMap())
+ var isLoading by remember { mutableStateOf(true) }
+
+ WearManageCustomPermissionContent(
+ isLoading,
+ getPermGroupChipParams(permissionGroups.value),
+ onPermGroupClick
+ )
+
+ if (isLoading && permissionGroups.value.isNotEmpty()) {
+ isLoading = false
+ }
+}
+
+@Composable
+internal fun WearManageCustomPermissionContent(
+ isLoading: Boolean,
+ permGroupChipParams: List<PermGroupChipParam>,
+ onPermGroupClick: (String) -> Unit
+) {
+ ScrollableScreen(
+ title = stringResource(R.string.additional_permissions),
+ isLoading = isLoading
+ ) {
+ for (params in permGroupChipParams) {
+ item {
+ Chip(
+ label = params.label,
+ labelMaxLines = 3,
+ icon = params.icon,
+ secondaryLabel = params.secondaryLabel,
+ secondaryLabelMaxLines = 3,
+ onClick = { onPermGroupClick(params.permGroupName) }
+ )
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageCustomPermissionsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageCustomPermissionsFragment.kt
new file mode 100644
index 000000000..a9e83919f
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageCustomPermissionsFragment.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.permission.ui.handheld.PermissionAppsFragment
+import com.android.permissioncontroller.permission.ui.model.ManageCustomPermissionsViewModel
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
+
+class WearManageCustomPermissionsFragment : Fragment() {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val activity = requireActivity()
+ val application = activity.getApplication()
+ val sessionId: Long =
+ arguments?.getLong(Constants.EXTRA_SESSION_ID) ?: Constants.INVALID_SESSION_ID
+ val viewModel =
+ ViewModelProvider(
+ this,
+ ViewModelProvider.AndroidViewModelFactory.getInstance(application)
+ )
+ .get(ManageCustomPermissionsViewModel::class.java)
+
+ val onPermGroupClick: (String) -> Unit = { permGroupName ->
+ viewModel.showPermissionApps(
+ this,
+ PermissionAppsFragment.createArgs(permGroupName, sessionId)
+ )
+ }
+
+ return ComposeView(activity).apply {
+ setContent {
+ WearPermissionTheme {
+ WearManageCustomPermissionScreen(viewModel, onPermGroupClick)
+ }
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionScreen.kt
new file mode 100644
index 000000000..7bf802755
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionScreen.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.graphics.drawable.Drawable
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.model.livedatatypes.PermGroupPackagesUiInfo
+import com.android.permissioncontroller.permission.ui.model.ManageStandardPermissionsViewModel
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupIcon
+import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
+import com.android.permissioncontroller.permission.utils.StringUtils
+import java.text.Collator
+
+@Composable
+fun WearManageStandardPermissionScreen(
+ viewModel: ManageStandardPermissionsViewModel,
+ onPermGroupClick: (String) -> Unit,
+ onCustomPermissionsClick: () -> Unit,
+ onAutoRevokedClick: () -> Unit
+) {
+ val permissionGroups = viewModel.uiDataLiveData.observeAsState(emptyMap())
+ val numCustomPermGroups = viewModel.numCustomPermGroups.observeAsState(0)
+ val numAutoRevoked = viewModel.numAutoRevoked.observeAsState(0)
+ var isLoading by remember { mutableStateOf(true) }
+
+ WearManageStandardPermissionContent(
+ isLoading,
+ getPermGroupChipParams(permissionGroups.value),
+ numCustomPermGroups.value,
+ numAutoRevoked.value,
+ onPermGroupClick,
+ onCustomPermissionsClick,
+ onAutoRevokedClick
+ )
+
+ if (isLoading && permissionGroups.value.isNotEmpty()) {
+ isLoading = false
+ }
+}
+
+@Composable
+internal fun getPermGroupChipParams(
+ permissionGroups: Map<String, PermGroupPackagesUiInfo?>
+): List<PermGroupChipParam> {
+ val context = LocalContext.current
+ val collator = Collator.getInstance(context.resources.getConfiguration().getLocales().get(0))
+ val summary =
+ if (context.resources.getBoolean(R.bool.config_useAlternativePermGroupSummary)) {
+ R.string.app_permissions_group_summary2
+ } else {
+ R.string.app_permissions_group_summary
+ }
+ return permissionGroups
+ .mapNotNull {
+ val uiInfo = it.value ?: return@mapNotNull null
+ PermGroupChipParam(
+ permGroupName = it.key,
+ label = getPermGroupLabel(context, it.key).toString(),
+ icon = getPermGroupIcon(context, it.key),
+ secondaryLabel =
+ stringResource(summary, uiInfo.nonSystemGranted, uiInfo.nonSystemTotal)
+ )
+ }
+ .sortedWith { lhs, rhs -> collator.compare(lhs.label, rhs.label) }
+ .toList()
+}
+
+@Composable
+internal fun WearManageStandardPermissionContent(
+ isLoading: Boolean,
+ permGroupChipParams: List<PermGroupChipParam>,
+ numCustomPermGroups: Int,
+ numAutoRevoked: Int,
+ onPermGroupClick: (String) -> Unit,
+ onCustomPermissionsClick: () -> Unit,
+ onAutoRevokedClick: () -> Unit
+) {
+ ScrollableScreen(
+ title = stringResource(R.string.app_permission_manager),
+ isLoading = isLoading
+ ) {
+ for (params in permGroupChipParams) {
+ item {
+ Chip(
+ label = params.label,
+ labelMaxLines = 3,
+ icon = params.icon,
+ secondaryLabel = params.secondaryLabel,
+ secondaryLabelMaxLines = 3,
+ onClick = { onPermGroupClick(params.permGroupName) }
+ )
+ }
+ }
+
+ if (numCustomPermGroups > 0) {
+ item {
+ Chip(
+ label = stringResource(R.string.additional_permissions),
+ labelMaxLines = 3,
+ icon = R.drawable.ic_more_horizontal,
+ secondaryLabel =
+ StringUtils.getIcuPluralsString(
+ LocalContext.current,
+ R.string.additional_permissions_more,
+ numCustomPermGroups
+ ),
+ secondaryLabelMaxLines = 3,
+ onClick = onCustomPermissionsClick
+ )
+ }
+ }
+
+ if (numAutoRevoked > 0) {
+ item {
+ Chip(
+ label = stringResource(R.string.auto_revoke_permission_notification_title),
+ labelMaxLines = 3,
+ icon = R.drawable.ic_info,
+ secondaryLabel = stringResource(R.string.auto_revoke_setting_subtitle),
+ secondaryLabelMaxLines = 3,
+ onClick = onAutoRevokedClick
+ )
+ }
+ }
+ }
+}
+
+internal data class PermGroupChipParam(
+ val permGroupName: String,
+ val label: String,
+ val icon: Drawable?,
+ val secondaryLabel: String,
+)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionsFragment.kt
new file mode 100644
index 000000000..16ed1f067
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearManageStandardPermissionsFragment.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.permission.ui.handheld.ManageCustomPermissionsFragment
+import com.android.permissioncontroller.permission.ui.handheld.PermissionAppsFragment
+import com.android.permissioncontroller.permission.ui.model.ManageStandardPermissionsViewModel
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
+
+class WearManageStandardPermissionsFragment : Fragment() {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val activity = requireActivity()
+ val application = activity.getApplication()
+ val sessionId: Long =
+ arguments?.getLong(Constants.EXTRA_SESSION_ID) ?: Constants.INVALID_SESSION_ID
+ val viewModel: ManageStandardPermissionsViewModel =
+ ViewModelProvider(
+ this,
+ ViewModelProvider.AndroidViewModelFactory.getInstance(application)
+ )
+ .get(ManageStandardPermissionsViewModel::class.java)
+
+ val onPermGroupClick: (String) -> Unit = { permGroupName ->
+ viewModel.showPermissionApps(
+ this,
+ PermissionAppsFragment.createArgs(permGroupName, sessionId)
+ )
+ }
+ val onCustomPermGroupClick = {
+ viewModel.showCustomPermissions(
+ this,
+ ManageCustomPermissionsFragment.createArgs(sessionId)
+ )
+ }
+ val onAutoRevokeClick = {
+ viewModel.showAutoRevoke(this, WearUnusedAppsFragment.createArgs(sessionId))
+ }
+
+ return ComposeView(activity).apply {
+ setContent {
+ WearPermissionTheme {
+ WearManageStandardPermissionScreen(
+ viewModel,
+ onPermGroupClick,
+ onCustomPermGroupClick,
+ onAutoRevokeClick
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt
new file mode 100644
index 000000000..d8eb71e0e
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.Manifest
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.os.UserHandle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.RequiresApi
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
+import com.android.permissioncontroller.permission.model.v31.PermissionUsages
+import com.android.permissioncontroller.permission.model.v31.PermissionUsages.PermissionsUsagesChangeCallback
+import com.android.permissioncontroller.permission.ui.handheld.AppPermissionFragment
+import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel
+import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModelFactory
+
+/**
+ * This is a condensed version of
+ * [com.android.permissioncontroller.permission.ui.handheld.PermissionAppsFragment], tailored for
+ * Wear.
+ *
+ * Show and manage apps which request a single permission group.
+ *
+ * <p>Shows a list of apps which request at least on permission of this group.
+ */
+class WearPermissionAppsFragment : Fragment(), PermissionsUsagesChangeCallback {
+ private val LOG_TAG = "PermissionAppsFragment"
+
+ private lateinit var permissionUsages: PermissionUsages
+ private lateinit var wearViewModel: WearAppPermissionUsagesViewModel
+
+ // Suppress warning of the deprecated class [android.app.LoaderManager] since other form factors
+ // are using the class to load PermissionUsages.
+ @Suppress("DEPRECATION")
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val permGroupName =
+ arguments?.getString(Intent.EXTRA_PERMISSION_GROUP_NAME)
+ ?: arguments?.getString(Intent.EXTRA_PERMISSION_NAME)
+ ?: throw RuntimeException("Permission group name must not be null.")
+ val sessionId: Long =
+ arguments?.getLong(Constants.EXTRA_SESSION_ID) ?: Constants.INVALID_SESSION_ID
+ val isStorageAndLessThanT =
+ !SdkLevel.isAtLeastT() && permGroupName == Manifest.permission_group.STORAGE
+
+ val activity = requireActivity()
+ val factory =
+ PermissionAppsViewModelFactory(activity.getApplication(), permGroupName, this, Bundle())
+ val viewModel = ViewModelProvider(this, factory).get(PermissionAppsViewModel::class.java)
+ wearViewModel =
+ ViewModelProvider(this, WearAppPermissionUsagesViewModelFactory())
+ .get(WearAppPermissionUsagesViewModel::class.java)
+
+ val onAppClick: (String, UserHandle, String) -> Unit = { packageName, user, category ->
+ run {
+ viewModel.navigateToAppPermission(
+ this,
+ packageName,
+ user,
+ AppPermissionFragment.createArgs(
+ packageName,
+ null,
+ permGroupName,
+ user,
+ this::class.java.name,
+ sessionId,
+ category
+ )
+ )
+ }
+ }
+
+ val onShowSystemClick: (Boolean) -> Unit = { showSystem ->
+ run { viewModel.updateShowSystem(showSystem) }
+ }
+
+ val logPermissionAppsFragmentCreated:
+ (String, UserHandle, Long, Boolean, Boolean, Boolean) -> Unit =
+ { packageName, user, viewId, isAllowed, isAllowedForeground, isDenied ->
+ run {
+ viewModel.logPermissionAppsFragmentCreated(
+ packageName,
+ user,
+ viewId,
+ isAllowed,
+ isAllowedForeground,
+ isDenied,
+ sessionId,
+ activity.getApplication(),
+ permGroupName,
+ LOG_TAG
+ )
+ }
+ }
+
+ // If the build type is below S, the app ops for permission usage can't be found. Thus, we
+ // shouldn't load permission usages, for them.
+ if (SdkLevel.isAtLeastS()) {
+ permissionUsages = PermissionUsages(requireContext())
+
+ val filterTimeBeginMillis: Long = viewModel.getFilterTimeBeginMillis()
+ permissionUsages.load(
+ null,
+ null,
+ filterTimeBeginMillis,
+ Long.MAX_VALUE,
+ PermissionUsages.USAGE_FLAG_LAST,
+ requireActivity().getLoaderManager(),
+ false,
+ false,
+ this,
+ false
+ )
+ }
+
+ return ComposeView(requireContext()).apply {
+ setContent {
+ WearPermissionAppsScreen(
+ WearPermissionAppsHelper(
+ activity.getApplication(),
+ permGroupName,
+ viewModel,
+ wearViewModel,
+ isStorageAndLessThanT,
+ onAppClick,
+ onShowSystemClick,
+ logPermissionAppsFragmentCreated
+ )
+ )
+ }
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ override fun onPermissionUsagesChanged() {
+ if (permissionUsages.usages.isEmpty()) {
+ return
+ }
+ if (context == null) {
+ // Async result has come in after our context is gone.
+ return
+ }
+ wearViewModel.appPermissionUsages.value =
+ ArrayList<AppPermissionUsage>(permissionUsages.usages)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt
new file mode 100644
index 000000000..539adf4fb
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.app.Application
+import android.graphics.drawable.Drawable
+import android.os.UserHandle
+import com.android.permission.flags.Flags
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
+import com.android.permissioncontroller.permission.ui.Category
+import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModel
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupDescription
+import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
+import com.android.settingslib.utils.applications.AppUtils
+import java.text.Collator
+import java.util.Random
+
+/** Helper class for WearPermissionsAppScreen. */
+class WearPermissionAppsHelper(
+ val application: Application,
+ val permGroupName: String,
+ val viewModel: PermissionAppsViewModel,
+ val wearViewModel: WearAppPermissionUsagesViewModel,
+ private val isStorageAndLessThanT: Boolean,
+ private val onAppClick: (String, UserHandle, String) -> Unit,
+ val onShowSystemClick: (Boolean) -> Unit,
+ val logFragmentCreated: (String, UserHandle, Long, Boolean, Boolean, Boolean) -> Unit
+) {
+ fun categorizedAppsLiveData() = viewModel.categorizedAppsLiveData
+ fun hasSystemAppsLiveData() = viewModel.hasSystemAppsLiveData
+ fun shouldShowSystemLiveData() = viewModel.shouldShowSystemLiveData
+ fun showAlways() = viewModel.showAllowAlwaysStringLiveData.value ?: false
+ fun getTitle() = getPermGroupLabel(application, permGroupName).toString()
+ fun getSubTitle() = getPermGroupDescription(application, permGroupName).toString()
+ fun getChipsByCategory(
+ categorizedApps: Map<Category, List<Pair<String, UserHandle>>>,
+ appPermissionUsages: List<AppPermissionUsage>
+ ): Map<String, List<ChipInfo>> {
+ val chipsByCategory: MutableMap<String, MutableList<ChipInfo>> = HashMap()
+
+ // A mapping of user + packageName to their last access timestamps for the permission group.
+ val groupUsageLastAccessTime: Map<String, Long> =
+ viewModel.extractGroupUsageLastAccessTime(appPermissionUsages)
+
+ val context = application
+ val collator = Collator.getInstance(context.resources.configuration.locales.get(0))
+ val comparator = ChipComparator(collator)
+
+ val viewIdForLogging = Random().nextLong()
+ for (category in Category.values()) {
+ if (category == Category.ALLOWED && isStorageAndLessThanT) {
+ val allowedList = categorizedApps[Category.ALLOWED]
+ if (!allowedList.isNullOrEmpty()) {
+ allowedList
+ .partition { p -> viewModel.packageHasFullStorage(p.first, p.second) }
+ .let {
+ if (it.first.isNotEmpty()) {
+ chipsByCategory[STORAGE_ALLOWED_FULL] =
+ convertToChips(
+ category,
+ it.first,
+ viewIdForLogging,
+ comparator,
+ groupUsageLastAccessTime
+ )
+ }
+ if (it.second.isNotEmpty()) {
+ chipsByCategory[STORAGE_ALLOWED_SCOPED] =
+ convertToChips(
+ category,
+ it.second,
+ viewIdForLogging,
+ comparator,
+ groupUsageLastAccessTime
+ )
+ }
+ }
+ }
+ continue
+ }
+ val list = categorizedApps[category]
+ if (!list.isNullOrEmpty()) {
+ chipsByCategory[category.categoryName] =
+ convertToChips(
+ category,
+ list,
+ viewIdForLogging,
+ comparator,
+ groupUsageLastAccessTime
+ )
+ }
+ }
+
+ // Add no_apps chips to allowed and denied if it doesn't have an app.
+ addNoAppsIfNeeded(chipsByCategory)
+ return chipsByCategory
+ }
+
+ private fun convertToChips(
+ category: Category,
+ list: List<Pair<String, UserHandle>>,
+ viewIdForLogging: Long,
+ comparator: Comparator<ChipInfo>,
+ groupUsageLastAccessTime: Map<String, Long>
+ ) =
+ list
+ .map { p ->
+ val lastAccessTime = groupUsageLastAccessTime[(p.second.toString() + p.first)]
+ createAppChipInfo(
+ application,
+ p.first,
+ p.second,
+ category,
+ onAppClick,
+ viewIdForLogging,
+ lastAccessTime
+ )
+ }
+ .sortedWith(comparator)
+ .toMutableList()
+
+ fun setCreationLogged(isLogged: Boolean) {
+ viewModel.creationLogged = isLogged
+ }
+
+ private fun createAppChipInfo(
+ application: Application,
+ packageName: String,
+ user: UserHandle,
+ category: Category,
+ onClick: (packageName: String, user: UserHandle, category: String) -> Unit,
+ viewIdForLogging: Long,
+ lastAccessTime: Long?
+ ): ChipInfo {
+ if (!viewModel.creationLogged) {
+ logFragmentCreated(
+ packageName,
+ user,
+ viewIdForLogging,
+ category == Category.ALLOWED,
+ category == Category.ALLOWED_FOREGROUND,
+ category == Category.DENIED
+ )
+ }
+ val summary =
+ if (Flags.wearPrivacyDashboardEnabled()) {
+ lastAccessTime?.let { WearUtils.getPreferenceSummary(application, lastAccessTime) }
+ } else {
+ null
+ }
+ return ChipInfo(
+ title = KotlinUtils.getPackageLabel(application, packageName, user),
+ summary = summary,
+ contentDescription =
+ AppUtils.getAppContentDescription(application, packageName, user.getIdentifier()),
+ icon = KotlinUtils.getBadgedPackageIcon(application, packageName, user),
+ onClick = { onClick(packageName, user, category.categoryName) }
+ )
+ }
+
+ private fun addNoAppsIfNeeded(chipsByCategory: MutableMap<String, MutableList<ChipInfo>>) {
+ addNoAppsToAllowed(chipsByCategory)
+ addNoAppsToDenied(chipsByCategory)
+ }
+
+ private fun addNoAppsToAllowed(chipsByCategory: MutableMap<String, MutableList<ChipInfo>>) {
+ if (isStorageAndLessThanT) {
+ // For the storage permission,
+ // allowed category is split into allowed_full and allowed_scoped categories,
+ // add no_apps chip to the categories.
+ addNoAppsTo(chipsByCategory, STORAGE_ALLOWED_FULL, R.string.no_apps_allowed_full)
+ addNoAppsTo(chipsByCategory, STORAGE_ALLOWED_SCOPED, R.string.no_apps_allowed_scoped)
+ return
+ }
+ addNoAppsTo(chipsByCategory, Category.ALLOWED.categoryName, R.string.no_apps_allowed)
+ }
+
+ private fun addNoAppsToDenied(chipsByCategory: MutableMap<String, MutableList<ChipInfo>>) {
+ addNoAppsTo(chipsByCategory, Category.DENIED.categoryName, R.string.no_apps_denied)
+ }
+
+ private fun addNoAppsTo(
+ chipsByCategory: MutableMap<String, MutableList<ChipInfo>>,
+ categoryName: String,
+ titleResId: Int
+ ) {
+ if (chipsByCategory[categoryName].isNullOrEmpty()) {
+ chipsByCategory[categoryName] =
+ mutableListOf(
+ ChipInfo(title = application.resources.getString(titleResId), enabled = false)
+ )
+ }
+ }
+
+ companion object {
+ private const val STORAGE_ALLOWED_FULL = "allowed_storage_full"
+ private const val STORAGE_ALLOWED_SCOPED = "allowed_storage_scoped"
+ }
+}
+
+class ChipInfo(
+ val title: String,
+ val summary: String? = null,
+ val contentDescription: String? = null,
+ val onClick: () -> Unit = {},
+ val icon: Drawable? = null,
+ val enabled: Boolean = true
+)
+
+internal class ChipComparator(val collator: Collator) : Comparator<ChipInfo> {
+ override fun compare(lhs: ChipInfo, rhs: ChipInfo): Int {
+ var result = collator.compare(lhs.title, rhs.title)
+ if (result == 0) {
+ result = lhs.title.compareTo(rhs.title)
+ }
+ return result
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt
new file mode 100644
index 000000000..154fd0bff
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.wear.compose.material.Text
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.Category
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ListSubheader
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+
+/** Compose the screen associated to a [WearPermissionAppsFragment]. */
+@Composable
+fun WearPermissionAppsScreen(helper: WearPermissionAppsHelper) {
+ val categorizedApps = helper.categorizedAppsLiveData().observeAsState(emptyMap())
+ val hasSystemApps = helper.hasSystemAppsLiveData().observeAsState(false)
+ val showSystem = helper.shouldShowSystemLiveData().observeAsState(false)
+ val appPermissionUsages = helper.wearViewModel.appPermissionUsages.observeAsState(emptyList())
+ var isLoading by remember { mutableStateOf(true) }
+
+ val title = helper.getTitle()
+ val subTitle = helper.getSubTitle()
+ val showAlways = helper.showAlways()
+ val chipsByCategory =
+ helper.getChipsByCategory(categorizedApps.value, appPermissionUsages.value)
+
+ WearPermissionAppsContent(
+ chipsByCategory,
+ showSystem.value,
+ hasSystemApps.value,
+ title,
+ subTitle,
+ showAlways,
+ isLoading,
+ helper.onShowSystemClick
+ )
+
+ if (isLoading && categorizedApps.value.isNotEmpty()) {
+ isLoading = false
+ }
+ helper.setCreationLogged(true)
+}
+
+@Composable
+internal fun WearPermissionAppsContent(
+ chipsByCategory: Map<String, List<ChipInfo>>,
+ showSystem: Boolean,
+ hasSystemApps: Boolean,
+ title: String,
+ subtitle: String,
+ showAlways: Boolean,
+ isLoading: Boolean,
+ onShowSystemClick: (showSystem: Boolean) -> Unit
+) {
+ ScrollableScreen(title = title, subtitle = subtitle, isLoading = isLoading) {
+ for (category in categoryOrder) {
+ val chips = chipsByCategory[category]
+ if (chips.isNullOrEmpty()) {
+ continue
+ }
+ item {
+ ListSubheader {
+ Text(text = stringResource(getCategoryString(category, showAlways)))
+ }
+ }
+ chips.forEach {
+ item {
+ Chip(
+ label = it.title,
+ labelMaxLines = Int.MAX_VALUE,
+ secondaryLabel = it.summary,
+ secondaryLabelMaxLines = Int.MAX_VALUE,
+ icon = it.icon,
+ enabled = it.enabled,
+ onClick = { it.onClick() },
+ modifier = Modifier.fillMaxWidth()
+ )
+ }
+ }
+ }
+
+ if (hasSystemApps) {
+ item {
+ Chip(
+ label =
+ if (showSystem) {
+ stringResource(R.string.menu_hide_system)
+ } else {
+ stringResource(R.string.menu_show_system)
+ },
+ labelMaxLines = Int.MAX_VALUE,
+ onClick = { onShowSystemClick(!showSystem) },
+ modifier = Modifier.fillMaxWidth(),
+ )
+ }
+ }
+ }
+}
+
+internal fun getCategoryString(category: String, showAlways: Boolean) =
+ when (category) {
+ "allowed_storage_full" -> R.string.allowed_storage_full
+ "allowed_storage_scoped" -> R.string.allowed_storage_scoped
+ Category.ALLOWED.categoryName ->
+ if (showAlways) {
+ R.string.allowed_always_header
+ } else {
+ R.string.allowed_header
+ }
+ Category.ALLOWED_FOREGROUND.categoryName -> R.string.allowed_foreground_header
+ Category.ASK.categoryName -> R.string.ask_header
+ Category.DENIED.categoryName -> R.string.denied_header
+ else -> throw IllegalArgumentException("Wrong category: $category")
+ }
+
+internal val categoryOrder =
+ listOf(
+ "allowed_storage_full",
+ "allowed_storage_scoped",
+ Category.ALLOWED.categoryName,
+ Category.ALLOWED_FOREGROUND.categoryName,
+ Category.ASK.categoryName,
+ Category.DENIED.categoryName
+ )
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt
new file mode 100644
index 000000000..ead7f9503
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.RequiresApi
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsViewModelFactory
+import com.android.permissioncontroller.permission.utils.KotlinUtils.is7DayToggleEnabled
+
+/**
+ * This is a condensed version of
+ * [com.android.permissioncontroller.permission.ui.handheld.v31.PermissionUsageDetailsFragment],
+ * tailored for Wear.
+ */
+@RequiresApi(Build.VERSION_CODES.S)
+class WearPermissionUsageDetailsFragment : Fragment() {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val permissionGroup =
+ arguments?.getString(Intent.EXTRA_PERMISSION_GROUP_NAME)
+ ?: let {
+ Log.e(TAG, "No permission group was provided for PermissionDetailsFragment")
+ return null
+ }
+ val showSystem =
+ arguments?.getBoolean(ManagePermissionsActivity.EXTRA_SHOW_SYSTEM, false) ?: false
+ val show7Days =
+ arguments?.getBoolean(ManagePermissionsActivity.EXTRA_SHOW_7_DAYS, false) ?: false
+
+ val factory =
+ PermissionUsageDetailsViewModelFactory(
+ PermissionControllerApplication.get(),
+ this,
+ permissionGroup
+ )
+ val viewModel =
+ ViewModelProvider(this, factory).get(PermissionUsageDetailsViewModel::class.java)
+ viewModel.updateShowSystemAppsToggle(showSystem)
+ viewModel.updateShow7DaysToggle(is7DayToggleEnabled() && show7Days)
+
+ return ComposeView(requireContext()).apply {
+ setContent { WearPermissionUsageDetailsScreen(permissionGroup, viewModel) }
+ }
+ }
+
+ companion object {
+ private const val TAG = "WearPermissionUsageDetails"
+
+ @JvmStatic
+ fun newInstance(
+ groupName: String?,
+ showSystem: Boolean,
+ show7Days: Boolean
+ ): WearPermissionUsageDetailsFragment {
+ return WearPermissionUsageDetailsFragment().apply {
+ val arguments =
+ Bundle().apply {
+ if (groupName != null) {
+ putString(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
+ }
+ putBoolean(ManagePermissionsActivity.EXTRA_SHOW_SYSTEM, showSystem)
+ putBoolean(ManagePermissionsActivity.EXTRA_SHOW_7_DAYS, show7Days)
+ }
+ setArguments(arguments)
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt
new file mode 100644
index 000000000..3c62e5343
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.content.Intent
+import android.os.Build
+import android.text.format.DateFormat
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.MaterialTheme
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.AppPermissionAccessUiInfo
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+
+@RequiresApi(Build.VERSION_CODES.S)
+@Composable
+fun WearPermissionUsageDetailsScreen(
+ permissionGroup: String,
+ viewModel: PermissionUsageDetailsViewModel
+) {
+ val context = LocalContext.current
+ val uiData = viewModel.permissionUsagesDetailsInfoUiLiveData.observeAsState(null)
+ val showSystem = viewModel.showSystemLiveData.observeAsState(false)
+ var isLoading by remember { mutableStateOf(true) }
+
+ val title = stringResource(R.string.permission_history_title)
+ val subtitle =
+ stringResource(
+ R.string.permission_group_usage_title,
+ KotlinUtils.getPermGroupLabel(context, permissionGroup)
+ )
+ val hasSystemApps: Boolean = uiData.value?.containsSystemAppAccesses ?: false
+ val onShowSystemClick: (Boolean) -> Unit = { show ->
+ run { viewModel.updateShowSystemAppsToggle(show) }
+ }
+ val onChipClick: (AppPermissionAccessUiInfo) -> Unit = { uiInfo ->
+ run {
+ val intent =
+ PermissionUsageDetailsViewModel.createHistoryPreferenceClickIntent(
+ context,
+ uiInfo.userHandle,
+ uiInfo.packageName,
+ uiInfo.permissionGroup,
+ uiInfo.accessStartTime,
+ uiInfo.accessEndTime,
+ uiInfo.showingAttribution,
+ uiInfo.attributionTags
+ )
+ context.startActivityAsUser(intent, uiInfo.userHandle)
+ }
+ }
+ val onManagePermissionClick: () -> Unit = {
+ val intent: Intent =
+ Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
+ .putExtra(Intent.EXTRA_PERMISSION_NAME, permissionGroup)
+ context.startActivity(intent)
+ }
+
+ val appPermissionAccessUiInfoList: List<AppPermissionAccessUiInfo> =
+ uiData.value?.appPermissionAccessUiInfoList ?: emptyList()
+
+ WearPermissionUsageDetailsContent(
+ title,
+ subtitle,
+ isLoading,
+ hasSystemApps,
+ showSystem.value,
+ onShowSystemClick,
+ appPermissionAccessUiInfoList,
+ onChipClick,
+ onManagePermissionClick
+ )
+
+ if (isLoading && uiData.value != null) {
+ isLoading = false
+ }
+}
+
+@Composable
+internal fun WearPermissionUsageDetailsContent(
+ title: String,
+ subtitle: String,
+ isLoading: Boolean,
+ hasSystemApps: Boolean,
+ showSystem: Boolean,
+ onShowSystemClick: (Boolean) -> Unit,
+ appPermissionAccessUiInfoList: List<AppPermissionAccessUiInfo>,
+ onChipClick: (AppPermissionAccessUiInfo) -> Unit,
+ onManagePermissionClick: () -> Unit
+) {
+ ScrollableScreen(title = title, subtitle = subtitle, isLoading = isLoading) {
+ if (appPermissionAccessUiInfoList.isEmpty()) {
+ item { Chip(label = stringResource(R.string.no_apps), onClick = {}) }
+ } else {
+ for (uiInfo in appPermissionAccessUiInfoList) {
+ item {
+ Chip(
+ label = uiInfo.packageLabel,
+ labelMaxLines = Int.MAX_VALUE,
+ secondaryLabel =
+ DateFormat.getTimeFormat(LocalContext.current)
+ .format(uiInfo.accessEndTime),
+ secondaryLabelMaxLines = Int.MAX_VALUE,
+ icon = uiInfo.badgedPackageIcon,
+ onClick = { onChipClick(uiInfo) }
+ )
+ }
+ }
+ if (hasSystemApps) {
+ item {
+ Chip(
+ label =
+ if (showSystem) {
+ stringResource(R.string.menu_hide_system)
+ } else {
+ stringResource(R.string.menu_show_system)
+ },
+ labelMaxLines = Int.MAX_VALUE,
+ onClick = { onShowSystemClick(!showSystem) },
+ modifier = Modifier.fillMaxWidth(),
+ )
+ }
+ }
+ item {
+ Chip(
+ label = stringResource(R.string.manage_permission),
+ textColor = MaterialTheme.colors.background,
+ colors = ChipDefaults.primaryChipColors(),
+ onClick = { onManagePermissionClick() },
+ )
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageFragment.kt
new file mode 100644
index 000000000..f8c305e0f
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageFragment.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.os.Build
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.RequiresApi
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModel
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModel.PermissionUsageViewModelFactory
+
+/**
+ * This is a condensed version of
+ * [com.android.permissioncontroller.permission.ui.handheld.v31.PermissionUsageFragment], tailored
+ * for Wear.
+ */
+@RequiresApi(Build.VERSION_CODES.S)
+class WearPermissionUsageFragment : Fragment() {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val sessionId: Long =
+ arguments?.getLong(Constants.EXTRA_SESSION_ID) ?: Constants.INVALID_SESSION_ID
+ val factory =
+ PermissionUsageViewModelFactory(requireActivity().getApplication(), this, Bundle())
+ val viewModel: PermissionUsageViewModel =
+ ViewModelProvider(this, factory).get(PermissionUsageViewModel::class.java)
+
+ return ComposeView(requireContext()).apply {
+ setContent { WearPermissionUsageScreen(sessionId, viewModel) }
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun newInstance(sessionId: Long): WearPermissionUsageFragment {
+ return WearPermissionUsageFragment().apply {
+ val arguments = Bundle().apply { putLong(Constants.EXTRA_SESSION_ID, sessionId) }
+ setArguments(arguments)
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageScreen.kt
new file mode 100644
index 000000000..f155365d0
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageScreen.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.handheld.v31.PermissionUsageControlPreference
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModel
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import java.text.Collator
+
+@RequiresApi(Build.VERSION_CODES.S)
+@Composable
+fun WearPermissionUsageScreen(sessionId: Long, viewModel: PermissionUsageViewModel) {
+ val context = LocalContext.current
+ val permissionUsagesUiData = viewModel.permissionUsagesUiLiveData.observeAsState(null)
+ val showSystem = viewModel.showSystemAppsLiveData.observeAsState(false)
+ val show7Days = viewModel.show7DaysLiveData.observeAsState(false)
+ var isLoading by remember { mutableStateOf(true) }
+
+ val hasSystemApps: Boolean = permissionUsagesUiData.value?.containsSystemAppUsages ?: false
+ val onShowSystemClick: (Boolean) -> Unit = { show -> run { viewModel.updateShowSystem(show) } }
+
+ val permissionGroupWithUsageCounts: Map<String, Int> =
+ permissionUsagesUiData.value?.permissionGroupsWithUsageCount ?: emptyMap()
+ val permissionGroupWithUsageCountsEntries: List<Map.Entry<String, Int>> =
+ ArrayList<Map.Entry<String, Int>>(permissionGroupWithUsageCounts.entries)
+
+ val collator = Collator.getInstance(context.resources.configuration.locales.get(0))
+ val permissionGroupPreferences =
+ permissionGroupWithUsageCountsEntries
+ .map {
+ PermissionUsageControlPreference(
+ context,
+ it.key,
+ it.value,
+ showSystem.value,
+ sessionId,
+ show7Days.value
+ )
+ }
+ .sortedWith { o1, o2 ->
+ var result = collator.compare(o1.title.toString(), o2.title.toString())
+ if (result == 0) {
+ result = o1.title.toString().compareTo(o2.title.toString())
+ }
+ result
+ }
+ .toList()
+
+ WearPermissionUsageContent(
+ isLoading,
+ hasSystemApps,
+ showSystem.value,
+ onShowSystemClick,
+ permissionGroupPreferences
+ )
+
+ if (isLoading && permissionUsagesUiData.value != null) {
+ isLoading = false
+ }
+}
+
+@Composable
+internal fun WearPermissionUsageContent(
+ isLoading: Boolean,
+ hasSystemApps: Boolean,
+ showSystem: Boolean,
+ onShowSystemClick: (Boolean) -> Unit,
+ permissionGroupPreferences: List<PermissionUsageControlPreference>
+) {
+ ScrollableScreen(
+ title = stringResource(R.string.permission_usage_title),
+ isLoading = isLoading
+ ) {
+ if (permissionGroupPreferences.isEmpty()) {
+ item { Chip(label = stringResource(R.string.no_permissions), onClick = {}) }
+ } else {
+ for (preference in permissionGroupPreferences) {
+ item {
+ Chip(
+ label = preference.title.toString(),
+ labelMaxLines = Int.MAX_VALUE,
+ secondaryLabel = preference.summary.toString(),
+ secondaryLabelMaxLines = Int.MAX_VALUE,
+ icon = preference.icon,
+ enabled = preference.isEnabled,
+ onClick = { preference.performClick() }
+ )
+ }
+ }
+ if (hasSystemApps) {
+ item {
+ Chip(
+ label =
+ if (showSystem) {
+ stringResource(R.string.menu_hide_system)
+ } else {
+ stringResource(R.string.menu_show_system)
+ },
+ labelMaxLines = Int.MAX_VALUE,
+ onClick = { onShowSystemClick(!showSystem) },
+ modifier = Modifier.fillMaxWidth(),
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUnusedAppsFragment.kt
new file mode 100644
index 000000000..9b8047a0c
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUnusedAppsFragment.kt
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.Manifest
+import android.content.Context
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.os.UserHandle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.Constants.INVALID_SESSION_ID
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel
+import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel.UnusedPackageInfo
+import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel.UnusedPeriod
+import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel.UnusedPeriod.Companion.allPeriods
+import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModelFactory
+import com.android.permissioncontroller.permission.ui.wear.model.WearUnusedAppsViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.WearUnusedAppsViewModel.UnusedAppChip
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.settingslib.utils.applications.AppUtils
+import java.text.Collator
+
+/**
+ * This is a condensed version of
+ * [com.android.permissioncontroller.permission.ui.UnusedAppsFragment.kt], tailored for Wear.
+ *
+ * A fragment displaying all applications that are unused as well as the option to remove them and
+ * to open them.
+ */
+class WearUnusedAppsFragment : Fragment() {
+ private lateinit var activity: FragmentActivity
+ private lateinit var context: Context
+ private lateinit var viewModel: UnusedAppsViewModel
+ private lateinit var wearViewModel: WearUnusedAppsViewModel
+ private lateinit var collator: Collator
+ private var sessionId: Long = 0L
+ private var isFirstLoad = false
+ private var categoryVisibilities: MutableList<Boolean> =
+ MutableList(UnusedPeriod.values().size) { false }
+ private var unusedAppsMap: MutableMap<UnusedPeriod, MutableMap<String, UnusedAppChip>> =
+ initUnusedAppsMap()
+
+ companion object {
+ private const val SHOW_LOAD_DELAY_MS = 200L
+ private val LOG_TAG = WearUnusedAppsFragment::class.java.simpleName
+
+ /**
+ * Create the args needed for this fragment
+ *
+ * @param sessionId The current session Id
+ * @return A bundle containing the session Id
+ */
+ @JvmStatic
+ fun createArgs(sessionId: Long): Bundle {
+ val bundle = Bundle()
+ bundle.putLong(EXTRA_SESSION_ID, sessionId)
+ return bundle
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ isFirstLoad = true
+ context = requireContext()
+ collator =
+ Collator.getInstance(context.getResources().getConfiguration().getLocales().get(0))
+ activity = requireActivity()
+ val application = activity.getApplication()
+ sessionId = arguments!!.getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID)
+ val factory = UnusedAppsViewModelFactory(activity.application, sessionId)
+ viewModel = ViewModelProvider(this, factory).get(UnusedAppsViewModel::class.java)
+ wearViewModel =
+ ViewModelProvider(
+ this,
+ ViewModelProvider.AndroidViewModelFactory.getInstance(application)
+ )
+ .get(WearUnusedAppsViewModel::class.java)
+ viewModel.unusedPackageCategoriesLiveData.observe(
+ this,
+ Observer {
+ it?.let { pkgs ->
+ updatePackages(pkgs)
+ updateWearViewModel(false)
+ }
+ }
+ )
+
+ if (!viewModel.unusedPackageCategoriesLiveData.isInitialized) {
+ val handler = Handler(Looper.getMainLooper())
+ handler.postDelayed(
+ {
+ if (!viewModel.unusedPackageCategoriesLiveData.isInitialized) {
+ wearViewModel.loadingLiveData.value = true
+ } else {
+ updatePackages(viewModel.unusedPackageCategoriesLiveData.value!!)
+ updateWearViewModel(false)
+ }
+ },
+ SHOW_LOAD_DELAY_MS
+ )
+ } else {
+ updatePackages(viewModel.unusedPackageCategoriesLiveData.value!!)
+ updateWearViewModel(false)
+ }
+
+ return ComposeView(activity).apply {
+ setContent { WearPermissionTheme { WearUnusedAppsScreen(wearViewModel) } }
+ }
+ }
+
+ private fun initUnusedAppsMap(): MutableMap<UnusedPeriod, MutableMap<String, UnusedAppChip>> {
+ val res = mutableMapOf<UnusedPeriod, MutableMap<String, UnusedAppChip>>()
+ for (period in allPeriods) {
+ res.put(period, mutableMapOf())
+ }
+ return res
+ }
+
+ private fun updatePackages(categorizedPackages: Map<UnusedPeriod, List<UnusedPackageInfo>>) {
+ // Remove stale unused app chips
+ for (period in allPeriods) {
+ val it: MutableIterator<Map.Entry<String, UnusedAppChip>> =
+ unusedAppsMap[period]!!.entries.iterator()
+ while (it.hasNext()) {
+ val contains =
+ categorizedPackages[period]?.any { (pkgName, user, _) ->
+ val key = createKey(pkgName, user)
+ it.next().key == key
+ }
+ if (contains != true) {
+ it.remove()
+ }
+ }
+ }
+
+ var allCategoriesEmpty = true
+ for ((period, packages) in categorizedPackages) {
+ categoryVisibilities.set(periodToIndex(period), packages.isNotEmpty())
+ if (packages.isNotEmpty()) {
+ allCategoriesEmpty = false
+ }
+
+ for ((pkgName, user, _, permSet) in packages) {
+ val revokedPerms = permSet.toList()
+ val key = createKey(pkgName, user)
+
+ if (!unusedAppsMap[period]!!.containsKey(key)) {
+ val mostImportant = getMostImportantGroup(revokedPerms)
+ val importantLabel = KotlinUtils.getPermGroupLabel(context, mostImportant)
+ val summary =
+ when {
+ revokedPerms.isEmpty() -> null
+ revokedPerms.size == 1 ->
+ getString(R.string.auto_revoked_app_summary_one, importantLabel)
+ revokedPerms.size == 2 -> {
+ val otherLabel =
+ if (revokedPerms[0] == mostImportant) {
+ KotlinUtils.getPermGroupLabel(context, revokedPerms[1])
+ } else {
+ KotlinUtils.getPermGroupLabel(context, revokedPerms[0])
+ }
+ getString(
+ R.string.auto_revoked_app_summary_two,
+ importantLabel,
+ otherLabel
+ )
+ }
+ else ->
+ getString(
+ R.string.auto_revoked_app_summary_many,
+ importantLabel,
+ "${revokedPerms.size - 1}"
+ )
+ }
+
+ val onChipClicked: () -> Unit = {
+ run { viewModel.navigateToAppInfo(pkgName, user, sessionId) }
+ }
+
+ val chip =
+ UnusedAppChip(
+ KotlinUtils.getPackageLabel(activity.application, pkgName, user),
+ summary,
+ KotlinUtils.getBadgedPackageIcon(activity.application, pkgName, user),
+ AppUtils.getAppContentDescription(
+ context,
+ pkgName,
+ user.getIdentifier()
+ ),
+ onChipClicked
+ )
+ unusedAppsMap[period]!!.put(key, chip)
+ }
+ }
+
+ // Sort the chips
+ unusedAppsMap[period] =
+ unusedAppsMap[period]!!
+ .toList()
+ .sortedWith(Comparator { lhs, rhs -> compareUnusedApps(lhs, rhs) })
+ .toMap()
+ .toMutableMap()
+ }
+
+ wearViewModel.infoMsgCategoryVisibilityLiveData.value = !allCategoriesEmpty
+
+ if (isFirstLoad) {
+ if (categorizedPackages.any { (_, packages) -> packages.isNotEmpty() }) {
+ isFirstLoad = false
+ }
+ Log.i(LOG_TAG, "sessionId: $sessionId Showed Auto Revoke Page")
+ for (period in allPeriods) {
+ Log.i(
+ LOG_TAG,
+ "sessionId: $sessionId $period unused: " + "${categorizedPackages[period]}"
+ )
+ for (revokedPackageInfo in categorizedPackages[period]!!) {
+ for (groupName in revokedPackageInfo.revokedGroups) {
+ val isNewlyRevoked = period.isNewlyUnused()
+ viewModel.logAppView(
+ revokedPackageInfo.packageName,
+ revokedPackageInfo.user,
+ groupName,
+ isNewlyRevoked
+ )
+ }
+ }
+ }
+ }
+ }
+
+ private fun createKey(packageName: String, user: UserHandle): String {
+ return "$packageName:${user.identifier}"
+ }
+
+ private fun periodToIndex(period: UnusedPeriod): Int {
+ when (period) {
+ UnusedPeriod.ONE_MONTH -> return 0
+ UnusedPeriod.THREE_MONTHS -> return 1
+ UnusedPeriod.SIX_MONTHS -> return 2
+ }
+ }
+
+ private fun getMostImportantGroup(groupNames: List<String>): String {
+ return when {
+ groupNames.contains(Manifest.permission_group.LOCATION) ->
+ Manifest.permission_group.LOCATION
+ groupNames.contains(Manifest.permission_group.MICROPHONE) ->
+ Manifest.permission_group.MICROPHONE
+ groupNames.contains(Manifest.permission_group.CAMERA) ->
+ Manifest.permission_group.CAMERA
+ groupNames.contains(Manifest.permission_group.CONTACTS) ->
+ Manifest.permission_group.CONTACTS
+ groupNames.contains(Manifest.permission_group.STORAGE) ->
+ Manifest.permission_group.STORAGE
+ groupNames.contains(Manifest.permission_group.CALENDAR) ->
+ Manifest.permission_group.CALENDAR
+ groupNames.isNotEmpty() -> groupNames[0]
+ else -> ""
+ }
+ }
+
+ private fun compareUnusedApps(
+ lhs: Pair<String, UnusedAppChip>,
+ rhs: Pair<String, UnusedAppChip>
+ ): Int {
+ var result = collator.compare(lhs.second.label, rhs.second.label)
+ if (result == 0) {
+ result = collator.compare(lhs.first, rhs.first)
+ }
+ return result
+ }
+
+ private fun updateWearViewModel(isLoading: Boolean) {
+ wearViewModel.loadingLiveData.value = isLoading
+ wearViewModel.unusedPeriodCategoryVisibilitiesLiveData.setValue(categoryVisibilities)
+ wearViewModel.unusedAppChipsLiveData.setValue(unusedAppsMap)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUnusedAppsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUnusedAppsScreen.kt
new file mode 100644
index 000000000..7c2487004
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUnusedAppsScreen.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.icu.text.MessageFormat
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.res.stringResource
+import androidx.wear.compose.material.Text
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.hibernation.isHibernationEnabled
+import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel.UnusedPeriod
+import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel.UnusedPeriod.Companion.allPeriods
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.Icon
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.ui.wear.model.WearUnusedAppsViewModel
+
+@Composable
+fun WearUnusedAppsScreen(viewModel: WearUnusedAppsViewModel) {
+ val loading = viewModel.loadingLiveData.observeAsState(true)
+ val unusedPeriodCategoryVisibilities =
+ viewModel.unusedPeriodCategoryVisibilitiesLiveData.observeAsState(emptyList())
+ val infoMsgCategoryVisibility =
+ viewModel.infoMsgCategoryVisibilityLiveData.observeAsState(false)
+ val unusedAppChips = viewModel.unusedAppChipsLiveData.observeAsState(mutableMapOf())
+
+ ScrollableScreen(
+ showTimeText = true,
+ title = getScreenTitle(),
+ isLoading = loading.value,
+ subtitle = getSubTitle(!infoMsgCategoryVisibility.value)
+ ) {
+ for (period in allPeriods) {
+ if (!unusedAppChips.value.containsKey(period)) {
+ continue
+ }
+ item {
+ val pos = posByPeriod(period)
+ if (unusedPeriodCategoryVisibilities.value.getOrElse(pos) { false }) {
+ Text(text = categoryTitleByPeriod(period))
+ }
+ }
+ for (unusedAppChip in unusedAppChips.value[period]!!.values) {
+ item {
+ Chip(
+ label = unusedAppChip.label,
+ secondaryLabel = unusedAppChip.summary,
+ icon = unusedAppChip.icon,
+ iconContentDescription = unusedAppChip.contentDescription,
+ onClick = unusedAppChip.onClick
+ )
+ }
+ }
+ }
+ // For info_msg_category
+ if (infoMsgCategoryVisibility.value) {
+ item { Icon(icon = R.drawable.ic_info_outline, contentDescription = null) }
+ if (isHibernationEnabled()) {
+ item { Text(text = stringResource(R.string.unused_apps_page_summary)) }
+ } else {
+ item { Text(text = stringResource(R.string.auto_revoked_apps_page_summary)) }
+ item { Text(text = stringResource(R.string.auto_revoke_open_app_message)) }
+ }
+ }
+ }
+}
+
+@Composable
+private fun getScreenTitle() =
+ if (isHibernationEnabled()) {
+ stringResource(R.string.unused_apps_page_title)
+ } else {
+ stringResource(R.string.permission_removed_page_title)
+ }
+
+@Composable
+private fun getSubTitle(shouldShow: Boolean) =
+ if (shouldShow) {
+ stringResource(R.string.no_unused_apps)
+ } else {
+ null
+ }
+
+@Composable
+private fun posByPeriod(period: UnusedPeriod) =
+ when (period) {
+ UnusedPeriod.ONE_MONTH -> 0
+ UnusedPeriod.THREE_MONTHS -> 1
+ UnusedPeriod.SIX_MONTHS -> 2
+ }
+
+@Composable
+private fun categoryTitleByPeriod(period: UnusedPeriod) =
+ MessageFormat.format(
+ stringResource(R.string.last_opened_category_title),
+ mapOf("count" to period.months)
+ )
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUtils.kt
new file mode 100644
index 000000000..53d41f7f0
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearUtils.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear
+
+import android.content.Context
+import android.text.format.DateFormat
+import androidx.annotation.IntDef
+import com.android.permissioncontroller.R
+import java.time.ZonedDateTime
+import java.time.temporal.ChronoUnit
+
+object WearUtils {
+ @Retention(AnnotationRetention.SOURCE)
+ @IntDef(value = [LAST_24H_TODAY, LAST_24H_YESTERDAY, LAST_7D, NOT_IN_LAST_7D])
+ annotation class AppPermsLastAccessType
+
+ const val LAST_24H_TODAY = 1
+ const val LAST_24H_YESTERDAY = 2
+ const val LAST_7D = 3
+ const val NOT_IN_LAST_7D = 4
+
+ /** Get the preference summary in app permission groups and permission apps screens for Wear. */
+ @JvmStatic
+ fun getPreferenceSummary(context: Context, lastAccessTime: Long?): String {
+ val summaryTimestamp = getPermissionLastAccessSummaryTimestamp(lastAccessTime, context)
+ val res = context.resources
+ return when (summaryTimestamp.second) {
+ LAST_24H_TODAY ->
+ res.getString(R.string.wear_app_perms_24h_access, summaryTimestamp.first)
+ LAST_24H_YESTERDAY ->
+ res.getString(R.string.wear_app_perms_24h_access_yest, summaryTimestamp.first)
+ LAST_7D ->
+ res.getString(
+ R.string.wear_app_perms_7d_access,
+ summaryTimestamp.third,
+ summaryTimestamp.first
+ )
+ else -> ""
+ }
+ }
+
+ @JvmStatic
+ private fun getPermissionLastAccessSummaryTimestamp(
+ lastAccessTime: Long?,
+ context: Context
+ ): Triple<String, Int, String> {
+ val midnightToday =
+ (ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS).toEpochSecond() * 1000L)
+ val midnightYesterday =
+ ZonedDateTime.now().minusDays(1).truncatedTo(ChronoUnit.DAYS).toEpochSecond() * 1000L
+ val isLastAccessToday = (lastAccessTime != null && midnightToday <= lastAccessTime)
+ val isLastAccessTodayOrYesterday =
+ (lastAccessTime != null && midnightYesterday <= lastAccessTime)
+ var lastAccessTimeFormatted = ""
+ var lastAccessDateFormatted = ""
+ @AppPermsLastAccessType var lastAccessType = NOT_IN_LAST_7D
+ if (lastAccessTime != null) {
+ lastAccessTimeFormatted = DateFormat.getTimeFormat(context).format(lastAccessTime)
+ lastAccessDateFormatted = DateFormat.getDateFormat(context).format(lastAccessTime)
+ lastAccessType =
+ if (isLastAccessToday) LAST_24H_TODAY
+ else if (isLastAccessTodayOrYesterday) LAST_24H_YESTERDAY else LAST_7D
+ }
+ return Triple(lastAccessTimeFormatted, lastAccessType, lastAccessDateFormatted)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AdjustChipHeightToFontScale.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AdjustChipHeightToFontScale.kt
new file mode 100644
index 000000000..4d66e6a1b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AdjustChipHeightToFontScale.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import androidx.compose.foundation.layout.height
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/** Adjusts height of the chip as per the font scale. */
+public fun Modifier.adjustChipHeightToFontScale(fontScale: Float, padding: Dp = 0.dp): Modifier =
+ if (fontScale > 1) {
+ this.then(Modifier.height(60.dp + padding))
+ } else {
+ this
+ }
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt
new file mode 100644
index 000000000..d0bbe25f6
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.gestures.animateScrollBy
+import androidx.compose.foundation.gestures.scrollBy
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.input.rotary.onRotaryScrollEvent
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.wear.compose.foundation.lazy.ScalingLazyListState
+import androidx.wear.compose.material.ButtonDefaults
+import androidx.wear.compose.material.Icon
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.dialog.Alert
+import androidx.wear.compose.material.dialog.Dialog
+import kotlinx.coroutines.launch
+
+/**
+ * This component is an alternative to [Alert], providing the following:
+ * - a convenient way of passing a title and a message;
+ * - default positive and negative buttons;
+ * - wrapped in a [Dialog];
+ */
+@Composable
+fun AlertDialog(
+ message: String,
+ iconRes: Int? = null,
+ onCancelButtonClick: () -> Unit,
+ onOKButtonClick: () -> Unit,
+ showDialog: Boolean,
+ scalingLazyListState: ScalingLazyListState,
+ modifier: Modifier = Modifier,
+ title: String = "",
+ okButtonContentDescription: String = stringResource(android.R.string.ok),
+ cancelButtonContentDescription: String = stringResource(android.R.string.cancel)
+) {
+ Dialog(
+ showDialog = showDialog,
+ onDismissRequest = onCancelButtonClick,
+ scrollState = scalingLazyListState,
+ modifier = modifier
+ ) {
+ Alert(
+ title = title,
+ iconRes = iconRes,
+ body = message,
+ scrollState = scalingLazyListState,
+ onCancelButtonClick = onCancelButtonClick,
+ onOKButtonClick = onOKButtonClick,
+ okButtonContentDescription = okButtonContentDescription,
+ cancelButtonContentDescription = cancelButtonContentDescription
+ )
+ }
+}
+
+/**
+ * This component is an alternative to [Alert], providing the following:
+ * - a convenient way of passing a title and a message;
+ * - default one button;
+ * - wrapped in a [Dialog];
+ */
+@Composable
+fun SingleButtonAlertDialog(
+ message: String,
+ iconRes: Int? = null,
+ onButtonClick: () -> Unit,
+ showDialog: Boolean,
+ scalingLazyListState: ScalingLazyListState,
+ modifier: Modifier = Modifier,
+ title: String = "",
+ buttonContentDescription: String = stringResource(android.R.string.ok)
+) {
+ Dialog(
+ showDialog = showDialog,
+ onDismissRequest = {},
+ scrollState = scalingLazyListState,
+ modifier = modifier
+ ) {
+ SingleButtonAlert(
+ title = title,
+ iconRes = iconRes,
+ body = message,
+ scrollState = scalingLazyListState,
+ onButtonClick = onButtonClick,
+ buttonContentDescription = buttonContentDescription
+ )
+ }
+}
+
+@Composable
+internal fun Alert(
+ title: String,
+ iconRes: Int? = null,
+ body: String,
+ scrollState: ScalingLazyListState,
+ onCancelButtonClick: () -> Unit,
+ onOKButtonClick: () -> Unit,
+ okButtonContentDescription: String,
+ cancelButtonContentDescription: String
+) {
+ val focusRequester = remember { FocusRequester() }
+ val coroutineScope = rememberCoroutineScope()
+ Alert(
+ modifier =
+ Modifier.onRotaryScrollEvent {
+ coroutineScope.launch {
+ scrollState.scrollBy(it.verticalScrollPixels)
+ scrollState.animateScrollBy(0f)
+ }
+ true
+ }
+ .focusRequester(focusRequester)
+ .focusable(),
+ contentPadding = DefaultContentPadding(),
+ scrollState = scrollState,
+ title = { AlertTitleText(title) },
+ icon = { AlertIcon(iconRes) },
+ content = { AlertBodyText(body) },
+ negativeButton = { NegativeButton(onCancelButtonClick, cancelButtonContentDescription) },
+ positiveButton = { PositiveButton(onOKButtonClick, okButtonContentDescription) }
+ )
+ RequestFocusOnResume(focusRequester = focusRequester)
+}
+
+@Composable
+private fun RequestFocusOnResume(focusRequester: FocusRequester) {
+ val lifecycleOwner = LocalLifecycleOwner.current
+ LaunchedEffect(Unit) {
+ lifecycleOwner.repeatOnLifecycle(state = Lifecycle.State.RESUMED) {
+ focusRequester.requestFocus()
+ }
+ }
+}
+
+@Composable
+private fun SingleButtonAlert(
+ title: String,
+ iconRes: Int? = null,
+ body: String,
+ scrollState: ScalingLazyListState,
+ isOkButton: Boolean = true,
+ onButtonClick: () -> Unit,
+ buttonContentDescription: String,
+) {
+ Alert(
+ contentPadding = DefaultContentPadding(),
+ title = { AlertTitleText(title) },
+ scrollState = scrollState,
+ icon = { AlertIcon(iconRes) },
+ message = { AlertBodyText(body) }
+ ) {
+ item {
+ if (isOkButton) {
+ PositiveButton(onButtonClick, buttonContentDescription)
+ } else {
+ NegativeButton(onButtonClick, buttonContentDescription)
+ }
+ }
+ }
+}
+
+@Composable private fun DefaultContentPadding() = PaddingValues(top = 24.dp, bottom = 24.dp)
+
+@Composable
+private fun AlertTitleText(title: String) =
+ Text(
+ text = title,
+ color = MaterialTheme.colors.onBackground,
+ textAlign = TextAlign.Center,
+ maxLines = 3,
+ style = MaterialTheme.typography.title3
+ )
+
+@Composable
+private fun AlertIcon(iconRes: Int?) =
+ if (iconRes != null && iconRes != 0) {
+ Icon(painter = painterResource(iconRes), contentDescription = null)
+ } else {
+ null
+ }
+
+@Composable
+private fun AlertBodyText(body: String) =
+ Text(
+ text = body,
+ color = MaterialTheme.colors.onBackground,
+ textAlign = TextAlign.Center,
+ style = MaterialTheme.typography.body2
+ )
+
+@Composable
+private fun PositiveButton(onClick: () -> Unit, contentDescription: String) =
+ Button(
+ imageVector = Icons.Default.Check,
+ contentDescription = contentDescription,
+ onClick = onClick
+ )
+
+@Composable
+private fun NegativeButton(onClick: () -> Unit, contentDescription: String) =
+ Button(
+ imageVector = Icons.Default.Close,
+ contentDescription = contentDescription,
+ onClick = onClick,
+ colors = ButtonDefaults.secondaryButtonColors()
+ )
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AnnotatedText.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AnnotatedText.kt
new file mode 100644
index 000000000..aca39b497
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AnnotatedText.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import android.text.Spanned
+import android.text.style.ClickableSpan
+import android.view.View
+import androidx.compose.foundation.text.ClickableText
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.style.TextDecoration
+import androidx.wear.compose.material.MaterialTheme
+
+const val CLICKABLE_SPAN_TAG = "CLICKABLE_SPAN_TAG"
+
+@Composable
+fun AnnotatedText(text: CharSequence, style: TextStyle, modifier: Modifier = Modifier) {
+ val onClickCallbacks = mutableMapOf<String, (View) -> Unit>()
+ val annotatedString = spannableStringToAnnotatedString(text, onClickCallbacks)
+ val context = LocalContext.current
+ ClickableText(text = annotatedString, style = style, modifier = modifier) { offset ->
+ // Fires the onClickCallback at the clicked position.
+ // It's tricky to send an empty view over the parameter, but no way to get the proper one.
+ // Need to improve to use it in common.
+ annotatedString
+ .getStringAnnotations(CLICKABLE_SPAN_TAG, offset, offset)
+ .firstOrNull()
+ ?.let { onClickCallbacks.get(it.item)?.invoke(View(context)) }
+ }
+}
+
+@Composable
+private fun spannableStringToAnnotatedString(
+ text: CharSequence,
+ onClickCallbacks: MutableMap<String, (View) -> Unit>,
+ spanColor: Color = MaterialTheme.colors.primary
+) =
+ if (text is Spanned) {
+ buildAnnotatedString {
+ append((text.toString()))
+ for (span in text.getSpans(0, text.length, Any::class.java)) {
+ val start = text.getSpanStart(span)
+ val end = text.getSpanEnd(span)
+ when (span) {
+ is ClickableSpan ->
+ addClickableSpan(span, spanColor, start, end, onClickCallbacks)
+ else -> addStyle(SpanStyle(), start, end)
+ }
+ }
+ }
+ } else {
+ AnnotatedString(text.toString())
+ }
+
+private fun AnnotatedString.Builder.addClickableSpan(
+ span: ClickableSpan,
+ spanColor: Color,
+ start: Int,
+ end: Int,
+ onClickCallbacks: MutableMap<String, (View) -> Unit>
+) {
+ addStyle(
+ SpanStyle(color = spanColor, textDecoration = TextDecoration.Underline),
+ start,
+ end,
+ )
+ val key = "${CLICKABLE_SPAN_TAG}:$start:$end"
+ onClickCallbacks[key] = span::onClick
+ addStringAnnotation(CLICKABLE_SPAN_TAG, key, start, end)
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Button.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Button.kt
new file mode 100644
index 000000000..1394c56ea
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Button.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import androidx.annotation.DrawableRes
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.Dp
+import androidx.wear.compose.material.Button
+import androidx.wear.compose.material.ButtonColors
+import androidx.wear.compose.material.ButtonDefaults
+import androidx.wear.compose.material.ButtonDefaults.DefaultButtonSize
+import androidx.wear.compose.material.ButtonDefaults.DefaultIconSize
+import androidx.wear.compose.material.ButtonDefaults.LargeButtonSize
+import androidx.wear.compose.material.ButtonDefaults.LargeIconSize
+import androidx.wear.compose.material.ButtonDefaults.SmallButtonSize
+import androidx.wear.compose.material.ButtonDefaults.SmallIconSize
+
+/**
+ * This component is an alternative to [Button], providing the following:
+ * - a convenient way of providing an icon and choosing its size from a range of sizes recommended
+ * by the Wear guidelines;
+ */
+@Composable
+public fun Button(
+ imageVector: ImageVector,
+ contentDescription: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ colors: ButtonColors = ButtonDefaults.primaryButtonColors(),
+ buttonSize: ButtonSize = ButtonSize.Default,
+ iconRtlMode: IconRtlMode = IconRtlMode.Default,
+ enabled: Boolean = true
+) {
+ Button(
+ icon = imageVector,
+ contentDescription = contentDescription,
+ onClick = onClick,
+ modifier = modifier,
+ colors = colors,
+ buttonSize = buttonSize,
+ iconRtlMode = iconRtlMode,
+ enabled = enabled
+ )
+}
+
+/**
+ * This component is an alternative to [Button], providing the following:
+ * - a convenient way of providing an icon and choosing its size from a range of sizes recommended
+ * by the Wear guidelines;
+ */
+@Composable
+public fun Button(
+ @DrawableRes id: Int,
+ contentDescription: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ colors: ButtonColors = ButtonDefaults.primaryButtonColors(),
+ buttonSize: ButtonSize = ButtonSize.Default,
+ iconRtlMode: IconRtlMode = IconRtlMode.Default,
+ enabled: Boolean = true
+) {
+ Button(
+ icon = id,
+ contentDescription = contentDescription,
+ onClick = onClick,
+ modifier = modifier,
+ colors = colors,
+ buttonSize = buttonSize,
+ iconRtlMode = iconRtlMode,
+ enabled = enabled
+ )
+}
+
+@Composable
+internal fun Button(
+ icon: Any,
+ contentDescription: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ colors: ButtonColors = ButtonDefaults.primaryButtonColors(),
+ buttonSize: ButtonSize = ButtonSize.Default,
+ iconRtlMode: IconRtlMode = IconRtlMode.Default,
+ enabled: Boolean = true
+) {
+ Button(
+ onClick = onClick,
+ modifier = modifier.size(buttonSize.tapTargetSize),
+ enabled = enabled,
+ colors = colors
+ ) {
+ val iconModifier = Modifier.size(buttonSize.iconSize).align(Alignment.Center)
+
+ Icon(
+ icon = icon,
+ contentDescription = contentDescription,
+ modifier = iconModifier,
+ rtlMode = iconRtlMode
+ )
+ }
+}
+
+public sealed class ButtonSize(public val iconSize: Dp, public val tapTargetSize: Dp) {
+ public object Default :
+ ButtonSize(iconSize = DefaultIconSize, tapTargetSize = DefaultButtonSize)
+
+ public object Large : ButtonSize(iconSize = LargeIconSize, tapTargetSize = LargeButtonSize)
+ public object Small : ButtonSize(iconSize = SmallIconSize, tapTargetSize = SmallButtonSize)
+
+ /**
+ * Custom sizes should follow the
+ * [accessibility principles and guidance for touch targets](https://developer.android.com/training/wearables/accessibility#set-minimum).
+ */
+ public data class Custom(val customIconSize: Dp, val customTapTargetSize: Dp) :
+ ButtonSize(iconSize = customIconSize, tapTargetSize = customTapTargetSize)
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Chip.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Chip.kt
new file mode 100644
index 000000000..bf9ebbadd
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Chip.kt
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import android.graphics.drawable.Drawable
+import androidx.annotation.StringRes
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material.Chip
+import androidx.wear.compose.material.ChipColors
+import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.ContentAlpha
+import androidx.wear.compose.material.Icon
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.contentColorFor
+import com.android.permissioncontroller.R
+
+/**
+ * This component is an alternative to [Chip], providing the following:
+ * - a convenient way of providing a label and a secondary label;
+ * - a convenient way of providing an icon, and choosing their size based on the sizes recommended
+ * by the Wear guidelines;
+ */
+@Composable
+public fun Chip(
+ label: String,
+ labelMaxLines: Int? = null,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ secondaryLabel: String? = null,
+ secondaryLabelMaxLines: Int? = null,
+ icon: Any? = null,
+ iconContentDescription: String? = null,
+ largeIcon: Boolean = false,
+ textColor: Color = MaterialTheme.colors.onSurface,
+ iconColor: Color = Color.Unspecified,
+ colors: ChipColors = chipDefaultColors(),
+ enabled: Boolean = true
+) {
+ val iconParam: (@Composable BoxScope.() -> Unit)? =
+ icon?.let {
+ {
+ val iconSize =
+ if (largeIcon) {
+ ChipDefaults.LargeIconSize
+ } else {
+ ChipDefaults.IconSize
+ }
+
+ Row {
+ val iconModifier = Modifier.size(iconSize).clip(CircleShape)
+ when (icon) {
+ is ImageVector ->
+ Icon(
+ imageVector = icon,
+ tint = iconColor,
+ contentDescription = iconContentDescription,
+ modifier = iconModifier
+ )
+ is Int ->
+ Icon(
+ painter = painterResource(id = icon),
+ tint = iconColor,
+ contentDescription = iconContentDescription,
+ modifier = iconModifier
+ )
+ is Drawable ->
+ Icon(
+ painter = rememberDrawablePainter(icon),
+ tint = iconColor,
+ contentDescription = iconContentDescription,
+ modifier = iconModifier
+ )
+ else -> {}
+ }
+ }
+ }
+ }
+
+ Chip(
+ label = label,
+ labelMaxLines = labelMaxLines,
+ onClick = onClick,
+ modifier = modifier,
+ secondaryLabel = secondaryLabel,
+ secondaryLabelMaxLines = secondaryLabelMaxLines,
+ icon = iconParam,
+ largeIcon = largeIcon,
+ textColor = textColor,
+ colors = colors,
+ enabled = enabled
+ )
+}
+
+/**
+ * This component is an alternative to [Chip], providing the following:
+ * - a convenient way of providing a label and a secondary label;
+ * - a convenient way of providing an icon, and choosing their size based on the sizes recommended
+ * by the Wear guidelines;
+ */
+@Composable
+public fun Chip(
+ @StringRes labelId: Int,
+ labelMaxLines: Int? = null,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ @StringRes secondaryLabel: Int? = null,
+ secondaryLabelMaxLines: Int? = null,
+ icon: Any? = null,
+ largeIcon: Boolean = false,
+ textColor: Color = MaterialTheme.colors.onSurface,
+ iconColor: Color = Color.Unspecified,
+ colors: ChipColors = chipDefaultColors(),
+ enabled: Boolean = true
+) {
+ Chip(
+ label = stringResource(id = labelId),
+ labelMaxLines = labelMaxLines,
+ onClick = onClick,
+ modifier = modifier,
+ secondaryLabel = secondaryLabel?.let { stringResource(id = it) },
+ secondaryLabelMaxLines = secondaryLabelMaxLines,
+ icon = icon,
+ largeIcon = largeIcon,
+ textColor = textColor,
+ iconColor = iconColor,
+ colors = colors,
+ enabled = enabled
+ )
+}
+
+/**
+ * This component is an alternative to [Chip], providing the following:
+ * - a convenient way of providing a label and a secondary label;
+ */
+@Composable
+public fun Chip(
+ label: String,
+ labelMaxLines: Int? = null,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ secondaryLabel: String? = null,
+ secondaryLabelMaxLines: Int? = null,
+ icon: (@Composable BoxScope.() -> Unit)? = null,
+ largeIcon: Boolean = false,
+ textColor: Color = MaterialTheme.colors.onSurface,
+ secondaryTextColor: Color = colorResource(R.color.wear_material_gray_600),
+ colors: ChipColors = chipDefaultColors(),
+ enabled: Boolean = true
+) {
+ val hasSecondaryLabel = secondaryLabel != null
+ val hasIcon = icon != null
+
+ val labelParam: (@Composable RowScope.() -> Unit) = {
+ Text(
+ text = label,
+ color = textColor,
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = if (hasSecondaryLabel || hasIcon) TextAlign.Start else TextAlign.Center,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = labelMaxLines ?: if (hasSecondaryLabel) 1 else 2,
+ style = MaterialTheme.typography.button
+ )
+ }
+
+ val secondaryLabelParam: (@Composable RowScope.() -> Unit)? =
+ secondaryLabel?.let {
+ {
+ Text(
+ text = secondaryLabel,
+ color = secondaryTextColor,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = secondaryLabelMaxLines ?: 1,
+ style = MaterialTheme.typography.caption2
+ )
+ }
+ }
+
+ val contentPadding =
+ if (largeIcon) {
+ val verticalPadding = ChipDefaults.ChipVerticalPadding
+ PaddingValues(
+ start = 10.dp,
+ top = verticalPadding,
+ end = ChipDefaults.ChipHorizontalPadding,
+ bottom = verticalPadding
+ )
+ } else {
+ ChipDefaults.ContentPadding
+ }
+
+ Chip(
+ label = labelParam,
+ onClick = onClick,
+ modifier =
+ modifier
+ .adjustChipHeightToFontScale(LocalConfiguration.current.fontScale)
+ .fillMaxWidth(),
+ secondaryLabel = secondaryLabelParam,
+ icon = icon,
+ colors = colors,
+ enabled = enabled,
+ contentPadding = contentPadding,
+ shape = RoundedCornerShape(26.dp)
+ )
+}
+
+/** Default colors of a Chip. */
+@Composable fun chipDefaultColors(): ChipColors = ChipDefaults.secondaryChipColors()
+
+/**
+ * ChipColors that disabled alpha is applied based on [ChipDefaults.secondaryChipColors()]. It is
+ * used for a Chip which would like to respond to click events, meanwhile it seems disabled.
+ */
+@Composable
+fun chipDisabledColors(): ChipColors {
+ val backgroundColor = MaterialTheme.colors.surface
+ val contentColor = contentColorFor(backgroundColor)
+ val secondaryContentColor = contentColor
+ val iconColor = contentColor
+
+ return ChipDefaults.chipColors(
+ backgroundColor = backgroundColor.copy(alpha = ContentAlpha.disabled),
+ contentColor = contentColor.copy(alpha = ContentAlpha.disabled),
+ secondaryContentColor = secondaryContentColor.copy(alpha = ContentAlpha.disabled),
+ iconColor = iconColor.copy(alpha = ContentAlpha.disabled)
+ )
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/DrawablePainter.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/DrawablePainter.kt
new file mode 100644
index 000000000..d505a0ea4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/DrawablePainter.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import android.graphics.drawable.Animatable
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import android.view.View
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.RememberObserver
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.asAndroidColorFilter
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.nativeCanvas
+import androidx.compose.ui.graphics.painter.ColorPainter
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.graphics.withSave
+import androidx.compose.ui.unit.LayoutDirection
+import kotlin.math.roundToInt
+
+private val MAIN_HANDLER by lazy(LazyThreadSafetyMode.NONE) { Handler(Looper.getMainLooper()) }
+
+/**
+ * A [Painter] which draws an Android [Drawable] and supports [Animatable] drawables. Instances
+ * should be remembered to be able to start and stop [Animatable] animations.
+ *
+ * Instances are usually retrieved from [rememberDrawablePainter].
+ */
+class DrawablePainter(val drawable: Drawable) : Painter(), RememberObserver {
+ private var drawInvalidateTick by mutableStateOf(0)
+ private var drawableIntrinsicSize by mutableStateOf(drawable.intrinsicSize)
+
+ private val callback: Drawable.Callback by lazy {
+ object : Drawable.Callback {
+ override fun invalidateDrawable(d: Drawable) {
+ // Update the tick so that we get re-drawn
+ drawInvalidateTick++
+ // Update our intrinsic size too
+ drawableIntrinsicSize = drawable.intrinsicSize
+ }
+
+ override fun scheduleDrawable(d: Drawable, what: Runnable, time: Long) {
+ MAIN_HANDLER.postAtTime(what, time)
+ }
+
+ override fun unscheduleDrawable(d: Drawable, what: Runnable) {
+ MAIN_HANDLER.removeCallbacks(what)
+ }
+ }
+ }
+
+ init {
+ if (drawable.intrinsicWidth >= 0 && drawable.intrinsicHeight >= 0) {
+ // Update the drawable's bounds to match the intrinsic size
+ drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
+ }
+ }
+
+ override fun onRemembered() {
+ drawable.callback = callback
+ drawable.setVisible(true, true)
+ if (drawable is Animatable) drawable.start()
+ }
+
+ override fun onAbandoned() = onForgotten()
+
+ override fun onForgotten() {
+ if (drawable is Animatable) drawable.stop()
+ drawable.setVisible(false, false)
+ drawable.callback = null
+ }
+
+ override fun applyAlpha(alpha: Float): Boolean {
+ drawable.alpha = (alpha * 255).roundToInt().coerceIn(0, 255)
+ return true
+ }
+
+ override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {
+ drawable.colorFilter = colorFilter?.asAndroidColorFilter()
+ return true
+ }
+
+ override fun applyLayoutDirection(layoutDirection: LayoutDirection): Boolean {
+ if (Build.VERSION.SDK_INT >= 23) {
+ return drawable.setLayoutDirection(
+ when (layoutDirection) {
+ LayoutDirection.Ltr -> View.LAYOUT_DIRECTION_LTR
+ LayoutDirection.Rtl -> View.LAYOUT_DIRECTION_RTL
+ }
+ )
+ }
+ return false
+ }
+
+ override val intrinsicSize: Size
+ get() = drawableIntrinsicSize
+
+ override fun DrawScope.onDraw() {
+ drawIntoCanvas { canvas ->
+ // Reading this ensures that we invalidate when invalidateDrawable() is called
+ drawInvalidateTick
+
+ // Update the Drawable's bounds
+ drawable.setBounds(0, 0, size.width.roundToInt(), size.height.roundToInt())
+
+ canvas.withSave { drawable.draw(canvas.nativeCanvas) }
+ }
+ }
+}
+
+/**
+ * Remembers [Drawable] wrapped up as a [Painter]. This function attempts to un-wrap the drawable
+ * contents and use Compose primitives where possible.
+ *
+ * If the provided [drawable] is `null`, an empty no-op painter is returned.
+ *
+ * This function tries to dispatch lifecycle events to [drawable] as much as possible from within
+ * Compose.
+ */
+@Composable
+fun rememberDrawablePainter(drawable: Drawable?): Painter =
+ remember(drawable) {
+ when (drawable) {
+ null -> EmptyPainter
+ is ColorDrawable -> ColorPainter(Color(drawable.color))
+ // Since the DrawablePainter will be remembered and it implements RememberObserver, it
+ // will receive the necessary events
+ else -> DrawablePainter(drawable.mutate())
+ }
+ }
+
+private val Drawable.intrinsicSize: Size
+ get() =
+ when {
+ // Only return a finite size if the drawable has an intrinsic size
+ intrinsicWidth >= 0 && intrinsicHeight >= 0 -> {
+ Size(width = intrinsicWidth.toFloat(), height = intrinsicHeight.toFloat())
+ }
+ else -> Size.Unspecified
+ }
+
+internal object EmptyPainter : Painter() {
+ override val intrinsicSize: Size
+ get() = Size.Unspecified
+ override fun DrawScope.onDraw() {}
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Icon.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Icon.kt
new file mode 100644
index 000000000..1a304b37e
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/Icon.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import android.graphics.drawable.Drawable
+import androidx.annotation.DrawableRes
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.scale
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.wear.compose.material.Icon
+import androidx.wear.compose.material.LocalContentAlpha
+import androidx.wear.compose.material.LocalContentColor
+
+/**
+ * This component is an alternative to [Icon], providing the following:
+ * - a convenient way of setting the icon to be mirrored in RTL mode;
+ */
+@Composable
+public fun Icon(
+ imageVector: ImageVector,
+ contentDescription: String?,
+ modifier: Modifier = Modifier,
+ tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
+ rtlMode: IconRtlMode = IconRtlMode.Default
+) {
+ val shouldMirror =
+ rtlMode == IconRtlMode.Mirrored && LocalLayoutDirection.current == LayoutDirection.Rtl
+ Icon(
+ modifier = modifier.scale(scaleX = if (shouldMirror) -1f else 1f, scaleY = 1f),
+ imageVector = imageVector,
+ contentDescription = contentDescription,
+ tint = tint
+ )
+}
+
+/**
+ * This component is an alternative to [Icon], providing the following:
+ * - a convenient way of setting the icon to be mirrored in RTL mode;
+ */
+@Composable
+public fun Icon(
+ @DrawableRes id: Int,
+ contentDescription: String?,
+ modifier: Modifier = Modifier,
+ tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
+ rtlMode: IconRtlMode = IconRtlMode.Default
+) {
+ val shouldMirror =
+ rtlMode == IconRtlMode.Mirrored && LocalLayoutDirection.current == LayoutDirection.Rtl
+
+ Icon(
+ painter = painterResource(id = id),
+ contentDescription = contentDescription,
+ modifier = modifier.scale(scaleX = if (shouldMirror) -1f else 1f, scaleY = 1f),
+ tint = tint
+ )
+}
+
+/**
+ * This component is an alternative to [Icon], providing the following:
+ * - a convenient way of providing an icon of various types
+ * - a convenient way of setting the icon to be mirrored in RTL mode;
+ */
+@Composable
+fun Icon(
+ icon: Any,
+ contentDescription: String?,
+ modifier: Modifier = Modifier,
+ tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
+ rtlMode: IconRtlMode = IconRtlMode.Default
+) {
+ val shouldMirror =
+ rtlMode == IconRtlMode.Mirrored && LocalLayoutDirection.current == LayoutDirection.Rtl
+
+ val iconModifier = modifier.scale(scaleX = if (shouldMirror) -1f else 1f, scaleY = 1f)
+ when (icon) {
+ is ImageVector -> {
+ Icon(
+ imageVector = icon,
+ modifier = iconModifier,
+ contentDescription = contentDescription,
+ tint = tint
+ )
+ }
+ is Int -> {
+ Icon(
+ painter = painterResource(id = icon),
+ contentDescription = contentDescription,
+ modifier = iconModifier,
+ tint = tint
+ )
+ }
+ is Drawable -> {
+ Icon(
+ painter = rememberDrawablePainter(icon),
+ contentDescription = contentDescription,
+ modifier = iconModifier,
+ tint = tint
+ )
+ }
+ else -> throw IllegalArgumentException("Type not supported.")
+ }
+}
+
+public enum class IconRtlMode {
+ Default,
+ Mirrored
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ListFooter.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ListFooter.kt
new file mode 100644
index 000000000..5ed912ec6
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ListFooter.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material.Icon
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.Text
+
+/** A slot based composable for creating a list footer item. */
+@Composable
+fun ListFooter(description: String, iconRes: Int? = null, onClick: (() -> Unit)? = null) {
+ val modifier = Modifier.fillMaxWidth()
+ Row(
+ modifier =
+ if (onClick == null) {
+ modifier
+ } else {
+ modifier.clickable(onClick = onClick)
+ }
+ ) {
+ iconRes?.let {
+ Spacer(modifier = Modifier.width(LeadingIconStartSpacing))
+ Icon(
+ painter = painterResource(id = it),
+ contentDescription = null,
+ modifier =
+ Modifier.size(LeadingIconSize, LeadingIconSize)
+ .align(Alignment.CenterVertically)
+ )
+ Spacer(modifier = Modifier.width(LeadingIconEndSpacing))
+ }
+ Text(
+ text = description,
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Start,
+ overflow = TextOverflow.Ellipsis,
+ color = MaterialTheme.colors.onSurfaceVariant,
+ style = MaterialTheme.typography.caption2
+ )
+ }
+}
+
+/** The size of the spacing before the leading icon when they used inside a list footer. */
+private val LeadingIconStartSpacing = 4.dp
+
+/** The size of the spacing between the leading icon and a text inside a list footer. */
+private val LeadingIconEndSpacing = 8.dp
+
+/** The size of the leading icon. */
+private val LeadingIconSize = 24.dp
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ListHeader.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ListHeader.kt
new file mode 100644
index 000000000..0afbb05fe
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ListHeader.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.semantics.heading
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material.LocalContentColor
+import androidx.wear.compose.material.LocalTextStyle
+import androidx.wear.compose.material.MaterialTheme
+
+/**
+ * A slot based composable for creating a list header item. [ListHeader]s are typically expected to
+ * be a few words of text on a single line. The contents will be start and end padded.
+ *
+ * @param modifier The modifier for the [ListHeader].
+ * @param backgroundColor The background color to apply - typically Color.Transparent
+ * @param contentColor The color to apply to content.
+ * @param contentPadding The spacing values to apply internally between the container and the
+ * content.
+ * @param content Slot for [ListHeader] content, expected to be a single line of text.
+ */
+@Composable
+fun ListHeader(
+ modifier: Modifier = Modifier,
+ backgroundColor: Color = Color.Transparent,
+ contentColor: Color = MaterialTheme.colors.onSurfaceVariant,
+ contentPadding: PaddingValues = ListHeaderDefaults.HeaderContentPadding,
+ content: @Composable RowScope.() -> Unit
+) {
+ Row(
+ horizontalArrangement = Arrangement.Center,
+ modifier =
+ modifier
+ .defaultMinSize(minHeight = ListHeaderDefaults.Height)
+ .wrapContentSize()
+ .background(backgroundColor)
+ .padding(contentPadding)
+ .semantics(mergeDescendants = true) { heading() }
+ ) {
+ CompositionLocalProvider(
+ LocalContentColor provides contentColor,
+ LocalTextStyle provides MaterialTheme.typography.title3,
+ ) {
+ content()
+ }
+ }
+}
+
+/**
+ * A two slot based composable for creating a list subheader item. [ListSubheader]s offer slots for
+ * an icon and for a text label. The contents will be start and end padded.
+ *
+ * @param modifier The modifier for the [ListSubheader].
+ * @param backgroundColor The background color to apply - typically Color.Transparent
+ * @param contentColor The color to apply to content.
+ * @param contentPadding The spacing values to apply internally between the container and the
+ * content.
+ * @param icon A slot for providing icon to the [ListSubheader].
+ * @param label A slot for providing label to the [ListSubheader].
+ */
+@Composable
+fun ListSubheader(
+ modifier: Modifier = Modifier,
+ backgroundColor: Color = Color.Transparent,
+ contentColor: Color = MaterialTheme.colors.onBackground,
+ contentPadding: PaddingValues = ListHeaderDefaults.SubheaderContentPadding,
+ icon: (@Composable BoxScope.() -> Unit)? = null,
+ label: @Composable RowScope.() -> Unit,
+) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Start,
+ modifier =
+ modifier
+ .defaultMinSize(minHeight = ListHeaderDefaults.Height)
+ .height(IntrinsicSize.Min)
+ .fillMaxWidth()
+ .wrapContentSize(align = Alignment.CenterStart)
+ .background(backgroundColor)
+ .padding(contentPadding)
+ .semantics(mergeDescendants = true) { heading() }
+ ) {
+ CompositionLocalProvider(
+ LocalContentColor provides contentColor,
+ LocalTextStyle provides MaterialTheme.typography.caption1,
+ ) {
+ if (icon != null) {
+ Box(
+ modifier = Modifier.wrapContentSize(align = Alignment.CenterStart),
+ content = icon
+ )
+ Spacer(modifier = Modifier.width(6.dp))
+ }
+ label()
+ }
+ }
+}
+
+object ListHeaderDefaults {
+ private val TopPadding = 16.dp
+ private val SubheaderBottomPadding = 8.dp
+ private val HeaderBottomPadding = 12.dp
+ private val HorizontalPadding = 14.dp
+ internal val Height = 48.dp
+
+ val HeaderContentPadding =
+ PaddingValues(HorizontalPadding, TopPadding, HorizontalPadding, HeaderBottomPadding)
+ val SubheaderContentPadding =
+ PaddingValues(HorizontalPadding, TopPadding, HorizontalPadding, SubheaderBottomPadding)
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt
new file mode 100644
index 000000000..47b5e2ad1
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import android.app.Activity
+import android.content.Context
+import android.content.ContextWrapper
+import android.graphics.drawable.Drawable
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.gestures.animateScrollBy
+import androidx.compose.foundation.gestures.scrollBy
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.input.rotary.onRotaryScrollEvent
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.testTagsAsResourceId
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.wear.compose.foundation.SwipeToDismissValue
+import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
+import androidx.wear.compose.foundation.lazy.ScalingLazyListScope
+import androidx.wear.compose.foundation.lazy.ScalingLazyListState
+import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
+import androidx.wear.compose.material.CircularProgressIndicator
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.PositionIndicator
+import androidx.wear.compose.material.Scaffold
+import androidx.wear.compose.material.SwipeToDismissBox
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.TimeText
+import androidx.wear.compose.material.Vignette
+import androidx.wear.compose.material.VignettePosition
+import androidx.wear.compose.material.scrollAway
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
+import kotlinx.coroutines.launch
+
+/**
+ * Screen that contains a list of items defined using the [content] parameter, adds the time text
+ * (if [showTimeText] is true), the tile (if [title] is not null), the vignette and the position
+ * indicator. It also manages the scaling animation and allows the user to scroll the content using
+ * the crown.
+ */
+@Composable
+fun ScrollableScreen(
+ showTimeText: Boolean = true,
+ title: String? = null,
+ subtitle: CharSequence? = null,
+ image: Any? = null,
+ isLoading: Boolean = false,
+ titleTestTag: String? = null,
+ subtitleTestTag: String? = null,
+ content: ScalingLazyListScope.() -> Unit,
+) {
+ var dismissed by remember { mutableStateOf(false) }
+ val activity = LocalContext.current.findActivity()
+ val state = rememberSwipeToDismissBoxState()
+
+ LaunchedEffect(state.currentValue) {
+ if (state.currentValue == SwipeToDismissValue.Dismissed) {
+ dismiss(activity)
+ dismissed = true
+ state.snapTo(SwipeToDismissValue.Default)
+ }
+ }
+
+ // To support Swipe-dismiss effect,
+ // add the view to SwipeToDismissBox if the screen is not on the top fragment.
+ if (getBackStackEntryCount(activity) > 0) {
+ SwipeToDismissBox(state = state) { isBackground ->
+ Scaffold(
+ showTimeText,
+ title,
+ subtitle,
+ image,
+ isLoading = isLoading || isBackground || dismissed,
+ content,
+ titleTestTag,
+ subtitleTestTag
+ )
+ }
+ } else {
+ Scaffold(
+ showTimeText,
+ title,
+ subtitle,
+ image,
+ isLoading,
+ content,
+ titleTestTag,
+ subtitleTestTag
+ )
+ }
+}
+
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+internal fun Scaffold(
+ showTimeText: Boolean,
+ title: String?,
+ subtitle: CharSequence?,
+ image: Any?,
+ isLoading: Boolean,
+ content: ScalingLazyListScope.() -> Unit,
+ titleTestTag: String? = null,
+ subtitleTestTag: String? = null,
+) {
+ val initialCenterIndex = 0
+ val scrollContentTopPadding = 32.dp
+ val centerHeightDp = Dp(LocalConfiguration.current.screenHeightDp / 2.0f)
+ val initialCenterItemScrollOffset = scrollContentTopPadding + 10.dp
+ val scrollAwayOffset = centerHeightDp - initialCenterItemScrollOffset
+
+ val focusRequester = remember { FocusRequester() }
+ val listState = remember { ScalingLazyListState(initialCenterItemIndex = initialCenterIndex) }
+ val coroutineScope = rememberCoroutineScope()
+
+ WearPermissionTheme {
+ Scaffold(
+ modifier =
+ Modifier.onRotaryScrollEvent {
+ coroutineScope.launch {
+ listState.scrollBy(it.verticalScrollPixels)
+ listState.animateScrollBy(0f)
+ }
+ true
+ }
+ .focusRequester(focusRequester)
+ .focusable()
+ .semantics { testTagsAsResourceId = true },
+ timeText = {
+ if (showTimeText && !isLoading) {
+ TimeText(
+ modifier =
+ Modifier.scrollAway(listState, initialCenterIndex, scrollAwayOffset),
+ contentPadding = PaddingValues(5.dp)
+ )
+ }
+ },
+ vignette = { Vignette(vignettePosition = VignettePosition.TopAndBottom) },
+ positionIndicator = { PositionIndicator(scalingLazyListState = listState) }
+ ) {
+ Box(modifier = Modifier.fillMaxSize()) {
+ if (isLoading) {
+ CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
+ } else {
+ ScalingLazyColumn(
+ state = listState,
+ // Set autoCentering to null to avoid adding extra padding based on the
+ // content.
+ autoCentering = null,
+ contentPadding =
+ PaddingValues(
+ start = 10.dp,
+ end = 10.dp,
+ top = scrollContentTopPadding,
+ bottom = 70.dp
+ )
+ ) {
+ image?.let {
+ val imageModifier = Modifier.size(24.dp)
+ when (image) {
+ is Int ->
+ item {
+ Image(
+ painter = painterResource(id = image),
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ modifier = imageModifier
+ )
+ }
+ is Drawable ->
+ item {
+ Image(
+ painter = rememberDrawablePainter(image),
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ modifier = imageModifier
+ )
+ }
+ else -> {}
+ }
+ }
+ if (title != null) {
+ item {
+ var modifier: Modifier = Modifier
+ if (titleTestTag != null) {
+ modifier = modifier.testTag(titleTestTag)
+ }
+ ListHeader {
+ Text(
+ text = title,
+ textAlign = TextAlign.Center,
+ modifier = modifier
+ )
+ }
+ }
+ }
+ if (subtitle != null) {
+ item {
+ var modifier: Modifier = Modifier
+ if (subtitleTestTag != null) {
+ modifier = modifier.testTag(subtitleTestTag)
+ }
+ AnnotatedText(
+ text = subtitle,
+ style =
+ MaterialTheme.typography.body2.copy(
+ color = MaterialTheme.colors.onSurfaceVariant
+ ),
+ modifier = modifier.fillMaxWidth(),
+ )
+ }
+ }
+
+ content()
+ }
+ RequestFocusOnResume(focusRequester = focusRequester)
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun RequestFocusOnResume(focusRequester: FocusRequester) {
+ val lifecycleOwner = LocalLifecycleOwner.current
+ LaunchedEffect(Unit) {
+ lifecycleOwner.repeatOnLifecycle(state = Lifecycle.State.RESUMED) {
+ focusRequester.requestFocus()
+ }
+ }
+}
+
+internal fun dismiss(activity: Activity) {
+ if (activity is FragmentActivity) {
+ if (!activity.getSupportFragmentManager().popBackStackImmediate()) {
+ activity.finish()
+ }
+ } else {
+ activity.finish()
+ }
+}
+
+internal fun getBackStackEntryCount(activity: Activity): Int {
+ return if (activity is FragmentActivity) {
+ activity
+ .getSupportFragmentManager()
+ .primaryNavigationFragment
+ ?.childFragmentManager
+ ?.backStackEntryCount
+ ?: 0
+ } else {
+ 0
+ }
+}
+
+internal fun Context.findActivity(): Activity {
+ var context = this
+ while (context is ContextWrapper) {
+ if (context is Activity) return context
+ context = context.baseContext
+ }
+ throw IllegalStateException("The screen should be called in the context of an Activity")
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ToggleChip.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ToggleChip.kt
new file mode 100644
index 000000000..9a8a29bc3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ToggleChip.kt
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.compositeOver
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.stateDescription
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.ContentAlpha
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.ToggleChip
+import androidx.wear.compose.material.ToggleChipColors
+import androidx.wear.compose.material.ToggleChipDefaults
+import androidx.wear.compose.material.contentColorFor
+import com.android.permissioncontroller.R
+
+/**
+ * This component is an alternative to [ToggleChip], providing the following:
+ * - a convenient way of providing a label and a secondary label;
+ * - a convenient way of choosing the toggle control;
+ * - a convenient way of providing an icon and setting the icon to be mirrored in RTL mode;
+ */
+@Composable
+public fun ToggleChip(
+ checked: Boolean,
+ onCheckedChanged: (Boolean) -> Unit,
+ label: String,
+ labelMaxLine: Int? = null,
+ toggleControl: ToggleChipToggleControl,
+ modifier: Modifier = Modifier,
+ icon: Any? = null,
+ iconColor: Color = Color.Unspecified,
+ iconRtlMode: IconRtlMode = IconRtlMode.Default,
+ secondaryLabel: String? = null,
+ secondaryLabelMaxLine: Int? = null,
+ colors: ToggleChipColors = ToggleChipDefaults.toggleChipColors(),
+ enabled: Boolean = true,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) {
+ val hasSecondaryLabel = secondaryLabel != null
+
+ val labelParam: (@Composable RowScope.() -> Unit) = {
+ Text(
+ text = label,
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Start,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = labelMaxLine ?: if (hasSecondaryLabel) 1 else 2,
+ style = MaterialTheme.typography.button
+ )
+ }
+
+ val secondaryLabelParam: (@Composable RowScope.() -> Unit)? =
+ secondaryLabel?.let {
+ {
+ Text(
+ text = secondaryLabel,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = secondaryLabelMaxLine ?: 1,
+ style = MaterialTheme.typography.caption2
+ )
+ }
+ }
+
+ val toggleControlParam: (@Composable () -> Unit) = {
+ Icon(
+ imageVector =
+ when (toggleControl) {
+ ToggleChipToggleControl.Switch -> ToggleChipDefaults.switchIcon(checked)
+ ToggleChipToggleControl.Radio -> ToggleChipDefaults.radioIcon(checked)
+ ToggleChipToggleControl.Checkbox -> ToggleChipDefaults.checkboxIcon(checked)
+ },
+ contentDescription = null,
+ // This potentially be removed once this issue is addressed:
+ // https://issuetracker.google.com/issues/287087138
+ rtlMode =
+ if (toggleControl == ToggleChipToggleControl.Switch) {
+ IconRtlMode.Mirrored
+ } else {
+ IconRtlMode.Default
+ }
+ )
+ }
+
+ val iconParam: (@Composable BoxScope.() -> Unit)? =
+ icon?.let {
+ {
+ Row {
+ Icon(
+ icon = icon,
+ tint = iconColor,
+ contentDescription = null,
+ modifier = Modifier.size(ChipDefaults.IconSize).clip(CircleShape),
+ rtlMode = iconRtlMode
+ )
+ }
+ }
+ }
+
+ val stateDescriptionSemantics =
+ stringResource(
+ if (checked) {
+ R.string.on
+ } else {
+ R.string.off
+ }
+ )
+ ToggleChip(
+ checked = checked,
+ onCheckedChange = onCheckedChanged,
+ label = labelParam,
+ toggleControl = toggleControlParam,
+ modifier =
+ modifier
+ .adjustChipHeightToFontScale(LocalConfiguration.current.fontScale)
+ .fillMaxWidth()
+ .semantics { stateDescription = stateDescriptionSemantics },
+ appIcon = iconParam,
+ secondaryLabel = secondaryLabelParam,
+ colors = colors,
+ enabled = enabled,
+ interactionSource = interactionSource
+ )
+}
+
+/**
+ * ToggleChipColors that disabled alpha is applied based on [ToggleChipDefaults.toggleChipColors()].
+ * It is used for a ToggleChip which would like to respond to click events, meanwhile it seems
+ * disabled.
+ */
+@Composable
+fun toggleChipDisabledColors(): ToggleChipColors {
+ val checkedStartBackgroundColor =
+ MaterialTheme.colors.surface.copy(alpha = 0f).compositeOver(MaterialTheme.colors.surface)
+ val checkedEndBackgroundColor =
+ MaterialTheme.colors.primary.copy(alpha = 0.5f).compositeOver(MaterialTheme.colors.surface)
+ val checkedContentColor = MaterialTheme.colors.onSurface
+ val checkedSecondaryContentColor = MaterialTheme.colors.onSurfaceVariant
+ val checkedToggleControlColor = MaterialTheme.colors.secondary
+ val uncheckedStartBackgroundColor = MaterialTheme.colors.surface
+ val uncheckedEndBackgroundColor = uncheckedStartBackgroundColor
+ val uncheckedContentColor = contentColorFor(checkedEndBackgroundColor)
+ val uncheckedSecondaryContentColor = uncheckedContentColor
+ val uncheckedToggleControlColor = uncheckedContentColor
+
+ return ToggleChipDefaults.toggleChipColors(
+ checkedStartBackgroundColor =
+ checkedStartBackgroundColor.copy(alpha = ContentAlpha.disabled),
+ checkedEndBackgroundColor = checkedEndBackgroundColor.copy(alpha = ContentAlpha.disabled),
+ checkedContentColor = checkedContentColor.copy(alpha = ContentAlpha.disabled),
+ checkedSecondaryContentColor =
+ checkedSecondaryContentColor.copy(alpha = ContentAlpha.disabled),
+ checkedToggleControlColor = checkedToggleControlColor.copy(alpha = ContentAlpha.disabled),
+ uncheckedStartBackgroundColor =
+ uncheckedStartBackgroundColor.copy(alpha = ContentAlpha.disabled),
+ uncheckedEndBackgroundColor =
+ uncheckedEndBackgroundColor.copy(alpha = ContentAlpha.disabled),
+ uncheckedContentColor = uncheckedContentColor.copy(alpha = ContentAlpha.disabled),
+ uncheckedSecondaryContentColor =
+ uncheckedSecondaryContentColor.copy(alpha = ContentAlpha.disabled),
+ uncheckedToggleControlColor =
+ uncheckedToggleControlColor.copy(alpha = ContentAlpha.disabled)
+ )
+}
+
+/**
+ * ToggleChipColors that theme background color is applied based on
+ * [ToggleChipDefaults.toggleChipColors()]. It is used for a ToggleChip having the same background
+ * color of the screen.
+ */
+@Composable
+fun toggleChipBackgroundColors(): ToggleChipColors {
+ val checkedStartBackgroundColor =
+ MaterialTheme.colors.background
+ .copy(alpha = 0f)
+ .compositeOver(MaterialTheme.colors.background)
+ val checkedEndBackgroundColor =
+ MaterialTheme.colors.primary
+ .copy(alpha = 0.5f)
+ .compositeOver(MaterialTheme.colors.background)
+ val checkedContentColor = MaterialTheme.colors.onBackground
+ val checkedSecondaryContentColor = MaterialTheme.colors.onSurfaceVariant
+ val checkedToggleControlColor = MaterialTheme.colors.secondary
+ val uncheckedStartBackgroundColor = MaterialTheme.colors.background
+ val uncheckedEndBackgroundColor = uncheckedStartBackgroundColor
+ val uncheckedContentColor = contentColorFor(checkedEndBackgroundColor)
+ val uncheckedSecondaryContentColor = uncheckedContentColor
+ val uncheckedToggleControlColor = uncheckedContentColor
+
+ return ToggleChipDefaults.toggleChipColors(
+ checkedStartBackgroundColor = checkedStartBackgroundColor,
+ checkedEndBackgroundColor = checkedEndBackgroundColor,
+ checkedContentColor = checkedContentColor,
+ checkedSecondaryContentColor = checkedSecondaryContentColor,
+ checkedToggleControlColor = checkedToggleControlColor,
+ uncheckedStartBackgroundColor = uncheckedStartBackgroundColor,
+ uncheckedEndBackgroundColor = uncheckedEndBackgroundColor,
+ uncheckedContentColor = uncheckedContentColor,
+ uncheckedSecondaryContentColor = uncheckedSecondaryContentColor,
+ uncheckedToggleControlColor = uncheckedToggleControlColor
+ )
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ToggleChipToggleControl.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ToggleChipToggleControl.kt
new file mode 100644
index 000000000..a4ce4e764
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ToggleChipToggleControl.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.elements
+
+public enum class ToggleChipToggleControl {
+ Switch,
+ Radio,
+ Checkbox
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/AppPermissionConfirmDialogViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/AppPermissionConfirmDialogViewModel.kt
new file mode 100644
index 000000000..ffcc4f7ec
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/AppPermissionConfirmDialogViewModel.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.model
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs
+
+class AppPermissionConfirmDialogViewModel : ViewModel() {
+ /** A livedata which stores whether confirmation dialog is visible. */
+ val showConfirmDialogLiveData = MutableLiveData<Boolean>()
+
+ /** Arguments for a confirmation dialog. */
+ var confirmDialogArgs: ConfirmDialogArgs? = null
+
+ /** A livedata which stores whether confirmation dialog is visible. */
+ val showAdvancedConfirmDialogLiveData = MutableLiveData<Boolean>()
+
+ /** Arguments for an advanced confirmation dialog. */
+ var advancedConfirmDialogArgs: AdvancedConfirmDialogArgs? = null
+
+ init {
+ showConfirmDialogLiveData.value = false
+ showAdvancedConfirmDialogLiveData.value = false
+ }
+}
+
+/** Factory for an AppPermissionConfirmDialogViewModel */
+class AppPermissionConfirmDialogViewModelFactory : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return AppPermissionConfirmDialogViewModel() as T
+ }
+}
+
+/** */
+data class ConfirmDialogArgs(
+ val messageId: Int,
+ val changeRequest: AppPermissionViewModel.ChangeRequest,
+ val buttonPressed: Int,
+ val oneTime: Boolean
+)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/AppPermissionGroupsRevokeDialogViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/AppPermissionGroupsRevokeDialogViewModel.kt
new file mode 100644
index 000000000..d383af7b0
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/AppPermissionGroupsRevokeDialogViewModel.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.model
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+
+class AppPermissionGroupsRevokeDialogViewModel : ViewModel() {
+ /** A livedata which stores whether the dialog is visible. */
+ val showDialogLiveData = MutableLiveData<Boolean>()
+ var hasConfirmedRevoke: Boolean = false
+ var revokeDialogArgs: RevokeDialogArgs? = null
+
+ init {
+ showDialogLiveData.value = false
+ }
+
+ fun dismissDialog() {
+ showDialogLiveData.value = false
+ revokeDialogArgs = null
+ }
+}
+
+/** Factory for an AppPermissionGroupsRevokeDialogViewModel */
+class AppPermissionGroupsRevokeDialogViewModelFactory : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return AppPermissionGroupsRevokeDialogViewModel() as T
+ }
+}
+
+data class RevokeDialogArgs(
+ val messageId: Int,
+ val onOkButtonClick: () -> Unit,
+ val onCancelButtonClick: () -> Unit
+)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearAppPermissionUsagesViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearAppPermissionUsagesViewModel.kt
new file mode 100644
index 000000000..85e9eaef2
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearAppPermissionUsagesViewModel.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.model
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
+
+class WearAppPermissionUsagesViewModel : ViewModel() {
+ val appPermissionUsages = MutableLiveData<List<AppPermissionUsage>>()
+}
+
+/** Factory for a WearAppPermissionGroupsViewModel */
+class WearAppPermissionUsagesViewModelFactory : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return WearAppPermissionUsagesViewModel() as T
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearGrantPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearGrantPermissionsViewModel.kt
new file mode 100644
index 000000000..54a6e7c9f
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearGrantPermissionsViewModel.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.model
+
+import android.graphics.drawable.Drawable
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+
+class WearGrantPermissionsViewModel : ViewModel() {
+ /** A livedata which stores the permission group name. */
+ val groupNameLiveData = MutableLiveData<String>()
+
+ /** A livedata which stores the permission group icon. */
+ val iconLiveData = MutableLiveData<Drawable?>()
+
+ /** A livedata which stores the permission group message. */
+ val groupMessageLiveData = MutableLiveData<String>()
+
+ /** A livedata which stores the permission group detail message. */
+ val detailMessageLiveData = MutableLiveData<CharSequence?>()
+
+ /** A livedata which stores the permission group location-granularity visibilities. */
+ val locationVisibilitiesLiveData = MutableLiveData<List<Boolean>>()
+
+ /** A livedata which stores weather the precise location toggle chip is checked. */
+ val preciseLocationCheckedLiveData = MutableLiveData<Boolean>()
+
+ /** A livedata which stores the permission group button visibilities. */
+ val buttonVisibilitiesLiveData = MutableLiveData<List<Boolean>>()
+
+ init {
+ groupNameLiveData.value = ""
+ iconLiveData.value = null
+ groupMessageLiveData.value = ""
+ detailMessageLiveData.value = null
+ locationVisibilitiesLiveData.value = emptyList()
+ preciseLocationCheckedLiveData.value = false
+ buttonVisibilitiesLiveData.value = emptyList()
+ }
+}
+
+/** Factory for a WearGrantPermissionsViewModel */
+class WearGrantPermissionsViewModelFactory : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return WearGrantPermissionsViewModel() as T
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearUnusedAppsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearUnusedAppsViewModel.kt
new file mode 100644
index 000000000..38810ddd6
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/model/WearUnusedAppsViewModel.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.permission.ui.wear.model
+
+import android.graphics.drawable.Drawable
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel.UnusedPeriod
+
+class WearUnusedAppsViewModel : ViewModel() {
+ /** A livedata which indicates if the loading animation should be showed. */
+ val loadingLiveData = MutableLiveData<Boolean>()
+
+ /** A livedata which stores unused period category visibilities. */
+ val unusedPeriodCategoryVisibilitiesLiveData = MutableLiveData<List<Boolean>>()
+
+ /** A livedata which indicates if the info massage category is visible or not. */
+ val infoMsgCategoryVisibilityLiveData = MutableLiveData<Boolean>()
+
+ /** A livedata which stores a map of unused apps group by UnusedPeriod. */
+ val unusedAppChipsLiveData =
+ MutableLiveData<MutableMap<UnusedPeriod, MutableMap<String, UnusedAppChip>>>()
+
+ data class UnusedAppChip(
+ val label: String,
+ val summary: String?,
+ val icon: Drawable?,
+ val contentDescription: String?,
+ val onClick: () -> Unit,
+ )
+
+ init {
+ loadingLiveData.value = true
+ unusedPeriodCategoryVisibilitiesLiveData.value = emptyList()
+ infoMsgCategoryVisibilityLiveData.value = false
+ unusedAppChipsLiveData.value = mutableMapOf()
+ }
+}
+
+/** Factory for a WearUnusedAppsViewModel */
+class WearUnusedAppsViewModelFactory : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return WearUnusedAppsViewModel() as T
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt
new file mode 100644
index 000000000..e7947fd5c
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt
@@ -0,0 +1,55 @@
+package com.android.permissioncontroller.permission.ui.wear.theme
+
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.wear.compose.material.Colors
+import androidx.wear.compose.material.MaterialTheme
+
+/** The Material 3 Theme Wrapper for Supporting RRO. */
+@Composable
+fun WearPermissionTheme(content: @Composable () -> Unit) {
+ val context = LocalContext.current
+ val colors =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ overlayColors(context)
+ .copy(error = MaterialTheme.colors.error, onError = MaterialTheme.colors.onError)
+ } else {
+ MaterialTheme.colors
+ }
+ MaterialTheme(colors = colors, content = content)
+}
+
+/**
+ * Creates a dynamic color maps that can be overlaid. 100 - Lightest shade; 0 - Darkest Shade; In
+ * wear we only support dark theme for the time being. Thus the fill colors and variants are dark
+ * and anything on top is light. We will use this custom redirection until wear compose material
+ * supports color scheming.
+ *
+ * The mapping is best case match on wear material color tokens from
+ * /android/clockwork/common/wearable/wearmaterial/color/res/values/color-tokens.xml
+ *
+ * @param context The context required to get system resource data.
+ */
+@RequiresApi(Build.VERSION_CODES.S)
+@VisibleForTesting
+internal fun overlayColors(context: Context): Colors {
+ val tonalPalette = dynamicTonalPalette(context)
+ return Colors(
+ background = Color.Black,
+ onBackground = Color.White,
+ primary = tonalPalette.primary90,
+ primaryVariant = tonalPalette.primary80,
+ onPrimary = tonalPalette.primary10,
+ secondary = tonalPalette.tertiary90,
+ secondaryVariant = tonalPalette.tertiary60,
+ onSecondary = tonalPalette.tertiary10,
+ surface = tonalPalette.neutral20,
+ onSurface = tonalPalette.neutral95,
+ onSurfaceVariant = tonalPalette.neutralVariant80,
+ )
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTonalPalette.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTonalPalette.kt
new file mode 100644
index 000000000..a86af8b3d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTonalPalette.kt
@@ -0,0 +1,191 @@
+@file:Suppress("unused")
+
+package com.android.permissioncontroller.permission.ui.wear.theme
+
+import android.R
+import android.content.Context
+import android.os.Build
+import androidx.annotation.ColorRes
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.compose.ui.graphics.Color
+
+/**
+ * Tonal Palette structure in Material.
+ *
+ * A tonal palette is comprised of 5 tonal ranges. Each tonal range includes the 13 stops, or tonal
+ * swatches.
+ *
+ * Tonal range names are:
+ * - Neutral (N)
+ * - Neutral variant (NV)
+ * - Primary (P)
+ * - Secondary (S)
+ * - Tertiary (T)
+ */
+internal class WearPermissionTonalPalette(
+ // The neutral tonal range.
+ val neutral100: Color,
+ val neutral99: Color,
+ val neutral95: Color,
+ val neutral90: Color,
+ val neutral80: Color,
+ val neutral70: Color,
+ val neutral60: Color,
+ val neutral50: Color,
+ val neutral40: Color,
+ val neutral30: Color,
+ val neutral20: Color,
+ val neutral10: Color,
+ val neutral0: Color,
+
+ // The neutral variant tonal range, sometimes called "neutral 2"
+ val neutralVariant100: Color,
+ val neutralVariant99: Color,
+ val neutralVariant95: Color,
+ val neutralVariant90: Color,
+ val neutralVariant80: Color,
+ val neutralVariant70: Color,
+ val neutralVariant60: Color,
+ val neutralVariant50: Color,
+ val neutralVariant40: Color,
+ val neutralVariant30: Color,
+ val neutralVariant20: Color,
+ val neutralVariant10: Color,
+ val neutralVariant0: Color,
+
+ // The primary tonal range, also known as accent 1
+ val primary100: Color,
+ val primary99: Color,
+ val primary95: Color,
+ val primary90: Color,
+ val primary80: Color,
+ val primary70: Color,
+ val primary60: Color,
+ val primary50: Color,
+ val primary40: Color,
+ val primary30: Color,
+ val primary20: Color,
+ val primary10: Color,
+ val primary0: Color,
+
+ // The Secondary tonal range, also know as accent 2
+ val secondary100: Color,
+ val secondary99: Color,
+ val secondary95: Color,
+ val secondary90: Color,
+ val secondary80: Color,
+ val secondary70: Color,
+ val secondary60: Color,
+ val secondary50: Color,
+ val secondary40: Color,
+ val secondary30: Color,
+ val secondary20: Color,
+ val secondary10: Color,
+ val secondary0: Color,
+
+ // The tertiary tonal range, also known as accent 3
+ val tertiary100: Color,
+ val tertiary99: Color,
+ val tertiary95: Color,
+ val tertiary90: Color,
+ val tertiary80: Color,
+ val tertiary70: Color,
+ val tertiary60: Color,
+ val tertiary50: Color,
+ val tertiary40: Color,
+ val tertiary30: Color,
+ val tertiary20: Color,
+ val tertiary10: Color,
+ val tertiary0: Color,
+)
+/** Dynamic colors for wear compose material to support resource overlay. */
+@RequiresApi(Build.VERSION_CODES.S)
+// TODO: once we have proper support for this on Wear 6+, we will do something similar to
+// https://source.corp.google.com/h/android/platform/superproject/+/androidx-main:frameworks/support/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DynamicTonalPalette.android.kt;l=307-362?q=dynamicTonalPalette&sq=repo:android%2Fplatform%2Fsuperproject%20b:androidx-main
+// Tracking Bug: b/270720571
+internal fun dynamicTonalPalette(context: Context) =
+ WearPermissionTonalPalette(
+ // The neutral tonal range from the generated dynamic color palette.
+ neutral100 = ColorResourceHelper.getColor(context, R.color.system_neutral1_0),
+ neutral99 = ColorResourceHelper.getColor(context, R.color.system_neutral1_10),
+ neutral95 = ColorResourceHelper.getColor(context, R.color.system_neutral1_50),
+ neutral90 = ColorResourceHelper.getColor(context, R.color.system_neutral1_100),
+ neutral80 = ColorResourceHelper.getColor(context, R.color.system_neutral1_200),
+ neutral70 = ColorResourceHelper.getColor(context, R.color.system_neutral1_300),
+ neutral60 = ColorResourceHelper.getColor(context, R.color.system_neutral1_400),
+ neutral50 = ColorResourceHelper.getColor(context, R.color.system_neutral1_500),
+ neutral40 = ColorResourceHelper.getColor(context, R.color.system_neutral1_600),
+ neutral30 = ColorResourceHelper.getColor(context, R.color.system_neutral1_700),
+ neutral20 = ColorResourceHelper.getColor(context, R.color.system_neutral1_800),
+ neutral10 = ColorResourceHelper.getColor(context, R.color.system_neutral1_900),
+ neutral0 = ColorResourceHelper.getColor(context, R.color.system_neutral1_1000),
+
+ // The neutral variant tonal range, sometimes called "neutral 2", from the
+ // generated dynamic color palette.
+ neutralVariant100 = ColorResourceHelper.getColor(context, R.color.system_neutral2_0),
+ neutralVariant99 = ColorResourceHelper.getColor(context, R.color.system_neutral2_10),
+ neutralVariant95 = ColorResourceHelper.getColor(context, R.color.system_neutral2_50),
+ neutralVariant90 = ColorResourceHelper.getColor(context, R.color.system_neutral2_100),
+ neutralVariant80 = ColorResourceHelper.getColor(context, R.color.system_neutral2_200),
+ neutralVariant70 = ColorResourceHelper.getColor(context, R.color.system_neutral2_300),
+ neutralVariant60 = ColorResourceHelper.getColor(context, R.color.system_neutral2_400),
+ neutralVariant50 = ColorResourceHelper.getColor(context, R.color.system_neutral2_500),
+ neutralVariant40 = ColorResourceHelper.getColor(context, R.color.system_neutral2_600),
+ neutralVariant30 = ColorResourceHelper.getColor(context, R.color.system_neutral2_700),
+ neutralVariant20 = ColorResourceHelper.getColor(context, R.color.system_neutral2_800),
+ neutralVariant10 = ColorResourceHelper.getColor(context, R.color.system_neutral2_900),
+ neutralVariant0 = ColorResourceHelper.getColor(context, R.color.system_neutral2_1000),
+
+ // The primary tonal range from the generated dynamic color palette.
+ primary100 = ColorResourceHelper.getColor(context, R.color.system_accent1_0),
+ primary99 = ColorResourceHelper.getColor(context, R.color.system_accent1_10),
+ primary95 = ColorResourceHelper.getColor(context, R.color.system_accent1_50),
+ primary90 = ColorResourceHelper.getColor(context, R.color.system_accent1_100),
+ primary80 = ColorResourceHelper.getColor(context, R.color.system_accent1_200),
+ primary70 = ColorResourceHelper.getColor(context, R.color.system_accent1_300),
+ primary60 = ColorResourceHelper.getColor(context, R.color.system_accent1_400),
+ primary50 = ColorResourceHelper.getColor(context, R.color.system_accent1_500),
+ primary40 = ColorResourceHelper.getColor(context, R.color.system_accent1_600),
+ primary30 = ColorResourceHelper.getColor(context, R.color.system_accent1_700),
+ primary20 = ColorResourceHelper.getColor(context, R.color.system_accent1_800),
+ primary10 = ColorResourceHelper.getColor(context, R.color.system_accent1_900),
+ primary0 = ColorResourceHelper.getColor(context, R.color.system_accent1_1000),
+
+ // The secondary tonal range from the generated dynamic color palette.
+ secondary100 = ColorResourceHelper.getColor(context, R.color.system_accent2_0),
+ secondary99 = ColorResourceHelper.getColor(context, R.color.system_accent2_10),
+ secondary95 = ColorResourceHelper.getColor(context, R.color.system_accent2_50),
+ secondary90 = ColorResourceHelper.getColor(context, R.color.system_accent2_100),
+ secondary80 = ColorResourceHelper.getColor(context, R.color.system_accent2_200),
+ secondary70 = ColorResourceHelper.getColor(context, R.color.system_accent2_300),
+ secondary60 = ColorResourceHelper.getColor(context, R.color.system_accent2_400),
+ secondary50 = ColorResourceHelper.getColor(context, R.color.system_accent2_500),
+ secondary40 = ColorResourceHelper.getColor(context, R.color.system_accent2_600),
+ secondary30 = ColorResourceHelper.getColor(context, R.color.system_accent2_700),
+ secondary20 = ColorResourceHelper.getColor(context, R.color.system_accent2_800),
+ secondary10 = ColorResourceHelper.getColor(context, R.color.system_accent2_900),
+ secondary0 = ColorResourceHelper.getColor(context, R.color.system_accent2_1000),
+
+ // The tertiary tonal range from the generated dynamic color palette.
+ tertiary100 = ColorResourceHelper.getColor(context, R.color.system_accent3_0),
+ tertiary99 = ColorResourceHelper.getColor(context, R.color.system_accent3_10),
+ tertiary95 = ColorResourceHelper.getColor(context, R.color.system_accent3_50),
+ tertiary90 = ColorResourceHelper.getColor(context, R.color.system_accent3_100),
+ tertiary80 = ColorResourceHelper.getColor(context, R.color.system_accent3_200),
+ tertiary70 = ColorResourceHelper.getColor(context, R.color.system_accent3_300),
+ tertiary60 = ColorResourceHelper.getColor(context, R.color.system_accent3_400),
+ tertiary50 = ColorResourceHelper.getColor(context, R.color.system_accent3_500),
+ tertiary40 = ColorResourceHelper.getColor(context, R.color.system_accent3_600),
+ tertiary30 = ColorResourceHelper.getColor(context, R.color.system_accent3_700),
+ tertiary20 = ColorResourceHelper.getColor(context, R.color.system_accent3_800),
+ tertiary10 = ColorResourceHelper.getColor(context, R.color.system_accent3_900),
+ tertiary0 = ColorResourceHelper.getColor(context, R.color.system_accent3_1000),
+ )
+
+private object ColorResourceHelper {
+ @DoNotInline
+ fun getColor(context: Context, @ColorRes id: Int): Color {
+ return Color(context.resources.getColor(id, context.theme))
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/AndroidUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/AndroidUtils.kt
index 6a6623da7..a5f78aa53 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/AndroidUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/AndroidUtils.kt
@@ -26,19 +26,19 @@ import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.os.Looper
import android.os.UserHandle
-import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executors
+import kotlinx.coroutines.asCoroutineDispatcher
-/**
- * Gets an [Application] instance from a regular [Context]
- */
-val Context.application: Application get() = when (this) {
- is Application -> this
- is Activity -> application
- is Service -> application
- is ContextWrapper -> baseContext.application
- else -> applicationContext as Application
-}
+/** Gets an [Application] instance from a regular [Context] */
+val Context.application: Application
+ get() =
+ when (this) {
+ is Application -> this
+ is Activity -> application
+ is Service -> application
+ is ContextWrapper -> baseContext.application
+ else -> applicationContext as Application
+ }
/**
* The number of threads in the IPC thread pool. Set to the maximum number of binder threads allowed
@@ -46,21 +46,16 @@ val Context.application: Application get() = when (this) {
*/
const val IPC_THREAD_POOL_COUNT = 8
-/**
- * A coroutine dispatcher with a fixed thread pool size, to be used for background tasks
- */
+/** A coroutine dispatcher with a fixed thread pool size, to be used for background tasks */
val IPC = Executors.newFixedThreadPool(IPC_THREAD_POOL_COUNT).asCoroutineDispatcher()
-/**
- * Assert that an operation is running on main thread
- */
-fun ensureMainThread() = check(Looper.myLooper() == Looper.getMainLooper()) {
- "Only meant to be used on the main thread"
-}
+/** Assert that an operation is running on main thread */
+fun ensureMainThread() =
+ check(Looper.myLooper() == Looper.getMainLooper()) {
+ "Only meant to be used on the main thread"
+ }
-/**
- * A more readable version of [PackageManager.updatePermissionFlags]
- */
+/** A more readable version of [PackageManager.updatePermissionFlags] */
fun PackageManager.updatePermissionFlags(
permissionName: String,
packageName: String,
@@ -68,18 +63,14 @@ fun PackageManager.updatePermissionFlags(
vararg flags: Pair<Int, Boolean>
) {
val mask = flags.fold(0, { mask, (flag, _) -> mask or flag })
- val value = flags.fold(0,
- { mask2, (flag, flagValue) -> if (flagValue) mask2 or flag else mask2 })
+ val value =
+ flags.fold(0, { mask2, (flag, flagValue) -> if (flagValue) mask2 or flag else mask2 })
updatePermissionFlags(permissionName, packageName, mask, value, user)
}
-/**
- * Gets a [ComponentInfo] from a [ResolveInfo]
- */
+/** Gets a [ComponentInfo] from a [ResolveInfo] */
val ResolveInfo.componentInfo: ComponentInfo
get() {
return (activityInfo as ComponentInfo?)
- ?: serviceInfo
- ?: providerInfo
- ?: throw IllegalStateException("Missing ComponentInfo!")
- } \ No newline at end of file
+ ?: serviceInfo ?: providerInfo ?: throw IllegalStateException("Missing ComponentInfo!")
+ }
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/ContextCompat.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/ContextCompat.java
new file mode 100644
index 000000000..4ee23f7a0
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/ContextCompat.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 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.permission.utils;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.modules.utils.build.SdkLevel;
+
+/**
+ * Helper Context compat class for {@link Context}.
+ */
+public class ContextCompat {
+ /**
+ * The default device ID, which is the ID of the primary (non-virtual) device.
+ *
+ * @see Context#DEVICE_ID_DEFAULT
+ */
+ public static final int DEVICE_ID_DEFAULT = 0;
+
+ private ContextCompat() {
+ }
+
+ /**
+ * @return The default device ID for pre V platforms, otherwise returns the device ID from
+ * the context.
+ */
+ public static int getDeviceId(@NonNull Context context) {
+ if (SdkLevel.isAtLeastU()) {
+ return context.getDeviceId();
+ } else {
+ return DEVICE_ID_DEFAULT;
+ }
+
+ }
+
+ /**
+ * Creates a new device context, if needed.
+ *
+ * @return A new context if the input context is for a different device, otherwise
+ * return the same context object. See {@link Context#DEVICE_ID_DEFAULT}
+ */
+ @NonNull
+ public static Context createDeviceContext(@NonNull Context context, int deviceId) {
+ if (SdkLevel.isAtLeastU()) {
+ return deviceId == context.getDeviceId()
+ ? context : context.createDeviceContext(deviceId);
+ } else {
+ if (deviceId != DEVICE_ID_DEFAULT) {
+ throw new IllegalArgumentException("Invalid device ID " + deviceId);
+ }
+ return context;
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/DebugUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/DebugUtils.kt
index cf8a69b40..96d634ded 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/DebugUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/DebugUtils.kt
@@ -25,24 +25,21 @@ import java.util.Collections.reverse
*/
fun shortStackTrace() = permissionsStackTrace().toShortString()
-/**
- * [StackTraceElement]s of only the permission-related frames
- */
-fun permissionsStackTrace() = stackTraceWithin("com.android.permissioncontroller")
- .dropLastWhile { it.className.contains(".DebugUtils") }
+/** [StackTraceElement]s of only the permission-related frames */
+fun permissionsStackTrace() =
+ stackTraceWithin("com.android.permissioncontroller").dropLastWhile {
+ it.className.contains(".DebugUtils")
+ }
/**
* [StackTraceElement]s of only frames who's [full class name][StackTraceElement.getClassName]
* starts with [pkgPrefix]
*/
-fun stackTraceWithin(pkgPrefix: String) = Thread
- .currentThread()
- .stackTrace
- .dropWhile {
- !it.className.startsWith(pkgPrefix)
- }.takeWhile {
- it.className.startsWith(pkgPrefix)
- }
+fun stackTraceWithin(pkgPrefix: String) =
+ Thread.currentThread()
+ .stackTrace
+ .dropWhile { !it.className.startsWith(pkgPrefix) }
+ .takeWhile { it.className.startsWith(pkgPrefix) }
/**
* Renders a stack trace slice to a short-ish single-line string.
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
index 861f82364..2aad0154b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
@@ -25,6 +25,8 @@ import android.Manifest.permission.POST_NOTIFICATIONS
import android.Manifest.permission.READ_MEDIA_IMAGES
import android.Manifest.permission.READ_MEDIA_VIDEO
import android.Manifest.permission_group.NOTIFICATIONS
+import android.annotation.SuppressLint
+import android.app.Activity
import android.app.ActivityManager
import android.app.AppOpsManager
import android.app.AppOpsManager.MODE_ALLOWED
@@ -59,8 +61,10 @@ import android.health.connect.HealthConnectManager
import android.os.Build
import android.os.Bundle
import android.os.UserHandle
+import android.os.UserManager
import android.permission.PermissionManager
import android.provider.DeviceConfig
+import android.provider.MediaStore
import android.provider.Settings
import android.safetylabel.SafetyLabelConstants.PERMISSION_RATIONALE_ENABLED
import android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED
@@ -74,6 +78,7 @@ import androidx.navigation.NavController
import androidx.preference.Preference
import androidx.preference.PreferenceGroup
import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.DeviceUtils
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.R
@@ -86,7 +91,7 @@ import com.android.permissioncontroller.permission.model.livedatatypes.LightPerm
import com.android.permissioncontroller.permission.model.livedatatypes.PermState
import com.android.permissioncontroller.permission.service.LocationAccessCheck
import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
import java.time.Duration
import java.util.concurrent.atomic.AtomicReference
import kotlin.coroutines.Continuation
@@ -106,13 +111,14 @@ object KotlinUtils {
private const val LOG_TAG = "PermissionController Utils"
- private const val PERMISSION_CONTROLLER_CHANGED_FLAG_MASK = FLAG_PERMISSION_USER_SET or
- FLAG_PERMISSION_USER_FIXED or
- FLAG_PERMISSION_ONE_TIME or
- FLAG_PERMISSION_REVOKED_COMPAT or
- FLAG_PERMISSION_ONE_TIME or
- FLAG_PERMISSION_REVIEW_REQUIRED or
- FLAG_PERMISSION_AUTO_REVOKED
+ private const val PERMISSION_CONTROLLER_CHANGED_FLAG_MASK =
+ FLAG_PERMISSION_USER_SET or
+ FLAG_PERMISSION_USER_FIXED or
+ FLAG_PERMISSION_ONE_TIME or
+ FLAG_PERMISSION_REVOKED_COMPAT or
+ FLAG_PERMISSION_ONE_TIME or
+ FLAG_PERMISSION_REVIEW_REQUIRED or
+ FLAG_PERMISSION_AUTO_REVOKED
private const val KILL_REASON_APP_OP_CHANGE = "Permission related app op changed"
private const val SAFETY_PROTECTION_RESOURCES_ENABLED = "safety_protection_enabled"
@@ -131,27 +137,21 @@ object KotlinUtils {
private val ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE =
ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE
- /** Whether to show the Permissions Hub. */
- private const val PROPERTY_PERMISSIONS_HUB_2_ENABLED = "permissions_hub_2_enabled"
-
- /** Whether to show the mic and camera icons. */
+ /** Whether to show the mic and camera icons. */
private const val PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"
/** Whether to show the location indicators. */
private const val PROPERTY_LOCATION_INDICATORS_ENABLED = "location_indicators_enabled"
- /** Whether to show 7-day toggle in privacy hub. */
+ /** Whether to show 7-day toggle in privacy hub. */
private const val PRIVACY_DASHBOARD_7_DAY_TOGGLE = "privacy_dashboard_7_day_toggle"
- /** Default location precision */
- private const val PROPERTY_LOCATION_PRECISION = "location_precision"
-
- /** Whether to show the photo picker option in permission prompts. */
+ /** Whether to show the photo picker option in permission prompts. */
private const val PROPERTY_PHOTO_PICKER_PROMPT_ENABLED = "photo_picker_prompt_enabled"
/**
- * The minimum amount of time to wait, after scheduling the safety label changes job, before
- * the job actually runs for the first time.
+ * The minimum amount of time to wait, after scheduling the safety label changes job, before the
+ * job actually runs for the first time.
*/
private const val PROPERTY_SAFETY_LABEL_CHANGES_JOB_DELAY_MILLIS =
"safety_label_changes_job_delay_millis"
@@ -168,95 +168,58 @@ object KotlinUtils {
private const val PROPERTY_SAFETY_LABEL_CHANGES_JOB_SERVICE_KILL_SWITCH =
"safety_label_changes_job_service_kill_switch"
- /**
- * Whether the Permissions Hub 2 flag is enabled
- *
- * @return whether the flag is enabled
- */
- @ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
- fun isPermissionsHub2FlagEnabled(): Boolean {
- return SdkLevel.isAtLeastS() && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_PERMISSIONS_HUB_2_ENABLED, false)
- }
- /**
- * Whether to show the Permissions Dashboard
- *
- * @return whether to show the Permissions Dashboard.
- */
- @ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
- fun shouldShowPermissionsDashboard(): Boolean {
- return isPermissionsHub2FlagEnabled()
- }
+ data class Quadruple<out A, out B, out C, out D>(
+ val first: A,
+ val second: B,
+ val third: C,
+ val fourth: D
+ )
/**
- * Whether the Camera and Mic Icons are enabled by flag.
- *
- * @return whether the Camera and Mic Icons are enabled.
- */
- @ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
- fun isCameraMicIconsFlagEnabled(): Boolean {
- return SdkLevel.isAtLeastS() && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_CAMERA_MIC_ICONS_ENABLED, true)
- }
-
- /**
- * Whether to show Camera and Mic Icons. They should be shown if the permission hub, or the icons
- * specifically, are enabled.
+ * Whether to show Camera and Mic Icons.
*
* @return whether to show the icons.
*/
@ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
fun shouldShowCameraMicIndicators(): Boolean {
- return isCameraMicIconsFlagEnabled() || isPermissionsHub2FlagEnabled()
+ return SdkLevel.isAtLeastS() &&
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_CAMERA_MIC_ICONS_ENABLED,
+ true
+ )
}
- /**
- * Whether the location indicators are enabled by flag.
- *
- * @return whether the location indicators are enabled by flag.
- */
- @ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
- fun isLocationIndicatorsFlagEnabled(): Boolean {
- return SdkLevel.isAtLeastS() && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_LOCATION_INDICATORS_ENABLED, false)
- }
-
- /**
- * Whether to show the location indicators. The location indicators are enable if the
- * permission hub, or location indicator specifically are enabled.
- */
+ /** Whether to show the location indicators. */
@ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
fun shouldShowLocationIndicators(): Boolean {
- return isLocationIndicatorsFlagEnabled() || isPermissionsHub2FlagEnabled()
+ return SdkLevel.isAtLeastS() &&
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_INDICATORS_ENABLED,
+ false
+ )
}
- /**
- * Whether the location accuracy feature is enabled
- */
+ /** Whether the location accuracy feature is enabled */
@ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
fun isLocationAccuracyEnabled(): Boolean {
return SdkLevel.isAtLeastS()
}
/**
- * Default state of location precision
- * true: default is FINE.
- * false: default is COARSE.
- */
- fun getDefaultPrecision(): Boolean {
- return !SdkLevel.isAtLeastS() || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_LOCATION_PRECISION, true)
- }
-
- /**
* Whether we should enable the 7-day toggle in privacy dashboard
*
* @return whether the flag is enabled
*/
@ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
fun is7DayToggleEnabled(): Boolean {
- return SdkLevel.isAtLeastS() && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PRIVACY_DASHBOARD_7_DAY_TOGGLE, false)
+ return SdkLevel.isAtLeastS() &&
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PRIVACY_DASHBOARD_7_DAY_TOGGLE,
+ false
+ )
}
/**
@@ -266,11 +229,22 @@ object KotlinUtils {
*/
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
fun isPhotoPickerPromptEnabled(): Boolean {
+ return isPhotoPickerPromptSupported() &&
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_PHOTO_PICKER_PROMPT_ENABLED,
+ true
+ )
+ }
+
+ /** Whether the Photo Picker Prompt is supported by the device */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
+ fun isPhotoPickerPromptSupported(): Boolean {
val app = PermissionControllerApplication.get()
- return SdkLevel.isAtLeastU() && !DeviceUtils.isAuto(app) &&
- !DeviceUtils.isTelevision(app) && !DeviceUtils.isWear(app) &&
- DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_PHOTO_PICKER_PROMPT_ENABLED, true)
+ return SdkLevel.isAtLeastU() &&
+ !DeviceUtils.isAuto(app) &&
+ !DeviceUtils.isTelevision(app) &&
+ !DeviceUtils.isWear(app)
}
/*
@@ -280,8 +254,12 @@ object KotlinUtils {
*/
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
fun isPermissionRationaleEnabled(): Boolean {
- return SdkLevel.isAtLeastU() && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PERMISSION_RATIONALE_ENABLED, true)
+ return SdkLevel.isAtLeastU() &&
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PERMISSION_RATIONALE_ENABLED,
+ true
+ )
}
/**
@@ -289,8 +267,12 @@ object KotlinUtils {
*/
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
fun isSafetyLabelChangeNotificationsEnabled(context: Context): Boolean {
- return SdkLevel.isAtLeastU() && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, true) &&
+ return SdkLevel.isAtLeastU() &&
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED,
+ true
+ ) &&
!DeviceUtils.isAuto(context) &&
!DeviceUtils.isTelevision(context) &&
!DeviceUtils.isWear(context)
@@ -302,8 +284,12 @@ object KotlinUtils {
*/
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
fun safetyLabelChangesJobServiceKillSwitch(): Boolean {
- return SdkLevel.isAtLeastU() && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_LABEL_CHANGES_JOB_SERVICE_KILL_SWITCH, false)
+ return SdkLevel.isAtLeastU() &&
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_SAFETY_LABEL_CHANGES_JOB_SERVICE_KILL_SWITCH,
+ false
+ )
}
/** How often the safety label changes job will run. */
@@ -312,7 +298,8 @@ object KotlinUtils {
return DeviceConfig.getLong(
DeviceConfig.NAMESPACE_PRIVACY,
PROPERTY_SAFETY_LABEL_CHANGES_JOB_INTERVAL_MILLIS,
- Duration.ofDays(30).toMillis())
+ Duration.ofDays(30).toMillis()
+ )
}
/** Whether the safety label changes job should only be run when the device is idle. */
@@ -321,19 +308,19 @@ object KotlinUtils {
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_PRIVACY,
PROPERTY_SAFETY_LABEL_CHANGES_JOB_RUN_WHEN_IDLE,
- true)
+ true
+ )
}
/**
- * Given a Map, and a List, determines which elements are in the list, but not the map, and
- * vice versa. Used primarily for determining which liveDatas are already being watched, and
- * which need to be removed or added
+ * Given a Map, and a List, determines which elements are in the list, but not the map, and vice
+ * versa. Used primarily for determining which liveDatas are already being watched, and which
+ * need to be removed or added
*
* @param oldValues A map of key type K, with any value type
* @param newValues A list of type K
- *
* @return A pair, where the first value is all items in the list, but not the map, and the
- * second is all keys in the map, but not the list
+ * second is all keys in the map, but not the list
*/
fun <K> getMapAndListDifferences(
newValues: Collection<K>,
@@ -355,7 +342,7 @@ object KotlinUtils {
*
* @param compare The function comparing two preferences, which will be used to sort
* @param hasHeader Whether the group contains a LargeHeaderPreference, which will be kept at
- * the top of the list
+ * the top of the list
*/
fun sortPreferenceGroup(
group: PreferenceGroup,
@@ -368,15 +355,17 @@ object KotlinUtils {
}
if (hasHeader) {
- preferences.sortWith(Comparator { lhs, rhs ->
- if (lhs is SettingsWithLargeHeader.LargeHeaderPreference) {
- -1
- } else if (rhs is SettingsWithLargeHeader.LargeHeaderPreference) {
- 1
- } else {
- compare(lhs, rhs)
+ preferences.sortWith(
+ Comparator { lhs, rhs ->
+ if (lhs is SettingsWithLargeHeader.LargeHeaderPreference) {
+ -1
+ } else if (rhs is SettingsWithLargeHeader.LargeHeaderPreference) {
+ 1
+ } else {
+ compare(lhs, rhs)
+ }
}
- })
+ )
} else {
preferences.sortWith(Comparator(compare))
}
@@ -391,17 +380,15 @@ object KotlinUtils {
*
* @param context The context from which to get the icon
* @param groupName The name of the permission group whose icon we want
- *
* @return The permission group's icon, the ic_perm_device_info icon if the group has no icon,
- * or the group does not exist
+ * or the group does not exist
*/
@JvmOverloads
fun getPermGroupIcon(context: Context, groupName: String, tint: Int? = null): Drawable? {
val groupInfo = Utils.getGroupInfo(groupName, context)
var icon: Drawable? = null
if (groupInfo != null && groupInfo.icon != 0) {
- icon = Utils.loadDrawable(context.packageManager, groupInfo.packageName,
- groupInfo.icon)
+ icon = Utils.loadDrawable(context.packageManager, groupInfo.packageName, groupInfo.icon)
}
if (icon == null) {
@@ -421,13 +408,15 @@ object KotlinUtils {
*
* @param context The context from which to get the label
* @param groupName The name of the permission group whose label we want
- *
* @return The permission group's label, or the group name, if the group is invalid
*/
fun getPermGroupLabel(context: Context, groupName: String): CharSequence {
val groupInfo = Utils.getGroupInfo(groupName, context) ?: return groupName
- return groupInfo.loadSafeLabel(context.packageManager, 0f,
- TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM)
+ return groupInfo.loadSafeLabel(
+ context.packageManager,
+ 0f,
+ TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
+ )
}
/**
@@ -435,9 +424,8 @@ object KotlinUtils {
*
* @param context The context from which to get the description
* @param groupName The name of the permission group whose description we want
- *
* @return The permission group's description, or an empty string, if the group is invalid, or
- * its description does not exist
+ * its description does not exist
*/
fun getPermGroupDescription(context: Context, groupName: String): CharSequence {
val groupInfo = Utils.getGroupInfo(groupName, context)
@@ -453,15 +441,20 @@ object KotlinUtils {
/**
* Gets a permission's label from the system.
+ *
* @param context The context from which to get the label
* @param permName The name of the permission whose label we want
- *
* @return The permission's label, or the permission name, if the permission is invalid
*/
fun getPermInfoLabel(context: Context, permName: String): CharSequence {
return try {
- context.packageManager.getPermissionInfo(permName, 0).loadSafeLabel(
- context.packageManager, 20000.toFloat(), TextUtils.SAFE_STRING_FLAG_TRIM)
+ context.packageManager
+ .getPermissionInfo(permName, 0)
+ .loadSafeLabel(
+ context.packageManager,
+ 20000.toFloat(),
+ TextUtils.SAFE_STRING_FLAG_TRIM
+ )
} catch (e: PackageManager.NameNotFoundException) {
permName
}
@@ -469,19 +462,23 @@ object KotlinUtils {
/**
* Gets a permission's icon from the system.
+ *
* @param context The context from which to get the icon
* @param permName The name of the permission whose icon we want
- *
- * @return The permission's icon, or the permission's group icon if the icon isn't set, or
- * the ic_perm_device_info icon if the permission is invalid.
+ * @return The permission's icon, or the permission's group icon if the icon isn't set, or the
+ * ic_perm_device_info icon if the permission is invalid.
*/
fun getPermInfoIcon(context: Context, permName: String): Drawable? {
return try {
val permInfo = context.packageManager.getPermissionInfo(permName, 0)
var icon: Drawable? = null
if (permInfo.icon != 0) {
- icon = Utils.applyTint(context, permInfo.loadUnbadgedIcon(context.packageManager),
- android.R.attr.colorControlNormal)
+ icon =
+ Utils.applyTint(
+ context,
+ permInfo.loadUnbadgedIcon(context.packageManager),
+ android.R.attr.colorControlNormal
+ )
}
if (icon == null) {
@@ -491,8 +488,11 @@ object KotlinUtils {
icon
} catch (e: PackageManager.NameNotFoundException) {
- Utils.applyTint(context, context.getDrawable(R.drawable.ic_perm_device_info),
- android.R.attr.colorControlNormal)
+ Utils.applyTint(
+ context,
+ context.getDrawable(R.drawable.ic_perm_device_info),
+ android.R.attr.colorControlNormal
+ )
}
}
@@ -501,9 +501,8 @@ object KotlinUtils {
*
* @param context The context from which to get the description
* @param permName The name of the permission whose description we want
- *
- * @return The permission's description, or an empty string, if the group is invalid, or
- * its description does not exist
+ * @return The permission's description, or an empty string, if the group is invalid, or its
+ * description does not exist
*/
fun getPermInfoDescription(context: Context, permName: String): CharSequence {
return try {
@@ -515,19 +514,29 @@ object KotlinUtils {
}
/**
+ * Get the settings icon
+ *
+ * @param app The current application
+ * @param user The user for whom we want the icon
+ * @param pm The PackageManager
+ * @return Bitmap of the setting's icon, or null
+ */
+ fun getSettingsIcon(app: Application, user: UserHandle, pm: PackageManager): Bitmap? {
+ val settingsPackageName =
+ getPackageNameForIntent(pm, Settings.ACTION_SETTINGS)
+ ?: Constants.SETTINGS_PACKAGE_NAME_FALLBACK
+ return getBadgedPackageIconBitmap(app, user, settingsPackageName)
+ }
+
+ /**
* Gets a package's badged icon from the system.
*
* @param app The current application
* @param packageName The name of the package whose icon we want
* @param user The user for whom we want the package icon
- *
* @return The package's icon, or null, if the package does not exist
*/
- fun getBadgedPackageIcon(
- app: Application,
- packageName: String,
- user: UserHandle
- ): Drawable? {
+ fun getBadgedPackageIcon(app: Application, packageName: String, user: UserHandle): Drawable? {
return try {
val userContext = Utils.getUserContext(app, user)
val appInfo = userContext.packageManager.getApplicationInfo(packageName, 0)
@@ -538,12 +547,35 @@ object KotlinUtils {
}
/**
+ * Get the icon of a package
+ *
+ * @param application The current application
+ * @param user The user for whom we want the icon
+ * @param packageName The name of the package whose icon we want
+ * @return Bitmap of the package icon, or null
+ */
+ fun getBadgedPackageIconBitmap(
+ application: Application,
+ user: UserHandle,
+ packageName: String
+ ): Bitmap? {
+ val drawable = getBadgedPackageIcon(application, packageName, user)
+
+ val icon =
+ if (drawable != null) {
+ convertToBitmap(drawable)
+ } else {
+ null
+ }
+ return icon
+ }
+
+ /**
* Gets a package's badged label from the system.
*
* @param app The current application
* @param packageName The name of the package whose label we want
* @param user The user for whom we want the package label
- *
* @return The package's label
*/
fun getPackageLabel(app: Application, packageName: String, user: UserHandle): String {
@@ -557,8 +589,12 @@ object KotlinUtils {
}
fun convertToBitmap(pkgIcon: Drawable): Bitmap {
- val pkgIconBmp = Bitmap.createBitmap(pkgIcon.intrinsicWidth, pkgIcon.intrinsicHeight,
- Bitmap.Config.ARGB_8888)
+ val pkgIconBmp =
+ Bitmap.createBitmap(
+ pkgIcon.intrinsicWidth,
+ pkgIcon.intrinsicHeight,
+ Bitmap.Config.ARGB_8888
+ )
// Draw the icon so it can be displayed.
val canvas = Canvas(pkgIconBmp)
pkgIcon.setBounds(0, 0, pkgIcon.intrinsicWidth, pkgIcon.intrinsicHeight)
@@ -567,19 +603,31 @@ object KotlinUtils {
}
/**
+ * Returns the name of the package that resolves the specified intent action
+ *
+ * @param pm The PackageManager
+ * @param intentAction The name of the intent action
+ * @return The package's name, or null
+ */
+ fun getPackageNameForIntent(pm: PackageManager, intentAction: String): String? {
+ val intent = Intent(intentAction)
+ return intent.resolveActivity(pm)?.packageName
+ }
+
+ /**
* Gets a package's uid, using a cached liveData value, if the liveData is currently being
* observed (and thus has an up-to-date value).
*
* @param app The current application
* @param packageName The name of the package whose uid we want
* @param user The user we want the package uid for
- *
* @return The package's UID, or null if the package or user is invalid
*/
fun getPackageUid(app: Application, packageName: String, user: UserHandle): Int? {
val liveData = LightPackageInfoLiveData[packageName, user]
val liveDataUid = liveData.value?.uid
- return if (liveDataUid != null && liveData.hasActiveObservers()) liveDataUid else {
+ return if (liveDataUid != null && liveData.hasActiveObservers()) liveDataUid
+ else {
val userContext = Utils.getUserContext(app, user)
try {
val appInfo = userContext.packageManager.getApplicationInfo(packageName, 0)
@@ -590,9 +638,31 @@ object KotlinUtils {
}
}
- /**
- * Return a specific MIME type, if a set of permissions is associated with one
- */
+ fun openPhotoPickerForApp(
+ activity: Activity,
+ uid: Int,
+ requestedPermissions: List<String>,
+ requestCode: Int
+ ) {
+ // A clone profile doesn't have a MediaProvider. If the app's user is a clone profile, open
+ // the photo picker in the parent profile
+ val appUser = UserHandle.getUserHandleForUid(uid)
+ val userManager =
+ activity.createContextAsUser(appUser, 0).getSystemService(UserManager::class.java)!!
+ val user =
+ if (userManager.isCloneProfile) {
+ userManager.getProfileParent(appUser) ?: appUser
+ } else {
+ appUser
+ }
+ val pickerIntent =
+ Intent(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP)
+ .putExtra(Intent.EXTRA_UID, uid)
+ .setType(getMimeTypeForPermissions(requestedPermissions))
+ activity.startActivityForResultAsUser(pickerIntent, requestCode, user)
+ }
+
+ /** Return a specific MIME type, if a set of permissions is associated with one */
fun getMimeTypeForPermissions(permissions: List<String>): String? {
if (permissions.contains(READ_MEDIA_IMAGES) && !permissions.contains(READ_MEDIA_VIDEO)) {
return "image/*"
@@ -610,36 +680,36 @@ object KotlinUtils {
* @param app The currenct application
* @param packageName The package name to check
* @param user The user whose package we want to check
- *
* @return true if the package is R+ (and not a work profile) or has auto revoke enabled
*/
fun isROrAutoRevokeEnabled(app: Application, packageName: String, user: UserHandle): Boolean {
val userContext = Utils.getUserContext(app, user)
val liveDataValue = LightPackageInfoLiveData[packageName, user].value
- val (targetSdk, uid) = if (liveDataValue != null) {
- liveDataValue.targetSdkVersion to liveDataValue.uid
- } else {
- val appInfo = userContext.packageManager.getApplicationInfo(packageName, 0)
- appInfo.targetSdkVersion to appInfo.uid
- }
+ val (targetSdk, uid) =
+ if (liveDataValue != null) {
+ liveDataValue.targetSdkVersion to liveDataValue.uid
+ } else {
+ val appInfo = userContext.packageManager.getApplicationInfo(packageName, 0)
+ appInfo.targetSdkVersion to appInfo.uid
+ }
if (targetSdk <= Build.VERSION_CODES.Q) {
val opsManager = app.getSystemService(AppOpsManager::class.java)!!
- return opsManager.unsafeCheckOpNoThrow(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, uid,
- packageName) == MODE_ALLOWED
+ return opsManager.unsafeCheckOpNoThrow(
+ OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+ uid,
+ packageName
+ ) == MODE_ALLOWED
}
return true
}
/**
- * Determine if the given permission should be treated as split from a
- * non-runtime permission for an application targeting the given SDK level.
+ * Determine if the given permission should be treated as split from a non-runtime permission
+ * for an application targeting the given SDK level.
*/
- private fun isPermissionSplitFromNonRuntime(
- app: Application,
- permName: String,
- targetSdk: Int
- ): Boolean {
+ @JvmStatic
+ fun isPermissionSplitFromNonRuntime(app: Context, permName: String, targetSdk: Int): Boolean {
val permissionManager = app.getSystemService(PermissionManager::class.java) ?: return false
val splitPerms = permissionManager.splitPermissions
val size = splitPerms.size
@@ -660,8 +730,7 @@ object KotlinUtils {
* @param group: The LightAppPermGroup whose permission flags we wish to set
* @param flags: Pairs of <FlagInt, ShouldSetFlag>
* @param filterPermissions: A list of permissions to filter by. Only the filtered permissions
- * will be set
- *
+ * will be set
* @return A new LightAppPermGroup with the flags set.
*/
fun setGroupFlags(
@@ -679,6 +748,10 @@ object KotlinUtils {
}
}
+ val deviceId = group.deviceId
+ // Create a new context with the given deviceId so that permission updates will be bound
+ // to the device
+ val context = ContextCompat.createDeviceContext(app.applicationContext, deviceId)
val newPerms = mutableMapOf<String, LightPermission>()
for ((permName, perm) in group.permissions) {
if (permName !in filterPermissions) {
@@ -686,14 +759,29 @@ object KotlinUtils {
}
// Check if flags need to be updated
if (flagMask and (perm.flags xor flagsToSet) != 0) {
- app.packageManager.updatePermissionFlags(permName, group.packageName,
- group.userHandle, *flags)
+ context.packageManager.updatePermissionFlags(
+ permName,
+ group.packageName,
+ group.userHandle,
+ *flags
+ )
}
- newPerms[permName] = LightPermission(group.packageInfo, perm.permInfo,
- perm.isGrantedIncludingAppOp, perm.flags or flagsToSet, perm.foregroundPerms)
+ newPerms[permName] =
+ LightPermission(
+ group.packageInfo,
+ perm.permInfo,
+ perm.isGrantedIncludingAppOp,
+ perm.flags or flagsToSet,
+ perm.foregroundPerms
+ )
}
- return LightAppPermGroup(group.packageInfo, group.permGroupInfo, newPerms,
- group.hasInstallToRuntimeSplit, group.specialLocationGrant)
+ return LightAppPermGroup(
+ group.packageInfo,
+ group.permGroupInfo,
+ newPerms,
+ group.hasInstallToRuntimeSplit,
+ group.specialLocationGrant
+ )
}
/**
@@ -704,22 +792,27 @@ object KotlinUtils {
* @param app The current application
* @param group The group whose permissions should be granted
* @param filterPermissions If not specified, all permissions of the group will be granted.
- * Otherwise only permissions in {@code filterPermissions} will be
- * granted.
- *
+ * Otherwise only permissions in {@code filterPermissions} will be granted.
* @return a new LightAppPermGroup, reflecting the new state
*/
@JvmOverloads
fun grantForegroundRuntimePermissions(
app: Application,
group: LightAppPermGroup,
- filterPermissions: List<String> = group.permissions.keys.toList(),
+ filterPermissions: Collection<String> = group.permissions.keys,
isOneTime: Boolean = false,
userFixed: Boolean = false,
withoutAppOps: Boolean = false,
): LightAppPermGroup {
- return grantRuntimePermissions(app, group, false, isOneTime, userFixed,
- withoutAppOps, filterPermissions)
+ return grantRuntimePermissions(
+ app,
+ group,
+ false,
+ isOneTime,
+ userFixed,
+ withoutAppOps,
+ filterPermissions
+ )
}
/**
@@ -730,21 +823,27 @@ object KotlinUtils {
* @param app The current application
* @param group The group whose permissions should be granted
* @param filterPermissions If not specified, all permissions of the group will be granted.
- * Otherwise only permissions in {@code filterPermissions} will be
- * granted.
- *
+ * Otherwise only permissions in {@code filterPermissions} will be granted.
* @return a new LightAppPermGroup, reflecting the new state
*/
@JvmOverloads
fun grantBackgroundRuntimePermissions(
app: Application,
group: LightAppPermGroup,
- filterPermissions: List<String> = group.permissions.keys.toList()
+ filterPermissions: Collection<String> = group.permissions.keys
): LightAppPermGroup {
- return grantRuntimePermissions(app, group, true, false, false, false,
- filterPermissions)
+ return grantRuntimePermissions(
+ app,
+ group,
+ grantBackground = true,
+ isOneTime = false,
+ userFixed = false,
+ withoutAppOps = false,
+ filterPermissions = filterPermissions
+ )
}
+ @SuppressLint("MissingPermission")
private fun grantRuntimePermissions(
app: Application,
group: LightAppPermGroup,
@@ -752,52 +851,78 @@ object KotlinUtils {
isOneTime: Boolean = false,
userFixed: Boolean = false,
withoutAppOps: Boolean = false,
- filterPermissions: List<String> = group.permissions.keys.toList(),
+ filterPermissions: Collection<String> = group.permissions.keys
): LightAppPermGroup {
+ val deviceId = group.deviceId
val newPerms = group.permissions.toMutableMap()
var shouldKillForAnyPermission = false
for (permName in filterPermissions) {
val perm = group.permissions[permName] ?: continue
val isBackgroundPerm = permName in group.backgroundPermNames
if (isBackgroundPerm == grantBackground) {
- val (newPerm, shouldKill) = grantRuntimePermission(app, perm, group, isOneTime,
- userFixed, withoutAppOps)
+ val (newPerm, shouldKill) =
+ grantRuntimePermission(app, perm, group, isOneTime, userFixed, withoutAppOps)
newPerms[newPerm.name] = newPerm
shouldKillForAnyPermission = shouldKillForAnyPermission || shouldKill
}
}
+
+ // Create a new context with the given deviceId so that permission updates will be bound
+ // to the device
+ val context = ContextCompat.createDeviceContext(app.applicationContext, deviceId)
+
if (!newPerms.isEmpty()) {
val user = UserHandle.getUserHandleForUid(group.packageInfo.uid)
for (groupPerm in group.allPermissions.values) {
var permFlags = groupPerm.flags
permFlags = permFlags.clearFlag(FLAG_PERMISSION_AUTO_REVOKED)
if (groupPerm.flags != permFlags) {
- app.packageManager.updatePermissionFlags(groupPerm.name,
- group.packageInfo.packageName, PERMISSION_CONTROLLER_CHANGED_FLAG_MASK,
- permFlags, user)
+ context.packageManager.updatePermissionFlags(
+ groupPerm.name,
+ group.packageInfo.packageName,
+ PERMISSION_CONTROLLER_CHANGED_FLAG_MASK,
+ permFlags,
+ user
+ )
}
}
}
if (shouldKillForAnyPermission) {
(app.getSystemService(ActivityManager::class.java) as ActivityManager).killUid(
- group.packageInfo.uid, KILL_REASON_APP_OP_CHANGE)
+ group.packageInfo.uid,
+ KILL_REASON_APP_OP_CHANGE
+ )
}
- val newGroup = LightAppPermGroup(group.packageInfo, group.permGroupInfo, newPerms,
- group.hasInstallToRuntimeSplit, group.specialLocationGrant)
+ val newGroup =
+ LightAppPermGroup(
+ group.packageInfo,
+ group.permGroupInfo,
+ newPerms,
+ group.hasInstallToRuntimeSplit,
+ group.specialLocationGrant
+ )
// If any permission in the group is one time granted, start one time permission session.
if (newGroup.permissions.any { it.value.isOneTime && it.value.isGrantedIncludingAppOp }) {
if (SdkLevel.isAtLeastT()) {
- app.getSystemService(PermissionManager::class.java)!!.startOneTimePermissionSession(
- group.packageName, Utils.getOneTimePermissionsTimeout(),
+ context
+ .getSystemService(PermissionManager::class.java)!!
+ .startOneTimePermissionSession(
+ group.packageName,
+ Utils.getOneTimePermissionsTimeout(),
Utils.getOneTimePermissionsKilledDelay(false),
ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_RESET_TIMER,
- ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE)
+ ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE
+ )
} else {
- app.getSystemService(PermissionManager::class.java)!!.startOneTimePermissionSession(
- group.packageName, Utils.getOneTimePermissionsTimeout(),
+ context
+ .getSystemService(PermissionManager::class.java)!!
+ .startOneTimePermissionSession(
+ group.packageName,
+ Utils.getOneTimePermissionsTimeout(),
ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_RESET_TIMER,
- ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE)
+ ONE_TIME_PACKAGE_IMPORTANCE_LEVEL_TO_KEEP_SESSION_ALIVE
+ )
}
}
return newGroup
@@ -809,14 +934,13 @@ object KotlinUtils {
* @param app The current application
* @param perm The permission which should be granted.
* @param group An app permission group in which to look for background or foreground
- * @param isOneTime Whether this is a one-time permission grant
- * permissions
+ * @param isOneTime Whether this is a one-time permission grant permissions
* @param userFixed Whether to mark the permissions as user fixed when granted
* @param withoutAppOps If these permission have app ops associated, and this value is true,
- * then do not grant the app op when the permission is granted, and add the REVOKED_COMPAT flag.
- *
+ * then do not grant the app op when the permission is granted, and add the REVOKED_COMPAT
+ * flag.
* @return a LightPermission and boolean pair <permission with updated state (or the original
- * state, if it wasn't changed), should kill app>
+ * state, if it wasn't changed), should kill app>
*/
private fun grantRuntimePermission(
app: Application,
@@ -828,9 +952,11 @@ object KotlinUtils {
): Pair<LightPermission, Boolean> {
val pkgInfo = group.packageInfo
val user = UserHandle.getUserHandleForUid(pkgInfo.uid)
+ val deviceId = group.deviceId
val supportsRuntime = pkgInfo.targetSdkVersion >= Build.VERSION_CODES.M
- val isGrantingAllowed = (!pkgInfo.isInstantApp || perm.isInstantPerm) &&
- (supportsRuntime || !perm.isRuntimeOnly)
+ val isGrantingAllowed =
+ (!pkgInfo.isInstantApp || perm.isInstantPerm) &&
+ (supportsRuntime || !perm.isRuntimeOnly)
// Do not touch permissions fixed by the system, or permissions that cannot be granted
if (!isGrantingAllowed || perm.isSystemFixed) {
return perm to false
@@ -841,6 +967,10 @@ object KotlinUtils {
var isGranted = perm.isGrantedIncludingAppOp
var shouldKill = false
+ // Create a new context with the given deviceId so that permission updates will be bound
+ // to the device
+ val context = ContextCompat.createDeviceContext(app.applicationContext, deviceId)
+
// Grant the permission if needed.
if (!perm.isGrantedIncludingAppOp) {
val affectsAppOp = permissionToOp(perm.name) != null || perm.isBackgroundPermission
@@ -851,11 +981,17 @@ object KotlinUtils {
// flag, so that the PermissionPolicyService doesn't reset the app op state
if (affectsAppOp && withoutAppOps) {
oldFlags = oldFlags.setFlag(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)
- app.packageManager.updatePermissionFlags(perm.name, group.packageName,
- PERMISSION_CONTROLLER_CHANGED_FLAG_MASK, oldFlags, user)
+ context.packageManager.updatePermissionFlags(
+ perm.name,
+ group.packageName,
+ PERMISSION_CONTROLLER_CHANGED_FLAG_MASK,
+ oldFlags,
+ user
+ )
+ // TODO: Update this method once AppOp is device aware
disallowAppOp(app, perm, group)
}
- app.packageManager.grantRuntimePermission(group.packageName, perm.name, user)
+ context.packageManager.grantRuntimePermission(group.packageName, perm.name, user)
isGranted = true
} else if (affectsAppOp) {
// Legacy apps do not know that they have to retry access to a
@@ -865,16 +1001,18 @@ object KotlinUtils {
shouldKill = true
isGranted = true
}
- newFlags = if (affectsAppOp && withoutAppOps) {
- newFlags.setFlag(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)
- } else {
- newFlags.clearFlag(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)
- }
+ newFlags =
+ if (affectsAppOp && withoutAppOps) {
+ newFlags.setFlag(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)
+ } else {
+ newFlags.clearFlag(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)
+ }
newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
// If this permission affects an app op, ensure the permission app op is enabled
// before the permission grant.
if (affectsAppOp && !withoutAppOps) {
+ // TODO: Update this method once AppOp is device aware
allowAppOp(app, perm, group)
}
}
@@ -894,11 +1032,12 @@ object KotlinUtils {
}
newFlags = newFlags.clearFlag(FLAG_PERMISSION_AUTO_REVOKED)
- newFlags = if (isOneTime) {
- newFlags.setFlag(FLAG_PERMISSION_ONE_TIME)
- } else {
- newFlags.clearFlag(FLAG_PERMISSION_ONE_TIME)
- }
+ newFlags =
+ if (isOneTime) {
+ newFlags.setFlag(FLAG_PERMISSION_ONE_TIME)
+ } else {
+ newFlags.clearFlag(FLAG_PERMISSION_ONE_TIME)
+ }
// If we newly grant background access to the fine location, double-guess the user some
// time later if this was really the right choice.
@@ -918,13 +1057,18 @@ object KotlinUtils {
}
if (oldFlags != newFlags) {
- app.packageManager.updatePermissionFlags(perm.name, group.packageInfo.packageName,
- PERMISSION_CONTROLLER_CHANGED_FLAG_MASK, newFlags, user)
+ context.packageManager.updatePermissionFlags(
+ perm.name,
+ group.packageInfo.packageName,
+ PERMISSION_CONTROLLER_CHANGED_FLAG_MASK,
+ newFlags,
+ user
+ )
}
val newState = PermState(newFlags, isGranted)
- return LightPermission(perm.pkgInfo, perm.permInfo, newState,
- perm.foregroundPerms) to shouldKill
+ return LightPermission(perm.pkgInfo, perm.permInfo, newState, perm.foregroundPerms) to
+ shouldKill
}
/**
@@ -937,9 +1081,7 @@ object KotlinUtils {
* @param userFixed If the user requested that they do not want to be asked again
* @param oneTime If the permission should be mark as one-time
* @param filterPermissions If not specified, all permissions of the group will be revoked.
- * Otherwise only permissions in {@code filterPermissions} will be
- * revoked.
- *
+ * Otherwise only permissions in {@code filterPermissions} will be revoked.
* @return a LightAppPermGroup representing the new state
*/
@JvmOverloads
@@ -949,10 +1091,17 @@ object KotlinUtils {
userFixed: Boolean = false,
oneTime: Boolean = false,
forceRemoveRevokedCompat: Boolean = false,
- filterPermissions: List<String> = group.permissions.keys.toList()
+ filterPermissions: Collection<String> = group.permissions.keys
): LightAppPermGroup {
- return revokeRuntimePermissions(app, group, false, userFixed, oneTime,
- forceRemoveRevokedCompat, filterPermissions)
+ return revokeRuntimePermissions(
+ app,
+ group,
+ false,
+ userFixed,
+ oneTime,
+ forceRemoveRevokedCompat,
+ filterPermissions
+ )
}
/**
@@ -964,9 +1113,7 @@ object KotlinUtils {
* @param group The group whose permissions should be revoked
* @param userFixed If the user requested that they do not want to be asked again
* @param filterPermissions If not specified, all permissions of the group will be revoked.
- * Otherwise only permissions in {@code filterPermissions} will be
- * revoked.
- *
+ * Otherwise only permissions in {@code filterPermissions} will be revoked.
* @return a LightAppPermGroup representing the new state
*/
@JvmOverloads
@@ -976,10 +1123,17 @@ object KotlinUtils {
userFixed: Boolean = false,
oneTime: Boolean = false,
forceRemoveRevokedCompat: Boolean = false,
- filterPermissions: List<String> = group.permissions.keys.toList()
+ filterPermissions: Collection<String> = group.permissions.keys
): LightAppPermGroup {
- return revokeRuntimePermissions(app, group, true, userFixed, oneTime,
- forceRemoveRevokedCompat, filterPermissions)
+ return revokeRuntimePermissions(
+ app,
+ group,
+ true,
+ userFixed,
+ oneTime,
+ forceRemoveRevokedCompat,
+ filterPermissions
+ )
}
private fun revokeRuntimePermissions(
@@ -989,8 +1143,9 @@ object KotlinUtils {
userFixed: Boolean,
oneTime: Boolean,
forceRemoveRevokedCompat: Boolean = false,
- filterPermissions: List<String>
+ filterPermissions: Collection<String>
): LightAppPermGroup {
+ val deviceId = group.deviceId
val wasOneTime = group.isOneTime
val newPerms = group.permissions.toMutableMap()
var shouldKillForAnyPermission = false
@@ -999,8 +1154,14 @@ object KotlinUtils {
val isBackgroundPerm = permName in group.backgroundPermNames
if (isBackgroundPerm == revokeBackground) {
val (newPerm, shouldKill) =
- revokeRuntimePermission(app, perm, userFixed, oneTime, forceRemoveRevokedCompat,
- group)
+ revokeRuntimePermission(
+ app,
+ perm,
+ userFixed,
+ oneTime,
+ forceRemoveRevokedCompat,
+ group
+ )
newPerms[newPerm.name] = newPerm
shouldKillForAnyPermission = shouldKillForAnyPermission || shouldKill
}
@@ -1008,15 +1169,27 @@ object KotlinUtils {
if (shouldKillForAnyPermission && !shouldSkipKillForGroup(app, group)) {
(app.getSystemService(ActivityManager::class.java) as ActivityManager).killUid(
- group.packageInfo.uid, KILL_REASON_APP_OP_CHANGE)
+ group.packageInfo.uid,
+ KILL_REASON_APP_OP_CHANGE
+ )
}
- val newGroup = LightAppPermGroup(group.packageInfo, group.permGroupInfo, newPerms,
- group.hasInstallToRuntimeSplit, group.specialLocationGrant)
+ val newGroup =
+ LightAppPermGroup(
+ group.packageInfo,
+ group.permGroupInfo,
+ newPerms,
+ group.hasInstallToRuntimeSplit,
+ group.specialLocationGrant
+ )
if (wasOneTime && !anyPermsOfPackageOneTimeGranted(app, newGroup.packageInfo, newGroup)) {
- app.getSystemService(PermissionManager::class.java)!!.stopOneTimePermissionSession(
- group.packageName)
+ // Create a new context with the given deviceId so that permission updates will be bound
+ // to the device
+ val context = ContextCompat.createDeviceContext(app.applicationContext, deviceId)
+ context
+ .getSystemService(PermissionManager::class.java)!!
+ .stopOneTimePermissionSession(group.packageName)
}
return newGroup
}
@@ -1038,8 +1211,9 @@ object KotlinUtils {
postRevokeHandler: Runnable?
) {
GlobalScope.launch(Dispatchers.Main) {
- val group = LightAppPermGroupLiveData[packageName, permissionGroupName, user]
- .getInitializedValue()
+ val group =
+ LightAppPermGroupLiveData[packageName, permissionGroupName, user]
+ .getInitializedValue()
if (group != null) {
revokeBackgroundRuntimePermissions(context.application, group)
}
@@ -1055,7 +1229,6 @@ object KotlinUtils {
* @param app The current application
* @param packageInfo The packageInfo we wish to examine
* @param group Optional, the current app permission group we are examining
- *
* @return true if any permission in the package is granted for one time, false otherwise
*/
private fun anyPermsOfPackageOneTimeGranted(
@@ -1071,11 +1244,12 @@ object KotlinUtils {
if (permName in group?.permissions ?: emptyMap()) {
continue
}
- val flags = app.packageManager.getPermissionFlags(permName, packageInfo.packageName,
- user) and FLAG_PERMISSION_ONE_TIME
- val granted = packageInfo.requestedPermissionsFlags[idx] ==
- PackageManager.PERMISSION_GRANTED &&
- (flags and FLAG_PERMISSION_REVOKED_COMPAT) == 0
+ val flags =
+ app.packageManager.getPermissionFlags(permName, packageInfo.packageName, user) and
+ FLAG_PERMISSION_ONE_TIME
+ val granted =
+ packageInfo.requestedPermissionsFlags[idx] == PackageManager.PERMISSION_GRANTED &&
+ (flags and FLAG_PERMISSION_REVOKED_COMPAT) == 0
if (granted && (flags and FLAG_PERMISSION_ONE_TIME) != 0) {
return true
}
@@ -1089,10 +1263,9 @@ object KotlinUtils {
* @param perm The permission which should be revoked.
* @param userFixed If the user requested that they do not want to be asked again
* @param group An optional app permission group in which to look for background or foreground
- * permissions
- *
+ * permissions
* @return a LightPermission and boolean pair <permission with updated state (or the original
- * state, if it wasn't changed), should kill app>
+ * state, if it wasn't changed), should kill app>
*/
private fun revokeRuntimePermission(
app: Application,
@@ -1109,18 +1282,32 @@ object KotlinUtils {
val user = UserHandle.getUserHandleForUid(group.packageInfo.uid)
var newFlags = perm.flags
+ val deviceId = group.deviceId
var isGranted = perm.isGrantedIncludingAppOp
val supportsRuntime = group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.M
var shouldKill = false
val affectsAppOp = permissionToOp(perm.name) != null || perm.isBackgroundPermission
+ // Create a new context with the given deviceId so that permission updates will be bound
+ // to the device
+ val context = ContextCompat.createDeviceContext(app.applicationContext, deviceId)
+
if (perm.isGrantedIncludingAppOp || (perm.isCompatRevoked && forceRemoveRevokedCompat)) {
- if (supportsRuntime && !isPermissionSplitFromNonRuntime(app, perm.name,
- group.packageInfo.targetSdkVersion)) {
+ if (
+ supportsRuntime &&
+ !isPermissionSplitFromNonRuntime(
+ app,
+ perm.name,
+ group.packageInfo.targetSdkVersion
+ )
+ ) {
// Revoke the permission if needed.
- app.packageManager.revokeRuntimePermission(group.packageInfo.packageName,
- perm.name, user)
+ context.packageManager.revokeRuntimePermission(
+ group.packageInfo.packageName,
+ perm.name,
+ user
+ )
isGranted = false
if (forceRemoveRevokedCompat) {
newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)
@@ -1139,24 +1326,33 @@ object KotlinUtils {
newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
if (affectsAppOp) {
+ // TODO: Update this method once AppOp is device aware
disallowAppOp(app, perm, group)
}
}
// Update the permission flags.
// Take a note that the user fixed the permission, if applicable.
- newFlags = if (userFixed) newFlags.setFlag(PackageManager.FLAG_PERMISSION_USER_FIXED)
- else newFlags.clearFlag(PackageManager.FLAG_PERMISSION_USER_FIXED)
- newFlags = if (oneTime) newFlags.clearFlag(PackageManager.FLAG_PERMISSION_USER_SET)
- else newFlags.setFlag(PackageManager.FLAG_PERMISSION_USER_SET)
- newFlags = if (oneTime) newFlags.setFlag(PackageManager.FLAG_PERMISSION_ONE_TIME)
- else newFlags.clearFlag(PackageManager.FLAG_PERMISSION_ONE_TIME)
+ newFlags =
+ if (userFixed) newFlags.setFlag(PackageManager.FLAG_PERMISSION_USER_FIXED)
+ else newFlags.clearFlag(PackageManager.FLAG_PERMISSION_USER_FIXED)
+ newFlags =
+ if (oneTime) newFlags.clearFlag(PackageManager.FLAG_PERMISSION_USER_SET)
+ else newFlags.setFlag(PackageManager.FLAG_PERMISSION_USER_SET)
+ newFlags =
+ if (oneTime) newFlags.setFlag(PackageManager.FLAG_PERMISSION_ONE_TIME)
+ else newFlags.clearFlag(PackageManager.FLAG_PERMISSION_ONE_TIME)
newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_AUTO_REVOKED)
newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED)
if (perm.flags != newFlags) {
- app.packageManager.updatePermissionFlags(perm.name, group.packageInfo.packageName,
- PERMISSION_CONTROLLER_CHANGED_FLAG_MASK, newFlags, user)
+ context.packageManager.updatePermissionFlags(
+ perm.name,
+ group.packageInfo.packageName,
+ PERMISSION_CONTROLLER_CHANGED_FLAG_MASK,
+ newFlags,
+ user
+ )
}
// If we revoke background access to the fine location, we trigger a check to remove
@@ -1172,17 +1368,18 @@ object KotlinUtils {
}
if (cancelLocationAccessWarning) {
// cancel location access warning notification
- LocationAccessCheck(app, null).cancelBackgroundAccessWarningNotification(
- group.packageInfo.packageName,
- user,
- true
- )
+ LocationAccessCheck(app, null)
+ .cancelBackgroundAccessWarningNotification(
+ group.packageInfo.packageName,
+ user,
+ true
+ )
}
}
val newState = PermState(newFlags, isGranted)
- return LightPermission(perm.pkgInfo, perm.permInfo, newState,
- perm.foregroundPerms) to shouldKill
+ return LightPermission(perm.pkgInfo, perm.permInfo, newState, perm.foregroundPerms) to
+ shouldKill
}
private fun Int.setFlag(flagToSet: Int): Int {
@@ -1196,27 +1393,20 @@ object KotlinUtils {
/**
* Allow the app op for a permission/uid.
*
- * <p>There are three cases:
- * <dl>
- * <dt>The permission is not split into foreground/background</dt>
- * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_ALLOWED}</dd>
- * <dt>The permission is a foreground permission:</dt>
- * <dd><dl><dt>The background permission permission is granted</dt>
- * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_ALLOWED}</dd>
- * <dt>The background permission permission is <u>not</u> granted</dt>
- * <dd>The app op matching the permission will be set to
- * {@link AppOpsManager#MODE_FOREGROUND}</dd>
- * </dl></dd>
- * <dt>The permission is a background permission:</dt>
- * <dd>All granted foreground permissions for this background permission will be set to
- * {@link AppOpsManager#MODE_ALLOWED}</dd>
- * </dl>
+ * <p>There are three cases: <dl> <dt>The permission is not split into
+ * foreground/background</dt> <dd>The app op matching the permission will be set to {@link
+ * AppOpsManager#MODE_ALLOWED}</dd> <dt>The permission is a foreground permission:</dt>
+ * <dd><dl><dt>The background permission permission is granted</dt> <dd>The app op matching the
+ * permission will be set to {@link AppOpsManager#MODE_ALLOWED}</dd> <dt>The background
+ * permission permission is <u>not</u> granted</dt> <dd>The app op matching the permission will
+ * be set to {@link AppOpsManager#MODE_FOREGROUND}</dd> </dl></dd> <dt>The permission is a
+ * background permission:</dt> <dd>All granted foreground permissions for this background
+ * permission will be set to {@link AppOpsManager#MODE_ALLOWED}</dd> </dl>
*
* @param app The current application
* @param perm The LightPermission whose app op should be allowed
- * @param group The LightAppPermGroup which will be looked in for foreground or
- * background LightPermission objects
- *
+ * @param group The LightAppPermGroup which will be looked in for foreground or background
+ * LightPermission objects
* @return {@code true} iff app-op was changed
*/
private fun allowAppOp(
@@ -1235,25 +1425,29 @@ object KotlinUtils {
val appOpName = permissionToOp(foregroundPermName) ?: continue
if (fgPerm != null && fgPerm.isGrantedIncludingAppOp) {
- wasChanged = setOpMode(appOpName, uid, packageName, MODE_ALLOWED,
- appOpsManager) || wasChanged
+ wasChanged =
+ setOpMode(appOpName, uid, packageName, MODE_ALLOWED, appOpsManager) ||
+ wasChanged
}
}
} else {
val appOpName = permissionToOp(perm.name) ?: return false
if (perm.backgroundPermission != null) {
- wasChanged = if (group.permissions.containsKey(perm.backgroundPermission)) {
- val bgPerm = group.permissions[perm.backgroundPermission]
- val mode = if (bgPerm != null && bgPerm.isGrantedIncludingAppOp) MODE_ALLOWED
- else MODE_FOREGROUND
-
- setOpMode(appOpName, uid, packageName, mode, appOpsManager)
- } else {
- // The app requested a permission that has a background permission but it did
- // not request the background permission, hence it can never get background
- // access
- setOpMode(appOpName, uid, packageName, MODE_FOREGROUND, appOpsManager)
- }
+ wasChanged =
+ if (group.permissions.containsKey(perm.backgroundPermission)) {
+ val bgPerm = group.permissions[perm.backgroundPermission]
+ val mode =
+ if (bgPerm != null && bgPerm.isGrantedIncludingAppOp) MODE_ALLOWED
+ else MODE_FOREGROUND
+
+ setOpMode(appOpName, uid, packageName, mode, appOpsManager)
+ } else {
+ // The app requested a permission that has a background permission but it
+ // did
+ // not request the background permission, hence it can never get background
+ // access
+ setOpMode(appOpName, uid, packageName, MODE_FOREGROUND, appOpsManager)
+ }
} else {
wasChanged = setOpMode(appOpName, uid, packageName, MODE_ALLOWED, appOpsManager)
}
@@ -1264,22 +1458,17 @@ object KotlinUtils {
/**
* Disallow the app op for a permission/uid.
*
- * <p>There are three cases:
- * <dl>
- * <dt>The permission is not split into foreground/background</dt>
- * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_IGNORED}</dd>
- * <dt>The permission is a foreground permission:</dt>
- * <dd>The app op matching the permission will be set to {@link AppOpsManager#MODE_IGNORED}</dd>
- * <dt>The permission is a background permission:</dt>
- * <dd>All granted foreground permissions for this background permission will be set to
- * {@link AppOpsManager#MODE_FOREGROUND}</dd>
- * </dl>
+ * <p>There are three cases: <dl> <dt>The permission is not split into
+ * foreground/background</dt> <dd>The app op matching the permission will be set to {@link
+ * AppOpsManager#MODE_IGNORED}</dd> <dt>The permission is a foreground permission:</dt> <dd>The
+ * app op matching the permission will be set to {@link AppOpsManager#MODE_IGNORED}</dd> <dt>The
+ * permission is a background permission:</dt> <dd>All granted foreground permissions for this
+ * background permission will be set to {@link AppOpsManager#MODE_FOREGROUND}</dd> </dl>
*
* @param app The current application
* @param perm The LightPermission whose app op should be allowed
- * @param group The LightAppPermGroup which will be looked in for foreground or
- * background LightPermission objects
- *
+ * @param group The LightAppPermGroup which will be looked in for foreground or background
+ * LightPermission objects
* @return {@code true} iff app-op was changed
*/
private fun disallowAppOp(
@@ -1297,8 +1486,9 @@ object KotlinUtils {
val fgPerm = group.permissions[foregroundPermName]
if (fgPerm != null && fgPerm.isGrantedIncludingAppOp) {
val appOpName = permissionToOp(foregroundPermName) ?: return false
- wasChanged = wasChanged || setOpMode(appOpName, uid, packageName,
- MODE_FOREGROUND, appOpsManager)
+ wasChanged =
+ wasChanged ||
+ setOpMode(appOpName, uid, packageName, MODE_FOREGROUND, appOpsManager)
}
}
} else {
@@ -1316,7 +1506,6 @@ object KotlinUtils {
* @param packageName The package the app-op belongs to
* @param mode The new mode
* @param manager The app ops manager to use to change the app op
- *
* @return {@code true} iff app-op was changed
*/
private fun setOpMode(
@@ -1339,22 +1528,25 @@ object KotlinUtils {
return false
}
- return shouldSkipKillOnPermDeny(app, POST_NOTIFICATIONS, group.packageName,
- group.userHandle)
+ return shouldSkipKillOnPermDeny(
+ app,
+ POST_NOTIFICATIONS,
+ group.packageName,
+ group.userHandle
+ )
}
/**
* Determine if the usual "kill app on permission denial" should be skipped. It should be
- * skipped if the permission is POST_NOTIFICATIONS, the app holds the BACKUP permission, and
- * a backup restore is currently in progress.
+ * skipped if the permission is POST_NOTIFICATIONS, the app holds the BACKUP permission, and a
+ * backup restore is currently in progress.
*
* @param app the current application
* @param permission the permission being denied
* @param packageName the package the permission was denied for
* @param user the user whose package the permission was denied for
- *
* @return true if the permission denied was POST_NOTIFICATIONS, the app is a backup app, and a
- * backup restore is in progress, false otherwise
+ * backup restore is in progress, false otherwise
*/
fun shouldSkipKillOnPermDeny(
app: Application,
@@ -1363,17 +1555,27 @@ object KotlinUtils {
user: UserHandle
): Boolean {
val userContext: Context = Utils.getUserContext(app, user)
- if (permission != POST_NOTIFICATIONS || userContext.packageManager
- .checkPermission(BACKUP, packageName) != PackageManager.PERMISSION_GRANTED) {
+ if (
+ permission != POST_NOTIFICATIONS ||
+ userContext.packageManager.checkPermission(BACKUP, packageName) !=
+ PackageManager.PERMISSION_GRANTED
+ ) {
return false
}
return try {
- val isInSetup = Settings.Secure.getInt(userContext.contentResolver,
- Settings.Secure.USER_SETUP_COMPLETE, user.identifier) == 0
- val isInDeferredSetup = Settings.Secure.getInt(userContext.contentResolver,
- Settings.Secure.USER_SETUP_PERSONALIZATION_STATE, user.identifier) ==
- Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED
+ val isInSetup =
+ Settings.Secure.getInt(
+ userContext.contentResolver,
+ Settings.Secure.USER_SETUP_COMPLETE,
+ user.identifier
+ ) == 0
+ val isInDeferredSetup =
+ Settings.Secure.getInt(
+ userContext.contentResolver,
+ Settings.Secure.USER_SETUP_PERSONALIZATION_STATE,
+ user.identifier
+ ) == Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED
isInSetup || isInDeferredSetup
} catch (e: Settings.SettingNotFoundException) {
Log.w(LOG_TAG, "Failed to check if the user is in restore: $e")
@@ -1387,22 +1589,27 @@ object KotlinUtils {
*
* @param context: The context from which to retrieve the package
* @param packageName: The package name to check
- *
* @return whether or not the given package has a launch intent
*/
fun packageHasLaunchIntent(context: Context, packageName: String): Boolean {
val intentToResolve = Intent(ACTION_MAIN)
intentToResolve.addCategory(CATEGORY_INFO)
intentToResolve.setPackage(packageName)
- var resolveInfos = context.packageManager.queryIntentActivities(intentToResolve,
- MATCH_DIRECT_BOOT_AWARE or MATCH_DIRECT_BOOT_UNAWARE)
+ var resolveInfos =
+ context.packageManager.queryIntentActivities(
+ intentToResolve,
+ MATCH_DIRECT_BOOT_AWARE or MATCH_DIRECT_BOOT_UNAWARE
+ )
if (resolveInfos.size <= 0) {
intentToResolve.removeCategory(CATEGORY_INFO)
intentToResolve.addCategory(CATEGORY_LAUNCHER)
intentToResolve.setPackage(packageName)
- resolveInfos = context.packageManager.queryIntentActivities(intentToResolve,
- MATCH_DIRECT_BOOT_AWARE or MATCH_DIRECT_BOOT_UNAWARE)
+ resolveInfos =
+ context.packageManager.queryIntentActivities(
+ intentToResolve,
+ MATCH_DIRECT_BOOT_AWARE or MATCH_DIRECT_BOOT_UNAWARE
+ )
}
return resolveInfos.size > 0
}
@@ -1420,39 +1627,55 @@ object KotlinUtils {
isFineSelected: Boolean
) {
if (isFineSelected) {
- setGroupFlags(app, group,
+ setGroupFlags(
+ app,
+ group,
PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY to true,
- filterPermissions = listOf(ACCESS_FINE_LOCATION))
- setGroupFlags(app, group,
+ filterPermissions = listOf(ACCESS_FINE_LOCATION)
+ )
+ setGroupFlags(
+ app,
+ group,
PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY to false,
- filterPermissions = listOf(Manifest.permission.ACCESS_COARSE_LOCATION))
+ filterPermissions = listOf(Manifest.permission.ACCESS_COARSE_LOCATION)
+ )
} else {
- setGroupFlags(app, group,
+ setGroupFlags(
+ app,
+ group,
PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY to false,
- filterPermissions = listOf(ACCESS_FINE_LOCATION))
- setGroupFlags(app, group,
+ filterPermissions = listOf(ACCESS_FINE_LOCATION)
+ )
+ setGroupFlags(
+ app,
+ group,
PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY to true,
- filterPermissions = listOf(Manifest.permission.ACCESS_COARSE_LOCATION))
+ filterPermissions = listOf(Manifest.permission.ACCESS_COARSE_LOCATION)
+ )
}
}
/**
- * Determines whether we should show the safety protection resources.
- * We show the resources only if
- * (1) the build version is T or after and
- * (2) the feature flag safety_protection_enabled is enabled and
- * (3) the config value config_safetyProtectionEnabled is enabled/true and
- * (4) the resources exist (currently the resources only exist on GMS devices)
+ * Determines whether we should show the safety protection resources. We show the resources only
+ * if (1) the build version is T or after and (2) the feature flag safety_protection_enabled is
+ * enabled and (3) the config value config_safetyProtectionEnabled is enabled/true and (4) the
+ * resources exist (currently the resources only exist on GMS devices)
*/
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
fun shouldShowSafetyProtectionResources(context: Context): Boolean {
return try {
SdkLevel.isAtLeastT() &&
DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY, SAFETY_PROTECTION_RESOURCES_ENABLED, false) &&
- context.getResources().getBoolean(
- Resources.getSystem()
- .getIdentifier("config_safetyProtectionEnabled", "bool", "android")) &&
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SAFETY_PROTECTION_RESOURCES_ENABLED,
+ false
+ ) &&
+ context
+ .getResources()
+ .getBoolean(
+ Resources.getSystem()
+ .getIdentifier("config_safetyProtectionEnabled", "bool", "android")
+ ) &&
context.getDrawable(android.R.drawable.ic_safety_protection) != null &&
!context.getString(android.R.string.safety_protection_display_text).isNullOrEmpty()
} catch (e: Resources.NotFoundException) {
@@ -1476,8 +1699,7 @@ object KotlinUtils {
installerPackageName: String?,
packageName: String?
): Intent? {
- val intent: Intent = Intent(Intent.ACTION_SHOW_APP_INFO)
- .setPackage(installerPackageName)
+ val intent: Intent = Intent(Intent.ACTION_SHOW_APP_INFO).setPackage(installerPackageName)
val result: Intent? = resolveActivityForIntent(context, intent)
if (result != null) {
result.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
@@ -1508,9 +1730,10 @@ object KotlinUtils {
val color: Int
// If U resources are available, and this is a U+ device, use those
if (SdkLevel.isAtLeastU()) {
- val scContext = SafetyCenterResourcesContext(context)
- val uIcon = scContext.getIconByDrawableName("ic_notification_badge_general")
- val uColor = scContext.getColorByName("notification_tint_normal")
+ val safetyCenterResourcesApk = SafetyCenterResourcesApk(context)
+ val uIcon =
+ safetyCenterResourcesApk.getIconByDrawableName("ic_notification_badge_general")
+ val uColor = safetyCenterResourcesApk.getColorByName("notification_tint_normal")
if (uIcon != null && uColor != null) {
appLabel = context.getString(R.string.safety_privacy_qs_tile_title)
return NotificationResources(appLabel, uIcon, uColor)
@@ -1519,24 +1742,21 @@ object KotlinUtils {
// Use PbA branding if available, otherwise default to more generic branding
if (shouldShowSafetyProtectionResources(context)) {
- appLabel = Html.fromHtml(context.getString(
- android.R.string.safety_protection_display_text), 0).toString()
- smallIcon =
- Icon.createWithResource(context, android.R.drawable.ic_safety_protection)
+ appLabel =
+ Html.fromHtml(context.getString(android.R.string.safety_protection_display_text), 0)
+ .toString()
+ smallIcon = Icon.createWithResource(context, android.R.drawable.ic_safety_protection)
color = context.getColor(R.color.safety_center_info)
} else {
appLabel = context.getString(R.string.safety_center_notification_app_label)
- smallIcon =
- Icon.createWithResource(context, R.drawable.ic_settings_notification)
+ smallIcon = Icon.createWithResource(context, R.drawable.ic_settings_notification)
color = context.getColor(android.R.color.system_notification_accent_color)
}
return NotificationResources(appLabel, smallIcon, color)
}
}
-/**
- * Get the [value][LiveData.getValue], suspending until [isInitialized] if not yet so
- */
+/** Get the [value][LiveData.getValue], suspending until [isInitialized] if not yet so */
suspend fun <T, LD : LiveData<T>> LD.getInitializedValue(
observe: LD.(Observer<T>) -> Unit = { observeForever(it) },
isValueInitialized: LD.() -> Boolean = { value != null }
@@ -1547,20 +1767,20 @@ suspend fun <T, LD : LiveData<T>> LD.getInitializedValue(
} else {
suspendCoroutine { continuation: Continuation<T> ->
val observer = AtomicReference<Observer<T>>()
- observer.set(Observer { newValue ->
- if (isValueInitialized()) {
- GlobalScope.launch(Dispatchers.Main) {
- observer.getAndSet(null)?.let { observerSnapshot ->
- removeObserver(observerSnapshot)
- continuation.resume(newValue)
+ observer.set(
+ Observer { newValue ->
+ if (isValueInitialized()) {
+ GlobalScope.launch(Dispatchers.Main) {
+ observer.getAndSet(null)?.let { observerSnapshot ->
+ removeObserver(observerSnapshot)
+ continuation.resume(newValue)
+ }
}
}
}
- })
+ )
- GlobalScope.launch(Dispatchers.Main) {
- observe(observer.get())
- }
+ GlobalScope.launch(Dispatchers.Main) { observe(observer.get()) }
}
}
}
@@ -1568,8 +1788,8 @@ suspend fun <T, LD : LiveData<T>> LD.getInitializedValue(
/**
* A parallel equivalent of [map]
*
- * Starts the given suspending function for each item in the collection without waiting for
- * previous ones to complete, then suspends until all the started operations finish.
+ * Starts the given suspending function for each item in the collection without waiting for previous
+ * ones to complete, then suspends until all the started operations finish.
*/
suspend inline fun <T, R> Iterable<T>.mapInParallel(
context: CoroutineContext,
@@ -1591,8 +1811,8 @@ suspend inline fun <T> Iterable<T>.forEachInParallel(
}
/**
- * Check that we haven't already started transitioning to a given destination. If we haven't,
- * start navigating to that destination.
+ * Check that we haven't already started transitioning to a given destination. If we haven't, start
+ * navigating to that destination.
*
* @param destResId The ID of the desired destination
* @param args The optional bundle of args to be passed to the destination
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/MultiDeviceUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/MultiDeviceUtils.kt
new file mode 100644
index 000000000..2719b9766
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/MultiDeviceUtils.kt
@@ -0,0 +1,50 @@
+package com.android.permissioncontroller.permission.utils
+
+import android.Manifest
+import android.companion.virtual.VirtualDeviceManager
+import android.content.Context
+import android.os.Build
+import android.provider.Settings
+import androidx.annotation.ChecksSdkIntAtLeast
+import com.android.modules.utils.build.SdkLevel
+import com.android.permission.flags.Flags
+
+object MultiDeviceUtils {
+ const val DEFAULT_REMOTE_DEVICE_NAME = "remote device"
+
+ /**
+ * Defines what runtime permissions are device aware. This can be replaced with an API from VDM
+ * which can take device's capabilities into account
+ */
+ // TODO: b/298661870 - Use new API to get the list of device aware permissions
+ private val DEVICE_AWARE_PERMISSIONS: Set<String> =
+ setOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
+
+ @JvmStatic
+ fun isPermissionDeviceAware(permission: String): Boolean =
+ permission in DEVICE_AWARE_PERMISSIONS
+
+ @JvmStatic
+ @ChecksSdkIntAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ fun isDeviceAwareGrantFlowEnabled(): Boolean {
+ return SdkLevel.isAtLeastV() && Flags.deviceAwarePermissionGrant()
+ }
+
+ @JvmStatic
+ fun getDeviceName(context: Context, deviceId: Int): String? {
+ // Pre Android V no permission requests can affect the VirtualDevice, thus return local
+ // device name.
+ if (!SdkLevel.isAtLeastV() || deviceId == ContextCompat.DEVICE_ID_DEFAULT) {
+ return Settings.Global.getString(context.contentResolver, Settings.Global.DEVICE_NAME)
+ }
+ val vdm: VirtualDeviceManager? = context.getSystemService(VirtualDeviceManager::class.java)
+ if (vdm != null) {
+ val virtualDevice = vdm.getVirtualDevice(deviceId)
+ if (virtualDevice != null) {
+ return if (virtualDevice.displayName != null) virtualDevice.displayName.toString()
+ else DEFAULT_REMOTE_DEVICE_NAME
+ }
+ }
+ throw IllegalArgumentException("No device name for device: $deviceId")
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt
index b06a09b28..840a033c3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt
@@ -23,10 +23,9 @@ import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP
import android.util.Log
-
import com.android.modules.utils.build.SdkLevel
-import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permission.safetylabel.DataCategoryConstants
+import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
/**
* This file contains the canonical mapping of permission to permission group, used in the
@@ -36,15 +35,16 @@ object PermissionMapping {
private val LOG_TAG = "PermissionMapping"
- private val PERMISSION_GROUPS_TO_DATA_CATEGORIES: Map<String, List<String>> = mapOf(
- Manifest.permission_group.LOCATION to listOf(DataCategoryConstants.CATEGORY_LOCATION))
+ private val PERMISSION_GROUPS_TO_DATA_CATEGORIES: Map<String, List<String>> =
+ mapOf(Manifest.permission_group.LOCATION to listOf(DataCategoryConstants.CATEGORY_LOCATION))
@JvmField
val SENSOR_DATA_PERMISSIONS: List<String> =
listOf(
Manifest.permission_group.LOCATION,
Manifest.permission_group.CAMERA,
- Manifest.permission_group.MICROPHONE)
+ Manifest.permission_group.MICROPHONE
+ )
@JvmField
val STORAGE_SUPERGROUP_PERMISSIONS: List<String> =
@@ -53,7 +53,8 @@ object PermissionMapping {
listOf(
Manifest.permission_group.STORAGE,
Manifest.permission_group.READ_MEDIA_AURAL,
- Manifest.permission_group.READ_MEDIA_VISUAL)
+ Manifest.permission_group.READ_MEDIA_VISUAL
+ )
val PARTIAL_MEDIA_PERMISSIONS: MutableSet<String> = mutableSetOf()
@@ -68,7 +69,6 @@ object PermissionMapping {
private val HEALTH_PERMISSIONS_SET: MutableSet<String> = mutableSetOf()
-
init {
PLATFORM_PERMISSIONS[Manifest.permission.READ_CONTACTS] = Manifest.permission_group.CONTACTS
PLATFORM_PERMISSIONS[Manifest.permission.WRITE_CONTACTS] =
@@ -202,7 +202,6 @@ object PermissionMapping {
* platform permission.
*
* @param permission the permission to resolve
- *
* @return The group the permission belongs to
*/
@JvmStatic
@@ -214,7 +213,6 @@ object PermissionMapping {
* Get name of the permission group a permission belongs to.
*
* @param permission the [info][PermissionInfo] of the permission to resolve
- *
* @return The group the permission belongs to
*/
@JvmStatic
@@ -230,9 +228,8 @@ object PermissionMapping {
* Get the names for all platform permissions belonging to a group.
*
* @param group the group
- *
* @return The permission names or an empty list if the group does not have platform runtime
- * permissions
+ * permissions
*/
@JvmStatic
fun getPlatformPermissionNamesOfGroup(group: String): List<String> {
@@ -245,19 +242,19 @@ object PermissionMapping {
*
* @param pm Package manager to use to resolve permission infos
* @param group the group
- *
* @return The infos for platform permissions belonging to the group or an empty list if the
- * group does not have platform runtime permissions
+ * group does not have platform runtime permissions
*/
@JvmStatic
fun getPlatformPermissionsOfGroup(pm: PackageManager, group: String): List<PermissionInfo> {
val permInfos = mutableListOf<PermissionInfo>()
for (permName in PLATFORM_PERMISSION_GROUPS[group] ?: emptyList()) {
- val permInfo: PermissionInfo = try {
+ val permInfo: PermissionInfo =
+ try {
pm.getPermissionInfo(permName, 0)
- } catch (e: PackageManager.NameNotFoundException) {
- throw IllegalStateException("$permName not defined by platform", e)
- }
+ } catch (e: PackageManager.NameNotFoundException) {
+ throw IllegalStateException("$permName not defined by platform", e)
+ }
permInfos.add(permInfo)
}
return permInfos
@@ -300,6 +297,7 @@ object PermissionMapping {
/**
* Whether the permission group supports one-time
+ *
* @param permissionGroup The permission group to check
* @return `true` iff the group supports one-time
*/
@@ -308,9 +306,7 @@ object PermissionMapping {
return ONE_TIME_PERMISSION_GROUPS.contains(permissionGroup)
}
- /**
- * Adds health permissions as platform permissions.
- */
+ /** Adds health permissions as platform permissions. */
@JvmStatic
fun addHealthPermissionsToPlatform(permissions: Set<String>) {
if (permissions.isEmpty()) {
@@ -334,8 +330,13 @@ object PermissionMapping {
* grant. Otherwise, ACCESS_MEDIA_LOCATION is considered a full grant (for compatibility).
*/
fun getPartialStorageGrantPermissionsForGroup(group: LightAppPermGroup): Set<String> {
- val appSupportsPickerPrompt = group
- .permissions[Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED]?.isImplicit == false
+ if (!KotlinUtils.isPhotoPickerPromptSupported()) {
+ return emptySet()
+ }
+
+ val appSupportsPickerPrompt =
+ group.permissions[Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED]?.isImplicit ==
+ false
return if (appSupportsPickerPrompt) {
PARTIAL_MEDIA_PERMISSIONS
@@ -344,9 +345,7 @@ object PermissionMapping {
}
}
- /**
- * Returns true if the given permission is a health platform permission.
- */
+ /** Returns true if the given permission is a health platform permission. */
@JvmStatic
fun isHealthPermission(permissionName: String): Boolean {
return HEALTH_PERMISSIONS_SET.contains(permissionName)
@@ -382,8 +381,8 @@ object PermissionMapping {
/**
* Get the SafetyLabel categories pertaining to a specified permission group.
*
- * @return The categories, or an empty list if the group does not have a supported mapping
- * to safety label category
+ * @return The categories, or an empty list if the group does not have a supported mapping to
+ * safety label category
*/
fun getDataCategoriesForPermissionGroup(permissionGroupName: String): List<String> {
return if (isSafetyLabelAwarePermissionGroup(permissionGroupName)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/SystemTimeSource.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/SystemTimeSource.kt
index dc05ededc..116c498be 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/SystemTimeSource.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/SystemTimeSource.kt
@@ -18,9 +18,7 @@ package com.android.permissioncontroller.permission.utils
import android.os.SystemClock
-/**
- * Time source that uses the system time.
- */
+/** Time source that uses the system time. */
class SystemTimeSource : TimeSource {
override fun currentTimeMillis(): Long {
@@ -30,4 +28,4 @@ class SystemTimeSource : TimeSource {
override fun elapsedRealtime(): Long {
return SystemClock.elapsedRealtime()
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/TimeSource.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/TimeSource.kt
index 00b93f405..29883e1f3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/TimeSource.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/TimeSource.kt
@@ -16,18 +16,12 @@
package com.android.permissioncontroller.permission.utils
-/**
- * Interface for system time components.
- */
+/** Interface for system time components. */
interface TimeSource {
- /**
- * Returns the current time in milliseconds.
- */
+ /** Returns the current time in milliseconds. */
fun currentTimeMillis(): Long
- /**
- * Returns milliseconds since boot, including time spent in sleep.
- */
+ /** Returns milliseconds since boot, including time spent in sleep. */
fun elapsedRealtime(): Long
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/UserSensitiveFlagsUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/UserSensitiveFlagsUtils.kt
index 3cd9891ee..50cacf876 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/UserSensitiveFlagsUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/UserSensitiveFlagsUtils.kt
@@ -25,9 +25,9 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.data.UserSensitivityLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.UidSensitivityState
import com.android.permissioncontroller.permission.utils.Utils.FLAGS_ALWAYS_USER_SENSITIVE
+import java.lang.IllegalStateException
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
-import java.lang.IllegalStateException
private const val LOG_TAG = "UserSensitiveFlagsUtils"
@@ -35,10 +35,9 @@ private const val LOG_TAG = "UserSensitiveFlagsUtils"
* Update the [PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED] and
* [PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED] for all apps of this user.
*
- * @see UserSensitivityLiveData.loadDataAndPostValue
- *
* @param user The user for whom packages will be updated
* @param callback A callback which will be executed when finished
+ * @see UserSensitivityLiveData.loadDataAndPostValue
*/
fun updateUserSensitiveForUser(user: UserHandle, callback: Runnable) {
GlobalScope.launch(IPC) {
@@ -47,7 +46,8 @@ fun updateUserSensitiveForUser(user: UserHandle, callback: Runnable) {
if (uidUserSensitivity == null) {
callback.run()
throw IllegalStateException(
- "All uids sensitivity liveData should not be null if initialized")
+ "All uids sensitivity liveData should not be null if initialized"
+ )
}
updateUserSensitiveForUidsInternal(uidUserSensitivity, user, callback)
}
@@ -62,28 +62,38 @@ private fun updateUserSensitiveForUidsInternal(
val pm = userContext.packageManager
for ((uid, uidState) in uidsUserSensitivity) {
- for (pkg in uidState.packages) {
- for (perm in pkg.requestedPermissions) {
- var flags = uidState.permStates[perm] ?: continue
+ for (pkg in uidState.packages) {
+ for (perm in pkg.requestedPermissions) {
+ var flags = uidState.permStates[perm] ?: continue
- try {
- val oldFlags = pm.getPermissionFlags(perm, pkg.packageName, user) and
+ try {
+ val oldFlags =
+ pm.getPermissionFlags(perm, pkg.packageName, user) and
FLAGS_ALWAYS_USER_SENSITIVE
- if (flags != oldFlags) {
- pm.updatePermissionFlags(perm, pkg.packageName,
- FLAGS_ALWAYS_USER_SENSITIVE, flags, user)
- }
- } catch (e: IllegalArgumentException) {
- if (e.message?.startsWith("Unknown permission: ") == false) {
- Log.e(LOG_TAG, "Unexpected exception while updating flags for " +
- "${pkg.packageName} (uid $uid) permission $perm", e)
- } else {
- // Unknown permission - ignore
- }
+ if (flags != oldFlags) {
+ pm.updatePermissionFlags(
+ perm,
+ pkg.packageName,
+ FLAGS_ALWAYS_USER_SENSITIVE,
+ flags,
+ user
+ )
+ }
+ } catch (e: IllegalArgumentException) {
+ if (e.message?.startsWith("Unknown permission: ") == false) {
+ Log.e(
+ LOG_TAG,
+ "Unexpected exception while updating flags for " +
+ "${pkg.packageName} (uid $uid) permission $perm",
+ e
+ )
+ } else {
+ // Unknown permission - ignore
}
}
}
}
+ }
callback?.run()
}
@@ -98,8 +108,11 @@ fun updateUserSensitiveForUid(uid: Int, callback: Runnable? = null) {
GlobalScope.launch(IPC) {
val uidSensitivityState = UserSensitivityLiveData[uid].getInitializedValue()
if (uidSensitivityState != null) {
- updateUserSensitiveForUidsInternal(uidSensitivityState,
- UserHandle.getUserHandleForUid(uid), callback)
+ updateUserSensitiveForUidsInternal(
+ uidSensitivityState,
+ UserHandle.getUserHandleForUid(uid),
+ callback
+ )
} else {
Log.e(LOG_TAG, "No packages associated with uid $uid, not updating flags")
callback?.run()
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
index d4354bd72..2c36c0adc 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
@@ -42,6 +42,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_W
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.health.connect.HealthConnectManager.ACTION_MANAGE_HEALTH_PERMISSIONS;
+import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP;
import static android.os.UserHandle.myUserId;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
@@ -73,6 +74,7 @@ import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.SensorPrivacyManager;
+import android.health.connect.HealthConnectManager;
import android.os.Binder;
import android.os.Build;
import android.os.Parcelable;
@@ -109,6 +111,8 @@ import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup;
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo;
+import kotlin.Triple;
+
import java.lang.annotation.Retention;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@@ -120,8 +124,6 @@ import java.util.Locale;
import java.util.Random;
import java.util.Set;
-import kotlin.Triple;
-
public final class Utils {
@Retention(SOURCE)
@@ -160,9 +162,6 @@ public final class Utils {
public static final String PROPERTY_SYSTEM_EXEMPT_HIBERNATION_ENABLED =
"system_exempt_hibernation_enabled";
- /** Whether to show the Permissions Hub. */
- private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
-
/** The timeout for one-time permissions */
private static final String PROPERTY_ONE_TIME_PERMISSIONS_TIMEOUT_MILLIS =
"one_time_permissions_timeout_millis";
@@ -171,10 +170,6 @@ public final class Utils {
private static final String PROPERTY_ONE_TIME_PERMISSIONS_KILLED_DELAY_MILLIS =
"one_time_permissions_killed_delay_millis";
- /** Whether to show location access check notifications. */
- private static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED =
- "location_access_check_enabled";
-
/** Whether to show health permission in various permission controller UIs. */
private static final String PROPERTY_HEALTH_PERMISSION_UI_ENABLED =
"health_permission_ui_enabled";
@@ -195,9 +190,6 @@ public final class Utils {
public static final String PROPERTY_PERMISSION_DECISIONS_MAX_DATA_AGE_MILLIS =
"permission_decisions_max_data_age_millis";
- /** Whether or not warning banner is displayed when device sensors are off **/
- public static final String PROPERTY_WARNING_BANNER_DISPLAY_ENABLED = "warning_banner_enabled";
-
/** All permission whitelists. */
public static final int FLAGS_PERMISSION_WHITELIST_ALL =
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
@@ -222,10 +214,13 @@ public final class Utils {
public static final long ONE_TIME_PERMISSIONS_KILLED_DELAY_MILLIS = 5 * 1000;
private static final ArrayMap<String, Integer> PERM_GROUP_REQUEST_RES;
+ private static final ArrayMap<String, Integer> PERM_GROUP_REQUEST_DEVICE_AWARE_RES;
private static final ArrayMap<String, Integer> PERM_GROUP_REQUEST_DETAIL_RES;
private static final ArrayMap<String, Integer> PERM_GROUP_BACKGROUND_REQUEST_RES;
+ private static final ArrayMap<String, Integer> PERM_GROUP_BACKGROUND_REQUEST_DEVICE_AWARE_RES;
private static final ArrayMap<String, Integer> PERM_GROUP_BACKGROUND_REQUEST_DETAIL_RES;
private static final ArrayMap<String, Integer> PERM_GROUP_UPGRADE_REQUEST_RES;
+ private static final ArrayMap<String, Integer> PERM_GROUP_UPGRADE_REQUEST_DEVICE_AWARE_RES;
private static final ArrayMap<String, Integer> PERM_GROUP_UPGRADE_REQUEST_DETAIL_RES;
/** Permission -> Sensor codes */
@@ -282,6 +277,38 @@ public final class Utils {
PERM_GROUP_REQUEST_RES.put(SENSORS, R.string.permgrouprequest_sensors);
PERM_GROUP_REQUEST_RES.put(NOTIFICATIONS, R.string.permgrouprequest_notifications);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES = new ArrayMap<>();
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(CONTACTS,
+ R.string.permgrouprequest_device_aware_contacts);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(LOCATION,
+ R.string.permgrouprequest_device_aware_location);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(NEARBY_DEVICES,
+ R.string.permgrouprequest_device_aware_nearby_devices);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(CALENDAR,
+ R.string.permgrouprequest_device_aware_calendar);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(SMS, R.string.permgrouprequest_device_aware_sms);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(STORAGE,
+ R.string.permgrouprequest_device_aware_storage);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(READ_MEDIA_AURAL,
+ R.string.permgrouprequest_device_aware_read_media_aural);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(READ_MEDIA_VISUAL,
+ R.string.permgrouprequest_device_aware_read_media_visual);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(MICROPHONE,
+ R.string.permgrouprequest_device_aware_microphone);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES
+ .put(ACTIVITY_RECOGNITION,
+ R.string.permgrouprequest_device_aware_activityRecognition);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(CAMERA,
+ R.string.permgrouprequest_device_aware_camera);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(CALL_LOG,
+ R.string.permgrouprequest_device_aware_calllog);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(PHONE,
+ R.string.permgrouprequest_device_aware_phone);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(SENSORS,
+ R.string.permgrouprequest_device_aware_sensors);
+ PERM_GROUP_REQUEST_DEVICE_AWARE_RES.put(NOTIFICATIONS,
+ R.string.permgrouprequest_device_aware_notifications);
+
PERM_GROUP_REQUEST_DETAIL_RES = new ArrayMap<>();
PERM_GROUP_REQUEST_DETAIL_RES.put(LOCATION, R.string.permgrouprequestdetail_location);
PERM_GROUP_REQUEST_DETAIL_RES.put(MICROPHONE, R.string.permgrouprequestdetail_microphone);
@@ -297,6 +324,16 @@ public final class Utils {
PERM_GROUP_BACKGROUND_REQUEST_RES
.put(SENSORS, R.string.permgroupbackgroundrequest_sensors);
+ PERM_GROUP_BACKGROUND_REQUEST_DEVICE_AWARE_RES = new ArrayMap<>();
+ PERM_GROUP_BACKGROUND_REQUEST_DEVICE_AWARE_RES
+ .put(LOCATION, R.string.permgroupbackgroundrequest_device_aware_location);
+ PERM_GROUP_BACKGROUND_REQUEST_DEVICE_AWARE_RES
+ .put(MICROPHONE, R.string.permgroupbackgroundrequest_device_aware_microphone);
+ PERM_GROUP_BACKGROUND_REQUEST_DEVICE_AWARE_RES
+ .put(CAMERA, R.string.permgroupbackgroundrequest_device_aware_camera);
+ PERM_GROUP_BACKGROUND_REQUEST_DEVICE_AWARE_RES
+ .put(SENSORS, R.string.permgroupbackgroundrequest_device_aware_sensors);
+
PERM_GROUP_BACKGROUND_REQUEST_DETAIL_RES = new ArrayMap<>();
PERM_GROUP_BACKGROUND_REQUEST_DETAIL_RES
.put(LOCATION, R.string.permgroupbackgroundrequestdetail_location);
@@ -313,6 +350,16 @@ public final class Utils {
PERM_GROUP_UPGRADE_REQUEST_RES.put(CAMERA, R.string.permgroupupgraderequest_camera);
PERM_GROUP_UPGRADE_REQUEST_RES.put(SENSORS, R.string.permgroupupgraderequest_sensors);
+ PERM_GROUP_UPGRADE_REQUEST_DEVICE_AWARE_RES = new ArrayMap<>();
+ PERM_GROUP_UPGRADE_REQUEST_DEVICE_AWARE_RES.put(LOCATION,
+ R.string.permgroupupgraderequest_device_aware_location);
+ PERM_GROUP_UPGRADE_REQUEST_DEVICE_AWARE_RES.put(MICROPHONE,
+ R.string.permgroupupgraderequest_device_aware_microphone);
+ PERM_GROUP_UPGRADE_REQUEST_DEVICE_AWARE_RES.put(CAMERA,
+ R.string.permgroupupgraderequest_device_aware_camera);
+ PERM_GROUP_UPGRADE_REQUEST_DEVICE_AWARE_RES.put(SENSORS,
+ R.string.permgroupupgraderequest_device_aware_sensors);
+
PERM_GROUP_UPGRADE_REQUEST_DETAIL_RES = new ArrayMap<>();
PERM_GROUP_UPGRADE_REQUEST_DETAIL_RES
.put(LOCATION, R.string.permgroupupgraderequestdetail_location);
@@ -345,6 +392,8 @@ public final class Utils {
/* do nothing - hide constructor */
}
+ private static Object sLock = new Object();
+
private static ArrayMap<UserHandle, Context> sUserContexts = new ArrayMap<>();
/**
@@ -359,11 +408,13 @@ public final class Utils {
* @throws RuntimeException If the app has no package name attached, which should never happen
*/
public static @NonNull Context getUserContext(Context context, UserHandle user) {
- if (!sUserContexts.containsKey(user)) {
- sUserContexts.put(user, context.getApplicationContext()
- .createContextAsUser(user, 0));
+ synchronized (sLock) {
+ if (!sUserContexts.containsKey(user)) {
+ sUserContexts.put(user, context.getApplicationContext()
+ .createContextAsUser(user, 0));
+ }
+ return Preconditions.checkNotNull(sUserContexts.get(user));
}
- return Preconditions.checkNotNull(sUserContexts.get(user));
}
/**
@@ -698,11 +749,16 @@ public final class Utils {
* @param groupName The name of the permission group
* @param context A context to resolve resources
* @param requestRes The resource id of the grant request message
- *
* @return The formatted message to be used as title when granting permissions
*/
- public static CharSequence getRequestMessage(CharSequence appLabel, String packageName,
- String groupName, Context context, @StringRes int requestRes) {
+ @NonNull
+ public static CharSequence getRequestMessage(
+ @NonNull String appLabel,
+ @NonNull String packageName,
+ @NonNull String groupName,
+ @NonNull Context context,
+ @StringRes int requestRes) {
+ String escapedAppLabel = Html.escapeHtml(appLabel);
boolean isIsolatedStorage;
try {
@@ -712,15 +768,76 @@ public final class Utils {
}
if (groupName.equals(STORAGE) && isIsolatedStorage) {
return Html.fromHtml(
- String.format(context.getResources().getConfiguration().getLocales().get(0),
+ String.format(
+ context.getResources().getConfiguration().getLocales().get(0),
context.getString(R.string.permgrouprequest_storage_isolated),
- appLabel), 0);
+ escapedAppLabel),
+ 0);
+ } else if (requestRes != 0) {
+ return Html.fromHtml(context.getResources().getString(requestRes, escapedAppLabel), 0);
+ }
+
+ return Html.fromHtml(
+ context.getString(
+ R.string.permission_warning_template,
+ escapedAppLabel,
+ loadGroupDescription(context, groupName, context.getPackageManager())),
+ 0);
+ }
+
+ /**
+ * Get the message shown to grant a permission group to an app.
+ *
+ * @param appLabel The label of the app
+ * @param packageName The package name of the app
+ * @param groupName The name of the permission group
+ * @param context A context to resolve resources
+ * @param requestRes The resource id of the grant request message
+ * @return The formatted message to be used as title when granting permissions
+ */
+ @NonNull
+ public static CharSequence getRequestMessage(
+ @NonNull String appLabel,
+ @NonNull String packageName,
+ @NonNull String groupName,
+ @NonNull String deviceLabel,
+ @NonNull Context context,
+ Boolean isDeviceAwareMessage,
+ @StringRes int requestRes) {
+ if (!isDeviceAwareMessage) {
+ return getRequestMessage(appLabel, packageName, groupName, context, requestRes);
+ }
+ String escapedAppLabel = Html.escapeHtml(appLabel);
+
+ boolean isIsolatedStorage;
+ try {
+ isIsolatedStorage = !isNonIsolatedStorage(context, packageName);
+ } catch (NameNotFoundException e) {
+ isIsolatedStorage = false;
+ }
+ if (groupName.equals(STORAGE) && isIsolatedStorage) {
+ String escapedDeviceLabel = Html.escapeHtml(deviceLabel);
+ return Html.fromHtml(
+ String.format(
+ context.getResources().getConfiguration().getLocales().get(0),
+ context.getString(
+ R.string.permgrouprequest_device_aware_storage_isolated),
+ escapedAppLabel,
+ escapedDeviceLabel),
+ 0);
+
} else if (requestRes != 0) {
- return Html.fromHtml(context.getResources().getString(requestRes, appLabel), 0);
+ String escapedDeviceLabel = Html.escapeHtml(deviceLabel);
+ return Html.fromHtml(context.getResources().getString(requestRes, escapedAppLabel,
+ escapedDeviceLabel), 0);
}
- return Html.fromHtml(context.getString(R.string.permission_warning_template, appLabel,
- loadGroupDescription(context, groupName, context.getPackageManager())), 0);
+ return Html.fromHtml(
+ context.getString(
+ R.string.permission_warning_template,
+ escapedAppLabel,
+ loadGroupDescription(context, groupName, context.getPackageManager())),
+ 0);
}
private static CharSequence loadGroupDescription(Context context, String groupName,
@@ -838,8 +955,9 @@ public final class Utils {
if (context.getPackageManager().resolveActivity(intent, 0) == null) {
return;
}
- MenuItem searchItem = menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.search_menu);
- searchItem.setIcon(R.drawable.ic_search_24dp);
+ MenuItem searchItem = menu.add(Menu.NONE, Menu.NONE, Menu.NONE,
+ com.android.settingslib.search.widget.R.string.search_menu);
+ searchItem.setIcon(com.android.settingslib.search.widget.R.drawable.ic_search_24dp);
searchItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
searchItem.setOnMenuItemClickListener(item -> {
try {
@@ -917,16 +1035,6 @@ public final class Utils {
}
/**
- * Whether the Location Access Check is enabled.
- *
- * @return {@code true} iff the Location Access Check is enabled.
- */
- public static boolean isLocationAccessCheckEnabled() {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_LOCATION_ACCESS_CHECK_ENABLED, true);
- }
-
- /**
* Whether we should show health permissions as platform permissions in the various
* permission controller UI.
*/
@@ -943,6 +1051,70 @@ public final class Utils {
}
/**
+ * Returns true if the group name passed is that of the Platform health group.
+ * @param permGroupName name of the group that needs to be checked.
+ */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static Boolean isHealthPermissionGroup(String permGroupName) {
+ return SdkLevel.isAtLeastU() && HEALTH_PERMISSION_GROUP.equals(permGroupName);
+ }
+
+ /**
+ * Return whether health permission setting entry should be shown or not
+ *
+ * Should not show Health permissions preference if the package doesn't handle
+ * VIEW_PERMISSION_USAGE_INTENT.
+ *
+ * Will show if above is true AND permission is already granted.
+ *
+ * @param packageInfo the {@link PackageInfo} app which uses the permission
+ * @param permGroupName the health permission group name to show
+ * @return {@code TRUE} iff health permission should be shown
+ */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static Boolean shouldShowHealthPermission(LightPackageInfo packageInfo,
+ String permGroupName) {
+ if (!isHealthPermissionGroup(permGroupName)) {
+ return false;
+ }
+
+ PermissionControllerApplication app = PermissionControllerApplication.get();
+ PackageManager pm = app.getPackageManager();
+ Context context = getUserContext(app, UserHandle.getUserHandleForUid(packageInfo.getUid()));
+
+ List<PermissionInfo> permissions = new ArrayList<>();
+ try {
+ permissions.addAll(getPermissionInfosForGroup(pm, permGroupName));
+ } catch (NameNotFoundException e) {
+ Log.e(LOG_TAG, "No permissions found for permission group " + permGroupName);
+ return false;
+ }
+
+ // Check in permission is already granted as we should not hide it in the UX at that point.
+ List<String> grantedPermissions = packageInfo.getGrantedPermissions();
+ for (PermissionInfo permission : permissions) {
+ boolean isCurrentlyGranted = grantedPermissions.contains(permission.name);
+ if (isCurrentlyGranted) {
+ Log.d(LOG_TAG, "At least one Health permission group permission is granted, "
+ + "show permission group entry");
+ return true;
+ }
+ }
+
+ Intent viewUsageIntent = new Intent(Intent.ACTION_VIEW_PERMISSION_USAGE);
+ viewUsageIntent.addCategory(HealthConnectManager.CATEGORY_HEALTH_PERMISSIONS);
+ viewUsageIntent.setPackage(packageInfo.getPackageName());
+
+ ResolveInfo resolveInfo = pm.resolveActivity(viewUsageIntent, PackageManager.MATCH_ALL);
+ if (resolveInfo == null) {
+ Log.e(LOG_TAG, "Package that asks for Health permission must also handle "
+ + "VIEW_PERMISSION_USAGE_INTENT.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Get a device protected storage based shared preferences. Avoid storing sensitive data in it.
*
* @param context the context to get the shared preferences
@@ -1013,7 +1185,21 @@ public final class Utils {
* @return The id or 0 if the permission group doesn't exist or have a message
*/
public static int getRequest(String groupName) {
- return PERM_GROUP_REQUEST_RES.getOrDefault(groupName, 0);
+ return getRequest(groupName, false);
+ }
+
+ /**
+ * The resource id for the request message for a permission group for a specific device
+ *
+ * @param groupName Permission group name
+ * @return The id or 0 if the permission group doesn't exist or have a message
+ */
+ public static int getRequest(String groupName, Boolean isDeviceAwareMessage) {
+ if (isDeviceAwareMessage) {
+ return PERM_GROUP_REQUEST_DEVICE_AWARE_RES.getOrDefault(groupName, 0);
+ } else {
+ return PERM_GROUP_REQUEST_RES.getOrDefault(groupName, 0);
+ }
}
/**
@@ -1031,7 +1217,22 @@ public final class Utils {
* @return The id or 0 if the permission group doesn't exist or have a message
*/
public static int getBackgroundRequest(String groupName) {
- return PERM_GROUP_BACKGROUND_REQUEST_RES.getOrDefault(groupName, 0);
+ return getBackgroundRequest(groupName, false);
+ }
+
+ /**
+ * The resource id for the background request message for a permission group for a specific
+ * device
+ *
+ * @param groupName Permission group name
+ * @return The id or 0 if the permission group doesn't exist or have a message
+ */
+ public static int getBackgroundRequest(String groupName, Boolean isDeviceAwareMessage) {
+ if (isDeviceAwareMessage) {
+ return PERM_GROUP_BACKGROUND_REQUEST_DEVICE_AWARE_RES.getOrDefault(groupName, 0);
+ } else {
+ return PERM_GROUP_BACKGROUND_REQUEST_RES.getOrDefault(groupName, 0);
+ }
}
/**
@@ -1049,7 +1250,21 @@ public final class Utils {
* @return The id or 0 if the permission group doesn't exist or have a message
*/
public static int getUpgradeRequest(String groupName) {
- return PERM_GROUP_UPGRADE_REQUEST_RES.getOrDefault(groupName, 0);
+ return getUpgradeRequest(groupName, false);
+ }
+
+ /**
+ * The resource id for the upgrade request message for a permission group for a specific device.
+ *
+ * @param groupName Permission group name
+ * @return The id or 0 if the permission group doesn't exist or have a message
+ */
+ public static int getUpgradeRequest(String groupName, Boolean isDeviceAwareMessage) {
+ if (isDeviceAwareMessage) {
+ return PERM_GROUP_UPGRADE_REQUEST_DEVICE_AWARE_RES.getOrDefault(groupName, 0);
+ } else {
+ return PERM_GROUP_UPGRADE_REQUEST_RES.getOrDefault(groupName, 0);
+ }
}
/**
@@ -1062,6 +1277,45 @@ public final class Utils {
}
/**
+ * The resource id for the fine location request message for a specific device
+ *
+ * @return The id
+ */
+ public static int getFineLocationRequest(Boolean isDeviceAwareMessage) {
+ if (isDeviceAwareMessage) {
+ return R.string.permgrouprequest_device_aware_fineupgrade;
+ } else {
+ return R.string.permgrouprequest_fineupgrade;
+ }
+ }
+
+ /**
+ * The resource id for the coarse location request message for a specific device
+ *
+ * @return The id
+ */
+ public static int getCoarseLocationRequest(Boolean isDeviceAwareMessage) {
+ if (isDeviceAwareMessage) {
+ return R.string.permgrouprequest_device_aware_coarselocation;
+ } else {
+ return R.string.permgrouprequest_coarselocation;
+ }
+ }
+
+ /**
+ * The resource id for the get more photos request message for a specific device
+ *
+ * @return The id
+ */
+ public static int getMorePhotosRequest(Boolean isDeviceAwareMessage) {
+ if (isDeviceAwareMessage) {
+ return R.string.permgrouprequest_device_aware_more_photos;
+ } else {
+ return R.string.permgrouprequest_more_photos;
+ }
+ }
+
+ /**
* Returns a random session ID value that's guaranteed to not be {@code INVALID_SESSION_ID}.
*
* @return A valid session ID.
@@ -1249,10 +1503,8 @@ public final class Utils {
* Returns if a card should be shown if the sensor is blocked
**/
public static boolean shouldDisplayCardIfBlocked(@NonNull String permissionGroupName) {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_WARNING_BANNER_DISPLAY_ENABLED, true) && (
- CAMERA.equals(permissionGroupName) || MICROPHONE.equals(permissionGroupName)
- || LOCATION.equals(permissionGroupName));
+ return CAMERA.equals(permissionGroupName) || MICROPHONE.equals(permissionGroupName)
+ || LOCATION.equals(permissionGroupName);
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt
index 5dbe203f9..9fd8ab916 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt
@@ -32,8 +32,8 @@ object SafetyLabelUtils {
groupName: String
): Set<Int> {
val purposeSet = mutableSetOf<Int>()
- val categoriesForPermission = PermissionMapping
- .getDataCategoriesForPermissionGroup(groupName)
+ val categoriesForPermission =
+ PermissionMapping.getDataCategoriesForPermissionGroup(groupName)
categoriesForPermission.forEach categoryLoop@{ category ->
val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category]
if (dataCategory == null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt
index 59dbf635d..f9079c41b 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt
@@ -32,24 +32,28 @@ object AccessibilitySettingsUtil {
private val LOG_TAG = AccessibilitySettingsUtil::class.java.simpleName
private val lock = Mutex()
- /**
- * Changes an accessibility component's state.
- */
+ /** Changes an accessibility component's state. */
suspend fun disableAccessibilityService(context: Context, serviceToBeDisabled: ComponentName) {
lock.withLock {
val settingsEnabledA11yServices = getEnabledServicesFromSettings(context)
- if (settingsEnabledA11yServices.isEmpty() ||
- !settingsEnabledA11yServices.contains(serviceToBeDisabled)
+ if (
+ settingsEnabledA11yServices.isEmpty() ||
+ !settingsEnabledA11yServices.contains(serviceToBeDisabled)
) {
- Log.w(LOG_TAG, "${serviceToBeDisabled.toShortString()} is already disabled " +
- "or not installed.")
+ Log.w(
+ LOG_TAG,
+ "${serviceToBeDisabled.toShortString()} is already disabled " +
+ "or not installed."
+ )
return
}
settingsEnabledA11yServices.remove(serviceToBeDisabled)
- val updatedEnabledServices = settingsEnabledA11yServices.map { it.flattenToString() }
- .joinToString(separator = ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR.toString())
+ val updatedEnabledServices =
+ settingsEnabledA11yServices
+ .map { it.flattenToString() }
+ .joinToString(separator = ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR.toString())
Settings.Secure.putString(
context.contentResolver,
@@ -59,27 +63,24 @@ object AccessibilitySettingsUtil {
}
}
- /**
- * @return the mutable set of enabled accessibility services.
- */
+ /** @return the mutable set of enabled accessibility services. */
fun getEnabledServicesFromSettings(context: Context): MutableSet<ComponentName> {
- val enabledServicesSetting = Settings.Secure.getString(
- context.contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
- )
+ val enabledServicesSetting =
+ Settings.Secure.getString(
+ context.contentResolver,
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
+ )
val enabledServices = mutableSetOf<ComponentName>()
if (TextUtils.isEmpty(enabledServicesSetting)) {
return enabledServices
}
- val colonSplitter: TextUtils.StringSplitter = TextUtils.SimpleStringSplitter(
- ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR
- )
+ val colonSplitter: TextUtils.StringSplitter =
+ TextUtils.SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR)
colonSplitter.setString(enabledServicesSetting)
for (componentNameString in colonSplitter) {
- val enabledService = ComponentName.unflattenFromString(
- componentNameString
- )
+ val enabledService = ComponentName.unflattenFromString(componentNameString)
if (enabledService != null) {
enabledServices.add(enabledService)
} else {
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt
index 1d5c9c9fa..da20727c5 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt
@@ -35,6 +35,8 @@ import android.os.Bundle
import android.provider.DeviceConfig
import android.provider.Settings
import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID
import android.safetycenter.SafetyEvent
import android.safetycenter.SafetySourceData
import android.safetycenter.SafetySourceIssue
@@ -78,8 +80,7 @@ import kotlinx.coroutines.sync.withLock
const val PROPERTY_SC_ACCESSIBILITY_SOURCE_ENABLED = "sc_accessibility_source_enabled"
const val PROPERTY_SC_ACCESSIBILITY_LISTENER_ENABLED = "sc_accessibility_listener_enabled"
const val SC_ACCESSIBILITY_SOURCE_ID = "AndroidAccessibility"
-const val SC_ACCESSIBILITY_REMOVE_ACCESS_ACTION_ID =
- "revoke_accessibility_app_access"
+const val SC_ACCESSIBILITY_REMOVE_ACCESS_ACTION_ID = "revoke_accessibility_app_access"
private const val DEBUG = false
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
@@ -95,9 +96,7 @@ fun isAccessibilitySourceEnabled(): Boolean {
)
}
-/**
- * cts test needs to disable the listener.
- */
+/** cts test needs to disable the listener. */
fun isAccessibilityListenerEnabled(): Boolean {
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_PRIVACY,
@@ -108,27 +107,24 @@ fun isAccessibilityListenerEnabled(): Boolean {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun isSafetyCenterEnabled(context: Context): Boolean {
- return getSystemServiceSafe(context, SafetyCenterManager::class.java)
- .isSafetyCenterEnabled
+ return getSystemServiceSafe(context, SafetyCenterManager::class.java).isSafetyCenterEnabled
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
-class AccessibilitySourceService(
- val context: Context,
- val random: Random = Random()
-) : PrivacySource {
+class AccessibilitySourceService(val context: Context, val random: Random = Random()) :
+ PrivacySource {
private val parentUserContext = Utils.getParentUserContext(context)
private val packageManager = parentUserContext.packageManager
- private val sharedPrefs: SharedPreferences = parentUserContext.getSharedPreferences(
- ACCESSIBILITY_PREFERENCES_FILE, Context.MODE_PRIVATE)
- private val notificationsManager = getSystemServiceSafe(parentUserContext,
- NotificationManager::class.java)
- private val safetyCenterManager = getSystemServiceSafe(parentUserContext,
- SafetyCenterManager::class.java)
+ private val sharedPrefs: SharedPreferences =
+ parentUserContext.getSharedPreferences(ACCESSIBILITY_PREFERENCES_FILE, Context.MODE_PRIVATE)
+ private val notificationsManager =
+ getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
+ private val safetyCenterManager =
+ getSystemServiceSafe(parentUserContext, SafetyCenterManager::class.java)
@WorkerThread
- internal suspend fun processAccessibilityJob(
+ suspend fun processAccessibilityJob(
params: JobParameters?,
jobService: AccessibilityJobService,
cancel: BooleanSupplier?
@@ -140,14 +136,12 @@ class AccessibilitySourceService(
sessionId = random.nextLong()
}
if (DEBUG) {
- Log.v(LOG_TAG, "safety center accessibility privacy job started.")
+ Log.d(LOG_TAG, "safety center accessibility privacy job started.")
}
interruptJobIfCanceled(cancel)
val a11yServiceList = getEnabledAccessibilityServices()
if (a11yServiceList.isEmpty()) {
- if (DEBUG) {
- Log.v(LOG_TAG, "accessibility services not enabled, job completed.")
- }
+ Log.d(LOG_TAG, "accessibility services not enabled, job completed.")
jobService.jobFinished(params, false)
jobService.clearJob()
return
@@ -155,19 +149,19 @@ class AccessibilitySourceService(
val lastShownNotification =
sharedPrefs.getLong(KEY_LAST_ACCESSIBILITY_NOTIFICATION_SHOWN, 0)
- val showNotification = ((System.currentTimeMillis() - lastShownNotification) >
- getNotificationsIntervalMillis()) && getCurrentNotification() == null
+ val showNotification =
+ ((System.currentTimeMillis() - lastShownNotification) >
+ getNotificationsIntervalMillis()) && getCurrentNotification() == null
if (showNotification) {
val alreadyNotifiedServices = getNotifiedServices()
- val toBeNotifiedServices = a11yServiceList.filter {
- !alreadyNotifiedServices.contains(it.id)
- }
+ val toBeNotifiedServices =
+ a11yServiceList.filter { !alreadyNotifiedServices.contains(it.id) }
if (toBeNotifiedServices.isNotEmpty()) {
if (DEBUG) {
- Log.v(LOG_TAG, "sending an accessibility service notification")
+ Log.d(LOG_TAG, "sending an accessibility service notification")
}
val serviceToBeNotified: AccessibilityServiceInfo =
toBeNotifiedServices[random.nextInt(toBeNotifiedServices.size)]
@@ -192,9 +186,7 @@ class AccessibilitySourceService(
}
}
- /**
- * sends a notification for a given accessibility package
- */
+ /** sends a notification for a given accessibility package */
private suspend fun sendNotification(
serviceToBeNotified: AccessibilityServiceInfo,
sessionId: Long
@@ -212,13 +204,13 @@ class AccessibilitySourceService(
identifier = componentName.flattenToString()
}
- val title = parentUserContext.getString(
- R.string.accessibility_access_reminder_notification_title
- )
- val summary = parentUserContext.getString(
- R.string.accessibility_access_reminder_notification_content,
- pkgLabel
- )
+ val title =
+ parentUserContext.getString(R.string.accessibility_access_reminder_notification_title)
+ val summary =
+ parentUserContext.getString(
+ R.string.accessibility_access_reminder_notification_content,
+ pkgLabel
+ )
val (appLabel, smallIcon, color) =
KotlinUtils.getSafetyCenterNotificationResources(parentUserContext)
@@ -234,12 +226,17 @@ class AccessibilitySourceService(
.setAutoCancel(true)
.setDeleteIntent(
PendingIntent.getBroadcast(
- parentUserContext, 0, notificationDeleteIntent,
- PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_UPDATE_CURRENT or
+ parentUserContext,
+ 0,
+ notificationDeleteIntent,
+ PendingIntent.FLAG_ONE_SHOT or
+ PendingIntent.FLAG_UPDATE_CURRENT or
PendingIntent.FLAG_IMMUTABLE
)
)
- .setContentIntent(getSafetyCenterActivityIntent(context, uid, sessionId))
+ .setContentIntent(
+ getSafetyCenterActivityIntent(context, uid, sessionId, componentName)
+ )
val appNameExtras = Bundle()
appNameExtras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appLabel)
@@ -252,15 +249,15 @@ class AccessibilitySourceService(
)
sharedPrefsLock.withLock {
- sharedPrefs.edit().putLong(
- KEY_LAST_ACCESSIBILITY_NOTIFICATION_SHOWN,
- System.currentTimeMillis()
- ).apply()
+ sharedPrefs
+ .edit()
+ .putLong(KEY_LAST_ACCESSIBILITY_NOTIFICATION_SHOWN, System.currentTimeMillis())
+ .apply()
}
markServiceAsNotified(ComponentName.unflattenFromString(serviceToBeNotified.id)!!)
if (DEBUG) {
- Log.v(LOG_TAG, "NOTIF_INTERACTION SEND metric, uid $uid session $sessionId")
+ Log.d(LOG_TAG, "NOTIF_INTERACTION SEND metric, uid $uid session $sessionId")
}
PermissionControllerStatsLog.write(
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
@@ -273,11 +270,12 @@ class AccessibilitySourceService(
/** Create the channel for a11y notifications */
private fun createPermissionReminderChannel() {
- val permissionReminderChannel = NotificationChannel(
- Constants.PERMISSION_REMINDER_CHANNEL_ID,
- context.getString(R.string.permission_reminders),
- NotificationManager.IMPORTANCE_LOW
- )
+ val permissionReminderChannel =
+ NotificationChannel(
+ Constants.PERMISSION_REMINDER_CHANNEL_ID,
+ context.getString(R.string.permission_reminders),
+ NotificationManager.IMPORTANCE_LOW
+ )
notificationsManager.createNotificationChannel(permissionReminderChannel)
}
@@ -290,36 +288,41 @@ class AccessibilitySourceService(
sessionId: Long
): SafetySourceIssue {
val componentName = ComponentName.unflattenFromString(a11yService.id)!!
- val safetySourceIssueId = "accessibility_${componentName.flattenToString()}"
+ val safetySourceIssueId = getSafetySourceIssueId(componentName)
val pkgLabel = a11yService.resolveInfo.loadLabel(packageManager).toString()
val uid = a11yService.resolveInfo.serviceInfo.applicationInfo.uid
- val removeAccessPendingIntent = getRemoveAccessPendingIntent(
- context,
- componentName,
- safetySourceIssueId,
- uid,
- sessionId
- )
+ val removeAccessPendingIntent =
+ getRemoveAccessPendingIntent(
+ context,
+ componentName,
+ safetySourceIssueId,
+ uid,
+ sessionId
+ )
- val removeAccessAction = SafetySourceIssue.Action.Builder(
- SC_ACCESSIBILITY_REMOVE_ACCESS_ACTION_ID,
- parentUserContext.getString(R.string.accessibility_remove_access_button_label),
- removeAccessPendingIntent
- )
- .setWillResolve(true)
- .setSuccessMessage(parentUserContext.getString(
- R.string.accessibility_remove_access_success_label))
- .build()
+ val removeAccessAction =
+ SafetySourceIssue.Action.Builder(
+ SC_ACCESSIBILITY_REMOVE_ACCESS_ACTION_ID,
+ parentUserContext.getString(R.string.accessibility_remove_access_button_label),
+ removeAccessPendingIntent
+ )
+ .setWillResolve(true)
+ .setSuccessMessage(
+ parentUserContext.getString(R.string.accessibility_remove_access_success_label)
+ )
+ .build()
val accessibilityActivityPendingIntent =
getAccessibilityActivityPendingIntent(context, uid, sessionId)
- val accessibilityActivityAction = SafetySourceIssue.Action.Builder(
- SC_ACCESSIBILITY_SHOW_ACCESSIBILITY_ACTIVITY_ACTION_ID,
- parentUserContext.getString(R.string.accessibility_show_all_apps_button_label),
- accessibilityActivityPendingIntent
- ).build()
+ val accessibilityActivityAction =
+ SafetySourceIssue.Action.Builder(
+ SC_ACCESSIBILITY_SHOW_ACCESSIBILITY_ACTIVITY_ACTION_ID,
+ parentUserContext.getString(R.string.accessibility_show_all_apps_button_label),
+ accessibilityActivityPendingIntent
+ )
+ .build()
val warningCardDismissIntent =
Intent(parentUserContext, AccessibilityWarningCardDismissalReceiver::class.java).apply {
@@ -330,15 +333,19 @@ class AccessibilitySourceService(
putExtra(Intent.EXTRA_UID, uid)
}
- val warningCardDismissPendingIntent = PendingIntent.getBroadcast(
- parentUserContext, 0, warningCardDismissIntent,
- PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_UPDATE_CURRENT or
- PendingIntent.FLAG_IMMUTABLE
- )
- val title = parentUserContext.getString(
- R.string.accessibility_access_reminder_notification_title)
- val summary = parentUserContext.getString(
- R.string.accessibility_access_warning_card_content)
+ val warningCardDismissPendingIntent =
+ PendingIntent.getBroadcast(
+ parentUserContext,
+ 0,
+ warningCardDismissIntent,
+ PendingIntent.FLAG_ONE_SHOT or
+ PendingIntent.FLAG_UPDATE_CURRENT or
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ val title =
+ parentUserContext.getString(R.string.accessibility_access_reminder_notification_title)
+ val summary =
+ parentUserContext.getString(R.string.accessibility_access_warning_card_content)
return SafetySourceIssue.Builder(
safetySourceIssueId,
@@ -355,9 +362,7 @@ class AccessibilitySourceService(
.build()
}
- /**
- * @return pending intent for remove access button on the warning card.
- */
+ /** @return pending intent for remove access button on the warning card. */
private fun getRemoveAccessPendingIntent(
context: Context,
serviceComponentName: ComponentName,
@@ -368,7 +373,7 @@ class AccessibilitySourceService(
val intent =
Intent(parentUserContext, AccessibilityRemoveAccessHandler::class.java).apply {
putExtra(Intent.EXTRA_COMPONENT_NAME, serviceComponentName)
- putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID, safetySourceIssueId)
+ putExtra(EXTRA_SAFETY_SOURCE_ISSUE_ID, safetySourceIssueId)
putExtra(Constants.EXTRA_SESSION_ID, sessionId)
putExtra(Intent.EXTRA_UID, uid)
flags = Intent.FLAG_RECEIVER_FOREGROUND
@@ -383,9 +388,7 @@ class AccessibilitySourceService(
)
}
- /**
- * @return pending intent for redirecting user to the accessibility page
- */
+ /** @return pending intent for redirecting user to the accessibility page */
private fun getAccessibilityActivityPendingIntent(
context: Context,
uid: Int,
@@ -408,18 +411,19 @@ class AccessibilitySourceService(
)
}
- /**
- * @return pending intent to redirect the user to safety center on notification click
- */
+ /** @return pending intent to redirect the user to safety center on notification click */
private fun getSafetyCenterActivityIntent(
context: Context,
uid: Int,
- sessionId: Long
+ sessionId: Long,
+ componentName: ComponentName
): PendingIntent {
val intent = Intent(Intent.ACTION_SAFETY_CENTER)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.putExtra(Constants.EXTRA_SESSION_ID, sessionId)
intent.putExtra(Intent.EXTRA_UID, uid)
+ intent.putExtra(EXTRA_SAFETY_SOURCE_ID, SC_ACCESSIBILITY_SOURCE_ID)
+ intent.putExtra(EXTRA_SAFETY_SOURCE_ISSUE_ID, getSafetySourceIssueId(componentName))
intent.putExtra(
Constants.EXTRA_PRIVACY_SOURCE,
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__A11Y_SERVICE
@@ -432,6 +436,10 @@ class AccessibilitySourceService(
)
}
+ private fun getSafetySourceIssueId(componentName: ComponentName): String {
+ return "accessibility_${componentName.flattenToString()}"
+ }
+
private fun sendIssuesToSafetyCenter(
a11yServiceList: List<AccessibilityServiceInfo>,
sessionId: Long,
@@ -441,9 +449,7 @@ class AccessibilitySourceService(
val dataBuilder = SafetySourceData.Builder()
pendingIssues.forEach { dataBuilder.addIssue(it) }
val safetySourceData = dataBuilder.build()
- if (DEBUG) {
- Log.v(LOG_TAG, "sending ${pendingIssues.size} issue to sc, data: $safetySourceData")
- }
+ Log.d(LOG_TAG, "a11y source sending ${pendingIssues.size} issue to sc")
safetyCenterManager.setSafetySourceData(
SC_ACCESSIBILITY_SOURCE_ID,
safetySourceData,
@@ -467,9 +473,7 @@ class AccessibilitySourceService(
sendIssuesToSafetyCenter(enabledServices, safetyEvent)
}
- /**
- * If [.cancel] throw an [InterruptedException].
- */
+ /** If [.cancel] throw an [InterruptedException]. */
@Throws(InterruptedException::class)
private fun interruptJobIfCanceled(cancel: BooleanSupplier?) {
if (cancel != null && cancel.asBoolean) {
@@ -477,26 +481,31 @@ class AccessibilitySourceService(
}
}
- private val accessibilityManager = getSystemServiceSafe(parentUserContext,
- AccessibilityManager::class.java)
+ private val accessibilityManager =
+ getSystemServiceSafe(parentUserContext, AccessibilityManager::class.java)
- /**
- * @return enabled 3rd party accessibility services.
- */
+ /** @return enabled 3rd party accessibility services. */
fun getEnabledAccessibilityServices(): List<AccessibilityServiceInfo> {
- val installedServices = accessibilityManager.getInstalledAccessibilityServiceList()
- .associateBy { ComponentName.unflattenFromString(it.id) }
- val enabledServices = AccessibilitySettingsUtil.getEnabledServicesFromSettings(context)
- .map {
+ val installedServices =
+ accessibilityManager.getInstalledAccessibilityServiceList().associateBy {
+ ComponentName.unflattenFromString(it.id)
+ }
+ val enabledServices =
+ AccessibilitySettingsUtil.getEnabledServicesFromSettings(context).map {
if (installedServices[it] == null) {
- Log.e(LOG_TAG, "enabled accessibility service ($it) not found in installed" +
- "services: ${installedServices.keys}")
+ Log.e(
+ LOG_TAG,
+ "enabled accessibility service ($it) not found in installed" +
+ "services: ${installedServices.keys}"
+ )
}
installedServices[it]
}
- return enabledServices.filterNotNull()
- .filter { !it.isAccessibilityTool }
+ val enabled3rdPartyServices =
+ enabledServices.filterNotNull().filter { !it.isAccessibilityTool }
+ Log.d(LOG_TAG, "enabled a11y services count ${enabledServices.size}")
+ return enabled3rdPartyServices
}
/**
@@ -509,25 +518,28 @@ class AccessibilitySourceService(
return notifications.firstOrNull { it.id == Constants.ACCESSIBILITY_CHECK_NOTIFICATION_ID }
}
- internal suspend fun removeFromNotifiedServices(a11Service: ComponentName) {
+ suspend fun removeFromNotifiedServices(a11Service: ComponentName) {
sharedPrefsLock.withLock {
val notifiedServices = getNotifiedServices()
- val filteredServices = notifiedServices.filter {
- it != a11Service.flattenToShortString()
- }.toSet()
+ val filteredServices =
+ notifiedServices.filter { it != a11Service.flattenToShortString() }.toSet()
if (filteredServices.size < notifiedServices.size) {
- sharedPrefs.edit().putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, filteredServices)
- .apply()
+ sharedPrefs
+ .edit()
+ .putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, filteredServices)
+ .apply()
}
}
}
- internal suspend fun markServiceAsNotified(a11Service: ComponentName) {
+ suspend fun markServiceAsNotified(a11Service: ComponentName) {
sharedPrefsLock.withLock {
val alreadyNotifiedServices = getNotifiedServices()
alreadyNotifiedServices.add(a11Service.flattenToShortString())
- sharedPrefs.edit().putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, alreadyNotifiedServices)
+ sharedPrefs
+ .edit()
+ .putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, alreadyNotifiedServices)
.apply()
}
}
@@ -537,7 +549,9 @@ class AccessibilitySourceService(
val alreadyNotifiedServices = getNotifiedServices()
val services = alreadyNotifiedServices.filter { enabledA11yServices.contains(it) }
if (services.size < alreadyNotifiedServices.size) {
- sharedPrefs.edit().putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, services.toSet())
+ sharedPrefs
+ .edit()
+ .putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, services.toSet())
.apply()
}
}
@@ -548,21 +562,17 @@ class AccessibilitySourceService(
}
@VisibleForTesting
- internal fun getSharedPreference(): SharedPreferences {
+ fun getSharedPreference(): SharedPreferences {
return sharedPrefs
}
- /**
- * Remove notification when safety center feature is turned off
- */
+ /** Remove notification when safety center feature is turned off */
private fun removeAccessibilityNotification() {
val notification: StatusBarNotification = getCurrentNotification() ?: return
cancelNotification(notification.tag)
}
- /**
- * Remove notification (if needed) when an accessibility event occur.
- */
+ /** Remove notification (if needed) when an accessibility event occur. */
fun removeAccessibilityNotification(a11yEnabledComponents: Set<String>) {
val notification = getCurrentNotification() ?: return
if (a11yEnabledComponents.contains(notification.tag)) {
@@ -571,9 +581,7 @@ class AccessibilitySourceService(
cancelNotification(notification.tag)
}
- /**
- * Remove notification when a package is uninstalled.
- */
+ /** Remove notification when a package is uninstalled. */
private fun removeAccessibilityNotification(pkg: String) {
val notification = getCurrentNotification() ?: return
val component = ComponentName.unflattenFromString(notification.tag)
@@ -583,9 +591,7 @@ class AccessibilitySourceService(
cancelNotification(notification.tag)
}
- /**
- * Remove notification for a component, when warning card is dismissed.
- */
+ /** Remove notification for a component, when warning card is dismissed. */
fun removeAccessibilityNotification(component: ComponentName) {
val notification = getCurrentNotification() ?: return
if (component.flattenToShortString() == notification.tag) {
@@ -598,20 +604,22 @@ class AccessibilitySourceService(
.cancel(notificationTag, Constants.ACCESSIBILITY_CHECK_NOTIFICATION_ID)
}
- internal suspend fun removePackageState(pkg: String) {
+ suspend fun removePackageState(pkg: String) {
sharedPrefsLock.withLock {
removeAccessibilityNotification(pkg)
- val notifiedServices = getNotifiedServices().mapNotNull {
- ComponentName.unflattenFromString(it)
- }
-
- val filteredServices = notifiedServices.filterNot { it.packageName == pkg }
- .map { it.flattenToShortString() }.toSet()
+ val notifiedServices =
+ getNotifiedServices().mapNotNull { ComponentName.unflattenFromString(it) }
+
+ val filteredServices =
+ notifiedServices
+ .filterNot { it.packageName == pkg }
+ .map { it.flattenToShortString() }
+ .toSet()
if (filteredServices.size < notifiedServices.size) {
- sharedPrefs.edit().putStringSet(
- KEY_ALREADY_NOTIFIED_SERVICES,
- filteredServices
- ).apply()
+ sharedPrefs
+ .edit()
+ .putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, filteredServices)
+ .apply()
}
}
}
@@ -629,8 +637,8 @@ class AccessibilitySourceService(
"sc_accessibility_job_interval_millis"
private val DEFAULT_SC_ACCESSIBILITY_JOB_INTERVAL_MILLIS = TimeUnit.DAYS.toMillis(1)
- private val sourceStateChanged = SafetyEvent.Builder(
- SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ private val sourceStateChanged =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
/** lock for processing a job */
internal val lock = Mutex()
@@ -656,7 +664,6 @@ class AccessibilitySourceService(
/**
* Flexibility of the periodic check.
*
- *
* 10% of [.getPeriodicCheckIntervalMillis]
*
* @return The flexibility of the periodic check in milliseconds
@@ -668,7 +675,6 @@ class AccessibilitySourceService(
/**
* Minimum time in between showing two notifications.
*
- *
* This is just small enough so that the periodic check can always show a notification.
*
* @return The minimum time in milliseconds
@@ -692,7 +698,7 @@ class AccessibilitySourceService(
refreshEvent: RefreshEvent
) {
if (DEBUG) {
- Log.v(LOG_TAG, "rescan and push event from safety center $refreshEvent")
+ Log.d(LOG_TAG, "rescan and push event from safety center $refreshEvent")
}
val safetyCenterEvent = getSafetyCenterEvent(refreshEvent, intent)
sendIssuesToSafetyCenter(safetyCenterEvent)
@@ -705,8 +711,9 @@ class AccessibilityPackageResetHandler : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
- if (action != Intent.ACTION_PACKAGE_DATA_CLEARED &&
- action != Intent.ACTION_PACKAGE_FULLY_REMOVED
+ if (
+ action != Intent.ACTION_PACKAGE_DATA_CLEARED &&
+ action != Intent.ACTION_PACKAGE_FULLY_REMOVED
) {
return
}
@@ -719,11 +726,9 @@ class AccessibilityPackageResetHandler : BroadcastReceiver() {
val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
coroutineScope.launch(Dispatchers.Default) {
if (DEBUG) {
- Log.v(LOG_TAG, "package reset event occurred for ${data.schemeSpecificPart}")
- }
- AccessibilitySourceService(context).run {
- removePackageState(data.schemeSpecificPart)
+ Log.d(LOG_TAG, "package reset event occurred for ${data.schemeSpecificPart}")
}
+ AccessibilitySourceService(context).run { removePackageState(data.schemeSpecificPart) }
}
}
}
@@ -738,7 +743,7 @@ class AccessibilityNotificationDeleteHandler : BroadcastReceiver() {
val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
coroutineScope.launch(Dispatchers.Default) {
if (DEBUG) {
- Log.v(LOG_TAG, "NOTIF_INTERACTION DISMISSED metric, uid $uid session $sessionId")
+ Log.d(LOG_TAG, "NOTIF_INTERACTION DISMISSED metric, uid $uid session $sessionId")
}
PermissionControllerStatsLog.write(
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
@@ -751,9 +756,7 @@ class AccessibilityNotificationDeleteHandler : BroadcastReceiver() {
}
}
-/**
- * Handler for Remove access action (warning cards) in safety center dashboard
- */
+/** Handler for Remove access action (warning cards) in safety center dashboard */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class AccessibilityRemoveAccessHandler : BroadcastReceiver() {
private val LOG_TAG = AccessibilityRemoveAccessHandler::class.java.simpleName
@@ -767,36 +770,36 @@ class AccessibilityRemoveAccessHandler : BroadcastReceiver() {
val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
coroutineScope.launch(Dispatchers.Default) {
if (DEBUG) {
- Log.v(LOG_TAG, "disabling a11y service ${a11yService.flattenToShortString()}")
+ Log.d(LOG_TAG, "disabling a11y service ${a11yService.flattenToShortString()}")
}
AccessibilitySourceService.lock.withLock {
val accessibilityService = AccessibilitySourceService(context)
var a11yEnabledServices = accessibilityService.getEnabledAccessibilityServices()
- val builder = try {
- AccessibilitySettingsUtil.disableAccessibilityService(context, a11yService)
- accessibilityService.removeFromNotifiedServices(a11yService)
- a11yEnabledServices = a11yEnabledServices.filter {
- it.id != a11yService.flattenToShortString()
+ val builder =
+ try {
+ AccessibilitySettingsUtil.disableAccessibilityService(context, a11yService)
+ accessibilityService.removeFromNotifiedServices(a11yService)
+ a11yEnabledServices =
+ a11yEnabledServices.filter {
+ it.id != a11yService.flattenToShortString()
+ }
+ SafetyEvent.Builder(
+ SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
+ )
+ } catch (ex: Exception) {
+ Log.w(LOG_TAG, "error occurred in disabling a11y service.", ex)
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
}
- SafetyEvent.Builder(
- SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
- )
- } catch (ex: Exception) {
- Log.w(LOG_TAG, "error occurred in disabling a11y service.", ex)
- SafetyEvent.Builder(
- SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
- )
- }
- val safetySourceIssueId = intent.getStringExtra(
- SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID
- )
- val safetyEvent = builder.setSafetySourceIssueId(safetySourceIssueId)
- .setSafetySourceIssueActionId(SC_ACCESSIBILITY_REMOVE_ACCESS_ACTION_ID)
- .build()
+ val safetySourceIssueId = intent.getStringExtra(EXTRA_SAFETY_SOURCE_ISSUE_ID)
+ val safetyEvent =
+ builder
+ .setSafetySourceIssueId(safetySourceIssueId)
+ .setSafetySourceIssueActionId(SC_ACCESSIBILITY_REMOVE_ACCESS_ACTION_ID)
+ .build()
accessibilityService.sendIssuesToSafetyCenter(a11yEnabledServices, safetyEvent)
}
if (DEBUG) {
- Log.v(LOG_TAG, "ISSUE_CARD_INTERACTION CTA1 metric, uid $uid session $sessionId")
+ Log.d(LOG_TAG, "ISSUE_CARD_INTERACTION CTA1 metric, uid $uid session $sessionId")
}
PermissionControllerStatsLog.write(
PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION,
@@ -809,9 +812,7 @@ class AccessibilityRemoveAccessHandler : BroadcastReceiver() {
}
}
-/**
- * Handler for accessibility warning cards dismissal in safety center dashboard
- */
+/** Handler for accessibility warning cards dismissal in safety center dashboard */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class AccessibilityWarningCardDismissalReceiver : BroadcastReceiver() {
private val LOG_TAG = AccessibilityWarningCardDismissalReceiver::class.java.simpleName
@@ -825,7 +826,7 @@ class AccessibilityWarningCardDismissalReceiver : BroadcastReceiver() {
val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
coroutineScope.launch(Dispatchers.Default) {
if (DEBUG) {
- Log.v(LOG_TAG, "removing notification for ${componentName.flattenToShortString()}")
+ Log.d(LOG_TAG, "removing notification for ${componentName.flattenToShortString()}")
}
val accessibilityService = AccessibilitySourceService(context)
accessibilityService.removeAccessibilityNotification(componentName)
@@ -833,7 +834,7 @@ class AccessibilityWarningCardDismissalReceiver : BroadcastReceiver() {
}
if (DEBUG) {
- Log.v(LOG_TAG, "ISSUE_CARD_INTERACTION DISMISSED metric, uid $uid session $sessionId")
+ Log.d(LOG_TAG, "ISSUE_CARD_INTERACTION DISMISSED metric, uid $uid session $sessionId")
}
PermissionControllerStatsLog.write(
PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION,
@@ -846,8 +847,8 @@ class AccessibilityWarningCardDismissalReceiver : BroadcastReceiver() {
}
/**
- * Schedules periodic job to send notifications for third part accessibility services,
- * the job also sends this data to Safety Center.
+ * Schedules periodic job to send notifications for third part accessibility services, the job also
+ * sends this data to Safety Center.
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class AccessibilityOnBootReceiver : BroadcastReceiver() {
@@ -855,25 +856,26 @@ class AccessibilityOnBootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (!isAccessibilitySourceSupported() || isProfile(context)) {
- Log.v(LOG_TAG, "accessibility privacy job not supported, can't schedule the job")
+ Log.i(LOG_TAG, "accessibility privacy job not supported, can't schedule the job")
return
}
if (DEBUG) {
- Log.v(LOG_TAG, "scheduling safety center accessibility privacy source job")
+ Log.d(LOG_TAG, "scheduling safety center accessibility privacy source job")
}
val jobScheduler = getSystemServiceSafe(context, JobScheduler::class.java)
if (jobScheduler.getPendingJob(Constants.PERIODIC_ACCESSIBILITY_CHECK_JOB_ID) == null) {
- val jobInfo = JobInfo.Builder(
- Constants.PERIODIC_ACCESSIBILITY_CHECK_JOB_ID,
- ComponentName(context, AccessibilityJobService::class.java)
- )
- .setPeriodic(
- AccessibilitySourceService.getJobsIntervalMillis(),
- AccessibilitySourceService.getFlexJobsIntervalMillis()
- )
- .build()
+ val jobInfo =
+ JobInfo.Builder(
+ Constants.PERIODIC_ACCESSIBILITY_CHECK_JOB_ID,
+ ComponentName(context, AccessibilityJobService::class.java)
+ )
+ .setPeriodic(
+ AccessibilitySourceService.getJobsIntervalMillis(),
+ AccessibilitySourceService.getFlexJobsIntervalMillis()
+ )
+ .build()
val status = jobScheduler.schedule(jobInfo)
if (status != JobScheduler.RESULT_SUCCESS) {
@@ -890,8 +892,7 @@ class AccessibilityJobService : JobService() {
private var mSourceService: AccessibilitySourceService? = null
private val mLock = Object()
- @GuardedBy("mLock")
- private var mCurrentJob: Job? = null
+ @GuardedBy("mLock") private var mCurrentJob: Job? = null
override fun onCreate() {
super.onCreate()
@@ -903,27 +904,31 @@ class AccessibilityJobService : JobService() {
Log.v(LOG_TAG, "accessibility privacy source job started.")
synchronized(mLock) {
if (mCurrentJob != null) {
- Log.v(LOG_TAG, "Accessibility privacy source job already running")
+ Log.i(LOG_TAG, "Accessibility privacy source job already running")
return false
}
- if (!isAccessibilitySourceEnabled() ||
- !isSafetyCenterEnabled(this@AccessibilityJobService)) {
- Log.v(LOG_TAG, "either privacy source or safety center is not enabled")
+ if (
+ !isAccessibilitySourceEnabled() ||
+ !isSafetyCenterEnabled(this@AccessibilityJobService)
+ ) {
+ Log.i(LOG_TAG, "either privacy source or safety center is not enabled")
jobFinished(params, false)
mCurrentJob = null
return false
}
val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
- mCurrentJob = coroutineScope.launch(Dispatchers.Default) {
- mSourceService?.processAccessibilityJob(
- params,
- this@AccessibilityJobService,
- BooleanSupplier {
- val job = mCurrentJob
- return@BooleanSupplier job?.isCancelled ?: false
- }
- ) ?: jobFinished(params, false)
- }
+ mCurrentJob =
+ coroutineScope.launch(Dispatchers.Default) {
+ mSourceService?.processAccessibilityJob(
+ params,
+ this@AccessibilityJobService,
+ BooleanSupplier {
+ val job = mCurrentJob
+ return@BooleanSupplier job?.isCancelled ?: false
+ }
+ )
+ ?: jobFinished(params, false)
+ }
}
return true
}
@@ -931,20 +936,19 @@ class AccessibilityJobService : JobService() {
override fun onStopJob(params: JobParameters?): Boolean {
var job: Job?
synchronized(mLock) {
- job = if (mCurrentJob == null) {
- return false
- } else {
- mCurrentJob
- }
+ job =
+ if (mCurrentJob == null) {
+ return false
+ } else {
+ mCurrentJob
+ }
}
job?.cancel()
return false
}
fun clearJob() {
- synchronized(mLock) {
- mCurrentJob = null
- }
+ synchronized(mLock) { mCurrentJob = null }
}
}
@@ -956,28 +960,33 @@ class SafetyCenterAccessibilityListener(val context: Context) :
override fun onAccessibilityServicesStateChanged(manager: AccessibilityManager) {
if (!isAccessibilityListenerEnabled()) {
- Log.v(LOG_TAG, "accessibility event occurred, listener not enabled.")
+ Log.i(LOG_TAG, "accessibility event occurred, listener not enabled.")
return
}
- if (!isAccessibilitySourceEnabled() || !isSafetyCenterEnabled(context) ||
- isProfile(context)) {
- Log.v(LOG_TAG, "accessibility event occurred, safety center feature not enabled.")
+ if (
+ !isAccessibilitySourceEnabled() || !isSafetyCenterEnabled(context) || isProfile(context)
+ ) {
+ Log.i(LOG_TAG, "accessibility event occurred, safety center feature not enabled.")
return
}
val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
coroutineScope.launch(Dispatchers.Default) {
if (DEBUG) {
- Log.v(LOG_TAG, "processing accessibility event")
+ Log.d(LOG_TAG, "processing accessibility event")
}
AccessibilitySourceService.lock.withLock {
val a11ySourceService = AccessibilitySourceService(context)
val a11yEnabledServices = a11ySourceService.getEnabledAccessibilityServices()
a11ySourceService.sendIssuesToSafetyCenter(a11yEnabledServices)
- val enabledComponents = a11yEnabledServices.map { a11yService ->
- ComponentName.unflattenFromString(a11yService.id)!!.flattenToShortString()
- }.toSet()
+ val enabledComponents =
+ a11yEnabledServices
+ .map { a11yService ->
+ ComponentName.unflattenFromString(a11yService.id)!!
+ .flattenToShortString()
+ }
+ .toSet()
a11ySourceService.removeAccessibilityNotification(enabledComponents)
a11ySourceService.updateServiceAsNotified(enabledComponents)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/AutoRevokePrivacySource.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/AutoRevokePrivacySource.kt
index 0660955ff..93bb376ba 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/AutoRevokePrivacySource.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/AutoRevokePrivacySource.kt
@@ -25,9 +25,7 @@ import com.android.permissioncontroller.hibernation.cancelUnusedAppsNotification
import com.android.permissioncontroller.hibernation.rescanAndPushDataToSafetyCenter
import java.util.Random
-/**
- * Privacy source for auto-revoked permissions.
- */
+/** Privacy source for auto-revoked permissions. */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class AutoRevokePrivacySource : PrivacySource {
override val shouldProcessProfileRequest: Boolean = false
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt
index df35048e5..97d1f3ebf 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt
@@ -20,7 +20,6 @@ import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.annotation.RequiresApi
-
import com.android.permissioncontroller.permission.service.LocationAccessCheck
import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent
@@ -40,4 +39,4 @@ class LocationAccessPrivacySource : PrivacySource {
val safetyRefreshEvent = getSafetyCenterEvent(refreshEvent, intent)
LocationAccessCheck(context, null).rescanAndPushSafetyCenterData(safetyRefreshEvent, null)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerCheck.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerCheck.kt
index 91a043a6a..43b3edc04 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerCheck.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerCheck.kt
@@ -109,7 +109,10 @@ private val DEFAULT_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS = DAYS.toMillis(
private fun isNotificationListenerCheckFlagEnabled(): Boolean {
// TODO: b/249789657 Set default to true after policy exemption + impact analysis
return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED, false)
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED,
+ false
+ )
}
/**
@@ -123,7 +126,8 @@ private fun getPeriodicCheckIntervalMillis(): Long {
return DeviceConfig.getLong(
DeviceConfig.NAMESPACE_PRIVACY,
PROPERTY_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS,
- DEFAULT_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS)
+ DEFAULT_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS
+ )
}
/**
@@ -178,15 +182,15 @@ private fun getSafetySourceIssueIdFromComponentName(componentName: ComponentName
* <p>We rate limit the number of notification we show and only ever show one notification at a
* time.
*
- * <p>As there are many cases why a notification should not been shown, we always schedule a {@link
- * #addNotificationListenerNotificationIfNeeded check} which then might add a notification.
+ * <p>As there are many cases why a notification should not been shown, we always schedule a
+ * {@link #addNotificationListenerNotificationIfNeeded check} which then might add a notification.
*
* @param context Used to resolve managers
* @param shouldCancel If supplied, can be used to interrupt long-running operations
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@VisibleForTesting
-internal class NotificationListenerCheckInternal(
+class NotificationListenerCheckInternal(
context: Context,
private val shouldCancel: BooleanSupplier?
) {
@@ -199,10 +203,11 @@ internal class NotificationListenerCheckInternal(
@VisibleForTesting
val exemptPackagesDelegate = lazy {
getExemptedPackages(
- getSystemServiceSafe(parentUserContext, RoleManager::class.java), parentUserContext)
+ getSystemServiceSafe(parentUserContext, RoleManager::class.java),
+ parentUserContext
+ )
}
- @VisibleForTesting
- val exemptPackages: Set<String> by exemptPackagesDelegate
+ @VisibleForTesting val exemptPackages: Set<String> by exemptPackagesDelegate
companion object {
@VisibleForTesting const val NLS_PREFERENCE_FILE = "nls_preference"
@@ -231,7 +236,8 @@ internal class NotificationListenerCheckInternal(
SYSTEM_AUDIO_INTELLIGENCE,
SYSTEM_NOTIFICATION_INTELLIGENCE,
SYSTEM_TEXT_INTELLIGENCE,
- SYSTEM_VISUAL_INTELLIGENCE)
+ SYSTEM_VISUAL_INTELLIGENCE
+ )
/** Lock required for all public methods */
private val nlsLock = Mutex()
@@ -249,7 +255,7 @@ internal class NotificationListenerCheckInternal(
* <p>Always run async inside a {@NotificationListenerCheckJobService} via coroutine.
*/
@WorkerThread
- internal suspend fun getEnabledNotificationListenersAndNotifyIfNeeded(
+ suspend fun getEnabledNotificationListenersAndNotifyIfNeeded(
params: JobParameters,
service: NotificationListenerCheckJobService
) {
@@ -282,11 +288,12 @@ internal class NotificationListenerCheckInternal(
sessionId = random.nextLong()
}
if (DEBUG) {
- Log.v(
+ Log.d(
TAG,
"Found ${enabledComponents.size} enabled notification listeners. " +
"${notifiedComponents.size} already notified. ${unNotifiedComponents.size} " +
- "unnotified, sessionId = $sessionId")
+ "unnotified, sessionId = $sessionId"
+ )
}
throwInterruptedExceptionIfTaskIsCanceled()
@@ -318,7 +325,8 @@ internal class NotificationListenerCheckInternal(
TAG,
"enabledNotificationListeners=$enabledNotificationListeners\n" +
"enabledNotificationListenersExcludingExemptPackages=" +
- "$enabledNotificationListenersExcludingExemptPackages")
+ "$enabledNotificationListenersExcludingExemptPackages"
+ )
}
throwInterruptedExceptionIfTaskIsCanceled()
@@ -335,11 +343,11 @@ internal class NotificationListenerCheckInternal(
}
@VisibleForTesting
- internal fun getNotifiedComponents(): MutableSet<String> {
+ fun getNotifiedComponents(): MutableSet<String> {
return sharedPrefs.getStringSet(KEY_ALREADY_NOTIFIED_COMPONENTS, mutableSetOf<String>())!!
}
- internal suspend fun removeDisabledComponentsFromNotifiedComponents(
+ suspend fun removeDisabledComponentsFromNotifiedComponents(
enabledComponents: Collection<ComponentName>
) {
sharedPrefsLock.withLock {
@@ -356,7 +364,7 @@ internal class NotificationListenerCheckInternal(
}
}
- internal suspend fun markComponentAsNotified(component: ComponentName) {
+ suspend fun markComponentAsNotified(component: ComponentName) {
sharedPrefsLock.withLock {
val notifiedComponents = getNotifiedComponents()
notifiedComponents.add(component.flattenToShortString())
@@ -367,7 +375,7 @@ internal class NotificationListenerCheckInternal(
}
}
- internal suspend fun removeFromNotifiedComponents(packageName: String) {
+ suspend fun removeFromNotifiedComponents(packageName: String) {
sharedPrefsLock.withLock {
val notifiedComponents = getNotifiedComponents()
val filteredServices =
@@ -386,7 +394,7 @@ internal class NotificationListenerCheckInternal(
}
}
- internal suspend fun removeFromNotifiedComponents(component: ComponentName) {
+ suspend fun removeFromNotifiedComponents(component: ComponentName) {
val componentNameShortString = component.flattenToShortString()
sharedPrefsLock.withLock {
val notifiedComponents = getNotifiedComponents()
@@ -421,13 +429,16 @@ internal class NotificationListenerCheckInternal(
val componentsInternal = components.toMutableList()
// Don't show too many notification within certain timespan
- if (currentTimeMillis() - getLastNotificationShownTimeMillis() <
- getInBetweenNotificationsMillis()) {
+ if (
+ currentTimeMillis() - getLastNotificationShownTimeMillis() <
+ getInBetweenNotificationsMillis()
+ ) {
if (DEBUG) {
- Log.v(
+ Log.d(
TAG,
"Notification not posted, within " +
- "$DEFAULT_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS ms")
+ "$DEFAULT_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS ms"
+ )
}
return
}
@@ -435,7 +446,7 @@ internal class NotificationListenerCheckInternal(
// Check for existing notification first, exit if one already present
if (getCurrentlyShownNotificationLocked() != null) {
if (DEBUG) {
- Log.v(TAG, "Notification not posted, previous notification has not been dismissed")
+ Log.d(TAG, "Notification not posted, previous notification has not been dismissed")
}
return
}
@@ -448,7 +459,7 @@ internal class NotificationListenerCheckInternal(
if (componentsInternal.isEmpty()) {
if (DEBUG) {
- Log.v(TAG, "Notification not posted, no unnotified enabled listeners")
+ Log.d(TAG, "Notification not posted, no unnotified enabled listeners")
}
return
}
@@ -456,9 +467,10 @@ internal class NotificationListenerCheckInternal(
componentToNotifyFor = componentsInternal[random.nextInt(componentsInternal.size)]
try {
if (DEBUG) {
- Log.v(
+ Log.d(
TAG,
- "Attempting to get PackageInfo for " + componentToNotifyFor.packageName)
+ "Attempting to get PackageInfo for " + componentToNotifyFor.packageName
+ )
}
pkgInfo =
Utils.getPackageInfoForComponentName(parentUserContext, componentToNotifyFor)
@@ -483,7 +495,8 @@ internal class NotificationListenerCheckInternal(
NotificationChannel(
Constants.PERMISSION_REMINDER_CHANNEL_ID,
parentUserContext.getString(R.string.permission_reminders),
- NotificationManager.IMPORTANCE_LOW)
+ NotificationManager.IMPORTANCE_LOW
+ )
val notificationManager =
getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
@@ -503,9 +516,8 @@ internal class NotificationListenerCheckInternal(
pkg: PackageInfo,
sessionId: Long
) {
- val pkgLabel =
- Utils.getApplicationLabel(parentUserContext, pkg.applicationInfo)
- val uid = pkg.applicationInfo.uid
+ val pkgLabel = Utils.getApplicationLabel(parentUserContext, pkg.applicationInfo!!)
+ val uid = pkg.applicationInfo!!.uid
val deletePendingIntent =
getNotificationDeletePendingIntent(parentUserContext, componentName, uid, sessionId)
@@ -516,7 +528,9 @@ internal class NotificationListenerCheckInternal(
parentUserContext.getString(R.string.notification_listener_reminder_notification_title)
val text =
parentUserContext.getString(
- R.string.notification_listener_reminder_notification_content, pkgLabel)
+ R.string.notification_listener_reminder_notification_content,
+ pkgLabel
+ )
val (appLabel, smallIcon, color) =
KotlinUtils.getSafetyCenterNotificationResources(parentUserContext)
@@ -543,13 +557,17 @@ internal class NotificationListenerCheckInternal(
val notificationManager =
getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
notificationManager.notify(
- componentName.flattenToString(), NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID, b.build())
+ componentName.flattenToString(),
+ NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID,
+ b.build()
+ )
if (DEBUG) {
- Log.v(
+ Log.d(
TAG,
"Notification listener check notification shown with component=" +
- "${componentName.flattenToString()}, uid=$uid, sessionId=$sessionId")
+ "${componentName.flattenToString()}, uid=$uid, sessionId=$sessionId"
+ )
}
PermissionControllerStatsLog.write(
@@ -557,7 +575,8 @@ internal class NotificationListenerCheckInternal(
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__NOTIFICATION_LISTENER,
uid,
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_SHOWN,
- sessionId)
+ sessionId
+ )
updateLastShownNotificationTime()
}
@@ -571,7 +590,8 @@ internal class NotificationListenerCheckInternal(
val intent =
Intent(
parentUserContext,
- NotificationListenerCheckNotificationDeleteHandler::class.java)
+ NotificationListenerCheckNotificationDeleteHandler::class.java
+ )
.apply {
putExtra(EXTRA_COMPONENT_NAME, componentName)
putExtra(Constants.EXTRA_SESSION_ID, sessionId)
@@ -580,7 +600,11 @@ internal class NotificationListenerCheckInternal(
identifier = componentName.flattenToString()
}
return PendingIntent.getBroadcast(
- context, 0, intent, FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
+ context,
+ 0,
+ intent,
+ FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
+ )
}
/** @return [PendingIntent] to safety center */
@@ -595,7 +619,8 @@ internal class NotificationListenerCheckInternal(
putExtra(EXTRA_SAFETY_SOURCE_ID, SC_NLS_SOURCE_ID)
putExtra(
EXTRA_SAFETY_SOURCE_ISSUE_ID,
- getSafetySourceIssueIdFromComponentName(componentName))
+ getSafetySourceIssueIdFromComponentName(componentName)
+ )
putExtra(EXTRA_COMPONENT_NAME, componentName)
putExtra(Constants.EXTRA_SESSION_ID, sessionId)
putExtra(Intent.EXTRA_UID, uid)
@@ -603,7 +628,11 @@ internal class NotificationListenerCheckInternal(
identifier = componentName.flattenToString()
}
return PendingIntent.getActivity(
- context, 0, intent, FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
+ context,
+ 0,
+ intent,
+ FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
+ )
}
/**
@@ -684,7 +713,7 @@ internal class NotificationListenerCheckInternal(
/**
* @param componentName enabled [NotificationListenerService]
* @return safety source issue, shown as the warning card in safety center. Null if unable to
- * create safety source issue
+ * create safety source issue
*/
@VisibleForTesting
fun createSafetySourceIssue(componentName: ComponentName, sessionId: Long): SafetySourceIssue? {
@@ -697,36 +726,51 @@ internal class NotificationListenerCheckInternal(
}
return null
}
- val pkgLabel = Utils.getApplicationLabel(parentUserContext, pkgInfo.applicationInfo)
+ val pkgLabel = Utils.getApplicationLabel(parentUserContext, pkgInfo.applicationInfo!!)
val safetySourceIssueId = getSafetySourceIssueIdFromComponentName(componentName)
- val uid = pkgInfo.applicationInfo.uid
+ val uid = pkgInfo.applicationInfo!!.uid
val disableNlsPendingIntent =
getDisableNlsPendingIntent(
- parentUserContext, safetySourceIssueId, componentName, uid, sessionId)
+ parentUserContext,
+ safetySourceIssueId,
+ componentName,
+ uid,
+ sessionId
+ )
val disableNlsAction =
SafetySourceIssue.Action.Builder(
SC_NLS_DISABLE_ACTION_ID,
parentUserContext.getString(
- R.string.notification_listener_remove_access_button_label),
- disableNlsPendingIntent)
+ R.string.notification_listener_remove_access_button_label
+ ),
+ disableNlsPendingIntent
+ )
.setWillResolve(true)
.setSuccessMessage(
parentUserContext.getString(
- R.string.notification_listener_remove_access_success_label))
+ R.string.notification_listener_remove_access_success_label
+ )
+ )
.build()
val notificationListenerDetailSettingsPendingIntent =
getNotificationListenerDetailSettingsPendingIntent(
- parentUserContext, componentName, uid, sessionId)
+ parentUserContext,
+ componentName,
+ uid,
+ sessionId
+ )
val showNotificationListenerSettingsAction =
SafetySourceIssue.Action.Builder(
SC_SHOW_NLS_SETTINGS_ACTION_ID,
parentUserContext.getString(
- R.string.notification_listener_review_app_button_label),
- notificationListenerDetailSettingsPendingIntent)
+ R.string.notification_listener_review_app_button_label
+ ),
+ notificationListenerDetailSettingsPendingIntent
+ )
.build()
val actionCardDismissPendingIntent =
@@ -742,7 +786,8 @@ internal class NotificationListenerCheckInternal(
title,
summary,
SafetySourceData.SEVERITY_LEVEL_INFORMATION,
- SC_NLS_ISSUE_TYPE_ID)
+ SC_NLS_ISSUE_TYPE_ID
+ )
.setSubtitle(pkgLabel)
.addAction(disableNlsAction)
.addAction(showNotificationListenerSettingsAction)
@@ -784,7 +829,9 @@ internal class NotificationListenerCheckInternal(
flags = FLAG_ACTIVITY_NEW_TASK
identifier = componentName.flattenToString()
putExtra(
- EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME, componentName.flattenToString())
+ EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME,
+ componentName.flattenToString()
+ )
putExtra(Constants.EXTRA_SESSION_ID, sessionId)
putExtra(Intent.EXTRA_UID, uid)
putExtra(Constants.EXTRA_IS_FROM_SLICE, true)
@@ -843,14 +890,14 @@ class NotificationListenerCheckJobService : JobService() {
val job = addNotificationListenerNotificationIfNeededJob
return@BooleanSupplier job?.isCancelled ?: false
}
- })
+ }
+ )
}
/**
* Starts an asynchronous check if a notification listener notification should be shown.
*
* @param params Not used other than for interacting with job scheduling
- *
* @return `false` if another check is already running, or if SDK Check fails (below T)
*/
override fun onStartJob(params: JobParameters): Boolean {
@@ -869,7 +916,9 @@ class NotificationListenerCheckJobService : JobService() {
GlobalScope.launch(Default) {
notificationListenerCheckInternal
?.getEnabledNotificationListenersAndNotifyIfNeeded(
- params, this@NotificationListenerCheckJobService)
+ params,
+ this@NotificationListenerCheckJobService
+ )
?: jobFinished(params, true)
}
}
@@ -880,7 +929,6 @@ class NotificationListenerCheckJobService : JobService() {
* Abort the check if still running.
*
* @param params ignored
- *
* @return false
*/
override fun onStopJob(params: JobParameters): Boolean {
@@ -922,13 +970,16 @@ class SetupPeriodicNotificationListenerCheck : BroadcastReceiver() {
val job =
JobInfo.Builder(
PERIODIC_NOTIFICATION_LISTENER_CHECK_JOB_ID,
- ComponentName(context, NotificationListenerCheckJobService::class.java))
+ ComponentName(context, NotificationListenerCheckJobService::class.java)
+ )
.setPeriodic(getPeriodicCheckIntervalMillis(), getFlexForPeriodicCheckMillis())
.build()
val scheduleResult = jobScheduler.schedule(job)
if (scheduleResult != JobScheduler.RESULT_SUCCESS) {
Log.e(
- TAG, "Could not schedule periodic notification listener check $scheduleResult")
+ TAG,
+ "Could not schedule periodic notification listener check $scheduleResult"
+ )
} else if (DEBUG) {
Log.i(TAG, "Scheduled periodic notification listener check")
}
@@ -954,17 +1005,19 @@ class NotificationListenerCheckNotificationDeleteHandler : BroadcastReceiver() {
NotificationListenerCheckInternal(context, null).markComponentAsNotified(componentName)
}
if (DEBUG) {
- Log.v(
+ Log.d(
TAG,
"Notification listener check notification declined with component=" +
- "${componentName.flattenToString()} , uid=$uid, sessionId=$sessionId")
+ "${componentName.flattenToString()} , uid=$uid, sessionId=$sessionId"
+ )
}
PermissionControllerStatsLog.write(
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__NOTIFICATION_LISTENER,
uid,
PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__DISMISSED,
- sessionId)
+ sessionId
+ )
}
}
@@ -981,10 +1034,11 @@ class DisableNotificationListenerComponentHandler : BroadcastReceiver() {
GlobalScope.launch(Default) {
if (DEBUG) {
- Log.v(
+ Log.d(
TAG,
"DisableComponentHandler: disabling $componentName," +
- "uid=$uid, sessionId=$sessionId")
+ "uid=$uid, sessionId=$sessionId"
+ )
}
val safetyEventBuilder =
@@ -993,7 +1047,10 @@ class DisableNotificationListenerComponentHandler : BroadcastReceiver() {
getSystemServiceSafe(context, NotificationManager::class.java)
disallowNlsLock.withLock {
notificationManager.setNotificationListenerAccessGranted(
- componentName, /* granted= */ false, /* userSet= */ true)
+ componentName,
+ /* granted= */ false,
+ /* userSet= */ true
+ )
}
SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
@@ -1019,7 +1076,8 @@ class DisableNotificationListenerComponentHandler : BroadcastReceiver() {
PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__NOTIFICATION_LISTENER,
uid,
PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CLICKED_CTA1,
- sessionId)
+ sessionId
+ )
}
}
@@ -1041,10 +1099,11 @@ class NotificationListenerActionCardDismissalReceiver : BroadcastReceiver() {
GlobalScope.launch(Default) {
if (DEBUG) {
- Log.v(
+ Log.d(
TAG,
"ActionCardDismissalReceiver: $componentName dismissed," +
- "uid=$uid, sessionId=$sessionId")
+ "uid=$uid, sessionId=$sessionId"
+ )
}
NotificationListenerCheckInternal(context, null).run {
removeNotificationsForComponent(componentName)
@@ -1056,7 +1115,8 @@ class NotificationListenerActionCardDismissalReceiver : BroadcastReceiver() {
PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__NOTIFICATION_LISTENER,
uid,
PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CARD_DISMISSED,
- sessionId)
+ sessionId
+ )
}
}
@@ -1068,8 +1128,10 @@ class NotificationListenerActionCardDismissalReceiver : BroadcastReceiver() {
class NotificationListenerPackageResetHandler : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
- if (action != Intent.ACTION_PACKAGE_DATA_CLEARED &&
- action != Intent.ACTION_PACKAGE_FULLY_REMOVED) {
+ if (
+ action != Intent.ACTION_PACKAGE_DATA_CLEARED &&
+ action != Intent.ACTION_PACKAGE_FULLY_REMOVED
+ ) {
return
}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt
index aaf2d32e6..4063ec8b2 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt
@@ -18,32 +18,34 @@ package com.android.permissioncontroller.privacysources
import android.content.Context
import androidx.annotation.VisibleForTesting
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
// (TODO:b/242573074) Remove for Android U.
class NotificationListenerPregrants(private val context: Context) {
@VisibleForTesting
val pregrantedPackagesDelegate = lazy {
hashSetOf(
- "android",
- "com.android.cellbroadcastreceiver",
- "com.android.server.telecom",
- "com.android.settings",
- "com.android.systemui",
- "com.android.launcher3",
- "com.android.dynsystem",
- "com.android.providers.settings",
- "com.android.inputdevices",
- "com.android.keychain",
- "com.android.localtransport",
- "com.android.wallpaperbackup",
- "com.android.location.fused"
- ).also {
- it.addAll(
- SafetyCenterResourcesContext(context)
- .getStringByName("config_NotificationListenerServicePregrants")
- .split(","))
- }
+ "android",
+ "com.android.cellbroadcastreceiver",
+ "com.android.server.telecom",
+ "com.android.settings",
+ "com.android.systemui",
+ "com.android.launcher3",
+ "com.android.dynsystem",
+ "com.android.providers.settings",
+ "com.android.inputdevices",
+ "com.android.keychain",
+ "com.android.localtransport",
+ "com.android.wallpaperbackup",
+ "com.android.location.fused"
+ )
+ .also {
+ it.addAll(
+ SafetyCenterResourcesApk(context)
+ .getStringByName("config_NotificationListenerServicePregrants")
+ .split(",")
+ )
+ }
}
val pregrantedPackages: Set<String> by pregrantedPackagesDelegate
}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt
index f5903dfc2..4abd7129c 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt
@@ -23,4 +23,4 @@ interface PrivacySourceData {
interface Creator<T> {
fun fromStorageData(data: String): T
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceStorageRepository.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceStorageRepository.kt
index 1eee90e31..621a7219d 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceStorageRepository.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceStorageRepository.kt
@@ -21,4 +21,4 @@ interface PrivacySourceStorageRepository {
fun persistData(dataList: List<PrivacySourceData>)
fun <T> readData(creator: PrivacySourceData.Creator<T>): List<T>
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING
index dc01ab3e2..3e8c5a19c 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING
@@ -36,5 +36,21 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsPermissionUiTestCases"
+ },
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.NotificationListenerCheckTest"
+ },
+ {
+ "include-filter": "android.permission.cts.AccessibilityPrivacySourceTest"
+ }
+ ]
+ }
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt
index 8a8711bb6..a2e5b1376 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt
@@ -40,14 +40,16 @@ class TextStorageRepository(private val file: File) : PrivacySourceStorageReposi
override fun <T> readData(creator: PrivacySourceData.Creator<T>): List<T> {
try {
BufferedReader(FileReader(file)).useLines { lines ->
- return lines.mapNotNull {
- try {
- creator.fromStorageData(it)
- } catch (ex: Exception) {
- Log.e(LOG_TAG, "corrupted data : $it in file ${file.absolutePath}", ex)
- null
+ return lines
+ .mapNotNull {
+ try {
+ creator.fromStorageData(it)
+ } catch (ex: Exception) {
+ Log.e(LOG_TAG, "corrupted data : $it in file ${file.absolutePath}", ex)
+ null
+ }
}
- }.toList()
+ .toList()
}
} catch (ignored: FileNotFoundException) {
Log.e(LOG_TAG, "Could not find file ${file.absolutePath}")
@@ -66,4 +68,4 @@ class TextStorageRepository(private val file: File) : PrivacySourceStorageReposi
}
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/WorkPolicyInfo.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/WorkPolicyInfo.kt
index 2ab6d37f0..bf9f92398 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/WorkPolicyInfo.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/WorkPolicyInfo.kt
@@ -74,7 +74,10 @@ class WorkPolicyInfo(private val workPolicyUtils: WorkPolicyUtils) : PrivacySour
val safetySourceData: SafetySourceData? = createSafetySourceDataForWorkPolicy(context)
safetyCenterManager.setSafetySourceData(
- WORK_POLICY_INFO_SOURCE_ID, safetySourceData, safetyEvent)
+ WORK_POLICY_INFO_SOURCE_ID,
+ safetySourceData,
+ safetyEvent
+ )
}
private fun createSafetySourceDataForWorkPolicy(context: Context): SafetySourceData? {
@@ -84,16 +87,25 @@ class WorkPolicyInfo(private val workPolicyUtils: WorkPolicyUtils) : PrivacySour
when {
deviceOwnerIntent != null -> {
PendingIntent.getActivity(
- context, 0, deviceOwnerIntent, PendingIntent.FLAG_IMMUTABLE)
+ context,
+ 0,
+ deviceOwnerIntent,
+ PendingIntent.FLAG_IMMUTABLE
+ )
}
profileOwnerIntent != null -> {
val managedProfileContext =
context.createPackageContextAsUser(
context.packageName,
0,
- UserHandle.of(workPolicyUtils.managedProfileUserId))
+ UserHandle.of(workPolicyUtils.managedProfileUserId)
+ )
PendingIntent.getActivity(
- managedProfileContext, 0, profileOwnerIntent, PendingIntent.FLAG_IMMUTABLE)
+ managedProfileContext,
+ 0,
+ profileOwnerIntent,
+ PendingIntent.FLAG_IMMUTABLE
+ )
}
else -> null
}
@@ -102,10 +114,17 @@ class WorkPolicyInfo(private val workPolicyUtils: WorkPolicyUtils) : PrivacySour
val safetySourceStatus: SafetySourceStatus =
SafetySourceStatus.Builder(
Utils.getEnterpriseString(
- context, WORK_POLICY_TITLE, R.string.work_policy_title),
+ context,
+ WORK_POLICY_TITLE,
+ R.string.work_policy_title
+ ),
Utils.getEnterpriseString(
- context, WORK_POLICY_SUMMARY, R.string.work_policy_summary),
- SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ context,
+ WORK_POLICY_SUMMARY,
+ R.string.work_policy_summary
+ ),
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
+ )
.setPendingIntent(pendingIntent)
.build()
@@ -120,7 +139,8 @@ class WorkPolicyInfo(private val workPolicyUtils: WorkPolicyUtils) : PrivacySour
RefreshEvent.EVENT_REFRESH_REQUESTED -> {
val refreshBroadcastId =
intent.getStringExtra(
- SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
+ )
SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
.setRefreshBroadcastId(refreshBroadcastId)
.build()
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.kt
index 8bedc3979..ec86a49a4 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.kt
@@ -71,13 +71,16 @@ class AppDataSharingUpdatesPrivacySource : PrivacySource {
SafetySourceStatus.Builder(
context.getString(R.string.data_sharing_updates_title),
context.getString(R.string.data_sharing_updates_summary),
- SEVERITY_LEVEL_INFORMATION)
+ SEVERITY_LEVEL_INFORMATION
+ )
.setPendingIntent(
PendingIntent.getActivity(
context,
/* requestCode= */ 0,
Intent(ACTION_REVIEW_APP_DATA_SHARING_UPDATES),
- FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE))
+ FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
+ )
+ )
.build(),
)
.build()
@@ -88,7 +91,8 @@ class AppDataSharingUpdatesPrivacySource : PrivacySource {
safetyCenterManager.setSafetySourceData(
APP_DATA_SHARING_UPDATES_SOURCE_ID,
safetySourceData,
- createSafetyEventForDataSharingUpdates(refreshEvent, intent))
+ createSafetyEventForDataSharingUpdates(refreshEvent, intent)
+ )
}
private fun createSafetyEventForDataSharingUpdates(
@@ -99,7 +103,8 @@ class AppDataSharingUpdatesPrivacySource : PrivacySource {
EVENT_REFRESH_REQUESTED -> {
val refreshBroadcastId =
intent.getStringExtra(
- SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
+ )
SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
.setRefreshBroadcastId(refreshBroadcastId)
.build()
diff --git a/PermissionController/src/com/android/permissioncontroller/role/Role.md b/PermissionController/src/com/android/permissioncontroller/role/Role.md
index bde9f86f0..acdfffb50 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/Role.md
+++ b/PermissionController/src/com/android/permissioncontroller/role/Role.md
@@ -65,6 +65,10 @@ title. This attribute is required if the role is `visible`.
Android S. This attribute is optional and defaults to `Build.VERSION_CODES.CUR_DEVELOPMENT`.
- `minSdkVersion`: The minimum SDK version for the role to be available (inclusive), e.g. `31` for
Android S. This attribute is optional and defaults to `Build.VERSION_CODES.BASE`.
+- `onlyGrantWhenAdded`: Whether the role should only grant privileges when a role holder is actively
+added. This attribute is optional and defaults to `false`.
+- `overrideUserWhenGranting`: Whether the role should override user's choice about privileges when
+granting. This attribute is optional and defaults to `false`.
- `requestDescription`: The string resource for the description in the request role dialog, e.g.
`@string/role_sms_request_description`, which says "Gets access to contacts, SMS, phone". This
description should describe to the user the privileges that are going to be granted, and should not
diff --git a/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
index d7718a2f2..01d04bea0 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
@@ -21,7 +21,26 @@
"exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
},
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsRoleTestCases"
+ }
+ ],
+ "mainline-postsubmit": [
+ {
+ "name": "CtsRoleTestCases[com.google.android.permission.apex]",
+ "options": [
+ // TODO(b/238677748): These two tests currently fails on R base image
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#openDefaultAppListThenIsNotDefaultAppInList"
+ },
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
}
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java b/PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java
index 1c845ee3a..870e2c03a 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.Binder;
+import android.os.Process;
import android.provider.SearchIndexablesContract;
import android.util.ArrayMap;
@@ -28,7 +29,6 @@ import androidx.annotation.Nullable;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.service.BaseSearchIndexablesProvider;
import com.android.permissioncontroller.role.model.RoleParserInitializer;
-import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.Roles;
@@ -61,8 +61,8 @@ public class RoleSearchIndexablesProvider extends BaseSearchIndexablesProvider {
long token = Binder.clearCallingIdentity();
try {
- if (!role.isAvailable(context) || !RoleUiBehaviorUtils.isVisible(role,
- context)) {
+ if (!role.isAvailableAsUser(Process.myUserHandle(), context)
+ || !role.isVisibleAsUser(Process.myUserHandle(), context)) {
continue;
}
} finally {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/ChangeDefaultCardEmulationActivity.java b/PermissionController/src/com/android/permissioncontroller/role/ui/ChangeDefaultCardEmulationActivity.java
new file mode 100644
index 000000000..882d01c56
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/ChangeDefaultCardEmulationActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.role.ui;
+
+import android.app.Activity;
+import android.app.role.RoleManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.nfc.cardemulation.CardEmulation;
+import android.os.Bundle;
+import android.os.Process;
+import android.permission.flags.Flags;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.modules.utils.build.SdkLevel;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Activity to handle {@link android.nfc.cardemulation.CardEmulation#ACTION_CHANGE_DEFAULT}.
+ */
+public class ChangeDefaultCardEmulationActivity extends Activity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent;
+ if (SdkLevel.isAtLeastV() && Flags.walletRoleEnabled()) {
+ intent = DefaultAppActivity.createIntent(RoleManager.ROLE_WALLET,
+ Process.myUserHandle(), this);
+ } else {
+ intent = getIntent();
+ setDefaultPaymentChangeHandlerDialogComponent(intent);
+ }
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+ finish();
+ }
+
+ // The only other handler of this intent is in the NFC stack.
+ private void setDefaultPaymentChangeHandlerDialogComponent(@NonNull Intent intent) {
+ Intent queryIntent = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT);
+ PackageManager packageManager = getPackageManager();
+ List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(queryIntent,
+ PackageManager.MATCH_SYSTEM_ONLY);
+ int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+ String packageName = resolveInfo.activityInfo.packageName;
+ if (!Objects.equals(packageName, getPackageName())) {
+ intent.setClassName(packageName,
+ resolveInfo.activityInfo.name);
+ return;
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java
index 52471cb32..41f1a06a9 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java
@@ -31,7 +31,7 @@ import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.role.ui.auto.AutoDefaultAppFragment;
import com.android.permissioncontroller.role.ui.handheld.HandheldDefaultAppFragment;
-import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
+import com.android.permissioncontroller.role.ui.wear.WearDefaultAppFragment;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.Roles;
@@ -88,7 +88,7 @@ public class DefaultAppActivity extends SettingsActivity {
return;
}
- if (!RoleUiBehaviorUtils.isVisibleAsUser(role, user, this)) {
+ if (!role.isVisibleAsUser(user, this)) {
Log.e(LOG_TAG, "Role is invisible: " + roleName);
finish();
return;
@@ -98,6 +98,8 @@ public class DefaultAppActivity extends SettingsActivity {
Fragment fragment;
if (DeviceUtils.isAuto(this)) {
fragment = AutoDefaultAppFragment.newInstance(roleName, user);
+ } else if (DeviceUtils.isWear(this)) {
+ fragment = WearDefaultAppFragment.Companion.newInstance(roleName, user);
} else {
fragment = HandheldDefaultAppFragment.newInstance(roleName, user);
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListActivity.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListActivity.java
index d9cb6dca8..58f35705c 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListActivity.java
@@ -25,6 +25,7 @@ import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.role.ui.auto.AutoDefaultAppListFragment;
import com.android.permissioncontroller.role.ui.handheld.HandheldDefaultAppListFragment;
+import com.android.permissioncontroller.role.ui.wear.WearDefaultAppListFragment;
/**
* Activity for the list of default apps.
@@ -45,6 +46,8 @@ public class DefaultAppListActivity extends SettingsActivity {
Fragment fragment;
if (DeviceUtils.isAuto(this)) {
fragment = AutoDefaultAppListFragment.newInstance();
+ } else if (DeviceUtils.isWear(this)) {
+ fragment = WearDefaultAppListFragment.Companion.newInstance();
} else {
fragment = HandheldDefaultAppListFragment.newInstance();
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
index f9a0193bd..e68fa88a0 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
@@ -191,7 +191,8 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat
preference.setIcon(Utils.getBadgedIcon(context, holderApplicationInfo));
preference.setSummary(Utils.getAppLabel(holderApplicationInfo, context));
}
- RoleUiBehaviorUtils.preparePreferenceAsUser(role, rolePreference, user, context);
+ RoleUiBehaviorUtils.preparePreferenceAsUser(role, holderApplicationInfos,
+ rolePreference, user, context);
preferenceGroup.addPreference(preference);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java
index 827d42643..279e55266 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java
@@ -33,11 +33,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
+import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.permission.utils.CollectionUtils;
import com.android.permissioncontroller.role.model.UserDeniedManager;
+import com.android.permissioncontroller.role.ui.wear.WearRequestRoleFragment;
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;
@@ -103,7 +104,7 @@ public class RequestRoleActivity extends FragmentActivity {
return;
}
- if (!role.isAvailable(this)) {
+ if (!role.isAvailableAsUser(Process.myUserHandle(), this)) {
Log.e(LOG_TAG, "Role is unavailable: " + mRoleName);
reportRequestResult(
PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED);
@@ -111,7 +112,7 @@ public class RequestRoleActivity extends FragmentActivity {
return;
}
- if (!RoleUiBehaviorUtils.isVisible(role, this)) {
+ if (!role.isVisibleAsUser(Process.myUserHandle(), this)) {
Log.e(LOG_TAG, "Role is invisible: " + mRoleName);
reportRequestResult(
PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED);
@@ -165,7 +166,7 @@ public class RequestRoleActivity extends FragmentActivity {
return;
}
- if (!role.isPackageQualified(mPackageName, this)) {
+ if (!role.isPackageQualifiedAsUser(mPackageName, Process.myUserHandle(), this)) {
Log.w(LOG_TAG, "Application doesn't qualify for role, role: " + mRoleName
+ ", package: " + mPackageName);
reportRequestResult(PermissionControllerStatsLog
@@ -184,10 +185,19 @@ public class RequestRoleActivity extends FragmentActivity {
}
if (savedInstanceState == null) {
- RequestRoleFragment fragment = RequestRoleFragment.newInstance(mRoleName, mPackageName);
- getSupportFragmentManager().beginTransaction()
- .add(fragment, null)
- .commit();
+ if (DeviceUtils.isWear(this)) {
+ WearRequestRoleFragment fragment = WearRequestRoleFragment.newInstance(
+ mRoleName, mPackageName);
+ getSupportFragmentManager().beginTransaction()
+ .add(android.R.id.content, fragment)
+ .commit();
+ } else {
+ RequestRoleFragment fragment = RequestRoleFragment.newInstance(mRoleName,
+ mPackageName);
+ getSupportFragmentManager().beginTransaction()
+ .add(fragment, null)
+ .commit();
+ }
}
}
@@ -302,4 +312,11 @@ public class RequestRoleActivity extends FragmentActivity {
}
return applicationInfo.uid;
}
+
+ @Override
+ protected void onNewIntent(@NonNull Intent intent) {
+ super.onNewIntent(intent);
+
+ Log.w(LOG_TAG, "Ignoring new intent: " + intent);
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java
index a5bd90dc2..80834a3e2 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java
@@ -457,7 +457,7 @@ public class RequestRoleFragment extends DialogFragment {
static void reportRequestResult(int requestingUid, String requestingPackageName,
String roleName, int qualifyingCount, int currentUid, String currentPackageName,
int grantedAnotherUid, String grantedAnotherPackageName, int result) {
- Log.v(LOG_TAG, "Role request result"
+ Log.i(LOG_TAG, "Role request result"
+ " requestingUid=" + requestingUid
+ " requestingPackageName=" + requestingPackageName
+ " roleName=" + roleName
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java
index b9011bd78..e6df3ed8a 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java
@@ -30,7 +30,6 @@ import androidx.lifecycle.LiveData;
import com.android.permissioncontroller.AsyncTaskLiveData;
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;
@@ -97,7 +96,7 @@ public class RoleListLiveData extends AsyncTaskLiveData<List<RoleItem>>
continue;
}
- if (!RoleUiBehaviorUtils.isVisibleAsUser(role, mUser, mContext)) {
+ if (!role.isVisibleAsUser(mUser, mContext)) {
continue;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java
index 3ccb1d8bc..bb492f76d 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java
@@ -30,7 +30,6 @@ import androidx.lifecycle.LiveData;
import com.android.permissioncontroller.AsyncTaskLiveData;
import com.android.permissioncontroller.role.utils.PackageUtils;
-import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
import com.android.role.controller.model.Role;
import java.util.ArrayList;
@@ -95,8 +94,7 @@ public class RoleLiveData extends AsyncTaskLiveData<List<Pair<ApplicationInfo, B
+ qualifyingPackageName);
continue;
}
- if (!RoleUiBehaviorUtils.isApplicationVisibleAsUser(mRole, qualifyingApplicationInfo,
- mUser, mContext)) {
+ if (!mRole.isApplicationVisibleAsUser(qualifyingApplicationInfo, mUser, mContext)) {
continue;
}
boolean isHolderApplication = holderPackageNames.contains(qualifyingPackageName);
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 97a3dad26..83c146ebc 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRadioPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRadioPreference.java
@@ -36,8 +36,9 @@ public class AutoRadioPreference extends TwoStatePreference implements
new UserRestrictionAwarePreferenceMixin(this);
public AutoRadioPreference(Context context) {
- super(context, null, TypedArrayUtils.getAttr(context, R.attr.preferenceStyle,
- android.R.attr.preferenceStyle));
+ super(context, null,
+ TypedArrayUtils.getAttr(context, androidx.preference.R.attr.preferenceStyle,
+ android.R.attr.preferenceStyle));
init();
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java
index 40bd7a33e..4df3ccf99 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java
@@ -26,7 +26,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.role.model.VisibilityMixin;
import com.android.role.controller.model.Role;
/***
@@ -34,12 +33,6 @@ import com.android.role.controller.model.Role;
*/
public class AssistantRoleUiBehavior implements RoleUiBehavior {
- @Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return VisibilityMixin.isVisible("config_showDefaultAssistant", context);
- }
-
@Nullable
@Override
public Intent getManageIntentAsUser(@NonNull Role role, @NonNull UserHandle user,
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java
index e6b8dabe1..ab87e24cf 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java
@@ -49,12 +49,6 @@ public class DialerRoleUiBehavior implements RoleUiBehavior {
}
}
- @Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return context.getResources().getBoolean(R.bool.config_showDialerRole);
- }
-
@Nullable
@Override
public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java
index 8a62ee7eb..f891bb3ed 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java
@@ -17,13 +17,11 @@
package com.android.permissioncontroller.role.ui.behavior;
import android.content.Context;
-import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.permissioncontroller.role.model.EncryptionUnawareConfirmationMixin;
-import com.android.permissioncontroller.role.model.VisibilityMixin;
import com.android.role.controller.model.Role;
/***
@@ -31,12 +29,6 @@ import com.android.role.controller.model.Role;
*/
public class EmergencyRoleUiBehavior implements RoleUiBehavior {
- @Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return VisibilityMixin.isVisible("config_showDefaultEmergency", context);
- }
-
@Nullable
@Override
public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java
index d0e7c0eef..0142e1c40 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java
@@ -34,12 +34,12 @@ import androidx.preference.Preference;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.utils.CollectionUtils;
import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.role.model.VisibilityMixin;
import com.android.permissioncontroller.role.ui.TwoTargetPreference;
import com.android.permissioncontroller.role.utils.UserUtils;
-import com.android.role.controller.behavior.HomeRoleBehavior;
import com.android.role.controller.model.Role;
+import java.util.List;
+
/***
* Class for UI behavior of Home role
*/
@@ -48,14 +48,9 @@ public class HomeRoleUiBehavior implements RoleUiBehavior {
private static final String LOG_TAG = HomeRoleUiBehavior.class.getSimpleName();
@Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return VisibilityMixin.isVisible("config_showDefaultHome", context);
- }
-
- @Override
public void preparePreferenceAsUser(@NonNull Role role, @NonNull TwoTargetPreference preference,
- @NonNull UserHandle user, @NonNull Context context) {
+ @NonNull List<ApplicationInfo> applicationInfos, @NonNull UserHandle user,
+ @NonNull Context context) {
TwoTargetPreference.OnSecondTargetClickListener listener = null;
RoleManager roleManager = context.getSystemService(RoleManager.class);
String packageName = CollectionUtils.firstOrNull(roleManager.getRoleHoldersAsUser(
@@ -82,14 +77,6 @@ public class HomeRoleUiBehavior implements RoleUiBehavior {
}
@Override
- public boolean isApplicationVisibleAsUser(@NonNull Role role,
- @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user,
- @NonNull Context context) {
- // Home is not available for work profile, so we can just use the current user.
- return !HomeRoleBehavior.isSettingsApplication(applicationInfo, context);
- }
-
- @Override
public void prepareApplicationPreferenceAsUser(@NonNull Role role,
@NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
@NonNull UserHandle user, @NonNull Context context) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
index 6e3b47fba..0a8f9113f 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
@@ -28,26 +28,14 @@ import androidx.preference.Preference;
import com.android.permissioncontroller.role.ui.TwoTargetPreference;
import com.android.role.controller.model.Role;
+import java.util.List;
+
/***
* Interface for UI behavior for roles
*/
public interface RoleUiBehavior {
/**
- * Check whether this role should be visible to user.
- *
- * @param role the role to check for
- * @param user the user to check for
- * @param context the `Context` to retrieve system services
- *
- * @return whether this role should be visible to user
- */
- default boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return true;
- }
-
- /**
* Get the {@link Intent} to manage this role, or {@code null} to use the default UI.
*
* @param role the role to get the intent for
@@ -67,30 +55,17 @@ public interface RoleUiBehavior {
*
* @param role the role to prepare the preference for
* @param preference the {@link Preference} for this role
+ * @param applicationInfos a list {@link ApplicationInfo} for the current role holders
* @param user the user for this role
* @param context the {@code Context} to retrieve system services
*/
default void preparePreferenceAsUser(@NonNull Role role,
@NonNull TwoTargetPreference preference,
+ @NonNull List<ApplicationInfo> applicationInfos,
@NonNull UserHandle user,
@NonNull Context context) {}
/**
- * Check whether a qualifying application should be visible to user.
- *
- * @param applicationInfo the {@link ApplicationInfo} for the application
- * @param user the user for the application
- * @param context the {@code Context} to retrieve system services
- *
- * @return whether the qualifying application should be visible to user
- */
- default boolean isApplicationVisibleAsUser(@NonNull Role role,
- @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user,
- @NonNull Context context) {
- return true;
- }
-
- /**
* Prepare a {@link Preference} for this role.
*
* @param role the role to prepare the preference for
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java
index 9fc9be3d4..e27bc1a30 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java
@@ -17,12 +17,10 @@
package com.android.permissioncontroller.role.ui.behavior;
import android.content.Context;
-import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.R;
import com.android.permissioncontroller.role.model.EncryptionUnawareConfirmationMixin;
import com.android.role.controller.model.Role;
@@ -31,12 +29,6 @@ import com.android.role.controller.model.Role;
*/
public class SmsRoleUiBehavior implements RoleUiBehavior {
- @Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return context.getResources().getBoolean(R.bool.config_showSmsRole);
- }
-
@Nullable
@Override
public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/WalletRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/WalletRoleUiBehavior.java
new file mode 100644
index 000000000..858621d74
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/WalletRoleUiBehavior.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2023 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.role.ui.behavior;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.nfc.cardemulation.ApduServiceInfo;
+import android.nfc.cardemulation.CardEmulation;
+import android.nfc.cardemulation.HostApduService;
+import android.nfc.cardemulation.OffHostApduService;
+import android.os.Build;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.util.Pair;
+import androidx.preference.Preference;
+
+import com.android.permissioncontroller.role.ui.TwoTargetPreference;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.util.UserUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/***
+ * Class for UI behavior of Wallet role
+ */
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+public class WalletRoleUiBehavior implements RoleUiBehavior {
+
+ private static final String LOG_TAG = WalletRoleUiBehavior.class.getSimpleName();
+
+ @Override
+ public void preparePreferenceAsUser(@NonNull Role role, @NonNull TwoTargetPreference preference,
+ @NonNull List<ApplicationInfo> applicationInfos, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ if (!applicationInfos.isEmpty()) {
+ preparePreferenceInternal(preference.asPreference(), applicationInfos.get(0),
+ false, user, userContext);
+ }
+ }
+
+ @Override
+ public void prepareApplicationPreferenceAsUser(@NonNull Role role,
+ @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ preparePreferenceInternal(preference, applicationInfo, true, user, userContext);
+ }
+
+ private void preparePreferenceInternal(@NonNull Preference preference,
+ @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 =
+ getNonPaymentServiceBannerAndLabelIfExists(serviceInfos, user, context);
+ if (bannerAndLabel != null) {
+ preference.setIcon(bannerAndLabel.first);
+ if (setTitle) {
+ preference.setTitle(bannerAndLabel.second);
+ } else {
+ preference.setSummary(bannerAndLabel.second);
+ }
+ }
+ }
+ }
+
+ @NonNull
+ private static List<ApduServiceInfo> getNfcServicesForPackage(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ Intent hostApduIntent = new Intent(HostApduService.SERVICE_INTERFACE);
+ Intent offHostApduIntent = new Intent(OffHostApduService.SERVICE_INTERFACE);
+ hostApduIntent.setPackage(packageName);
+ offHostApduIntent.setPackage(packageName);
+ List<ResolveInfo> hostApduServices = packageManager.queryIntentServicesAsUser(
+ hostApduIntent,
+ PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), user);
+ List<ResolveInfo> offHostApduServices = packageManager.queryIntentServicesAsUser(
+ offHostApduIntent,
+ PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), user);
+ List<ApduServiceInfo> nfcServices = new ArrayList<>();
+ int apduServiceInfoSize = hostApduServices.size();
+ for (int i = 0; i < apduServiceInfoSize; i++) {
+ ResolveInfo resolveInfo = hostApduServices.get(i);
+ ApduServiceInfo apduServiceInfo;
+ try {
+ apduServiceInfo = new ApduServiceInfo(packageManager, resolveInfo, true);
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(LOG_TAG, "Error creating the apduserviceinfo.", e);
+ continue;
+ }
+ nfcServices.add(apduServiceInfo);
+ }
+ int offHostApduServiceInfoSize = offHostApduServices.size();
+ for (int i = 0; i < offHostApduServiceInfoSize; i++) {
+ ResolveInfo resolveInfo = offHostApduServices.get(i);
+ ApduServiceInfo apduServiceInfo;
+ try {
+ apduServiceInfo = new ApduServiceInfo(packageManager, resolveInfo, false);
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(LOG_TAG, "Error creating the apduserviceinfo.", e);
+ continue;
+ }
+ nfcServices.add(apduServiceInfo);
+ }
+ return nfcServices;
+ }
+
+ @Nullable
+ private Pair<Drawable, CharSequence> getNonPaymentServiceBannerAndLabelIfExists(
+ @NonNull List<ApduServiceInfo> apduServiceInfos, @NonNull UserHandle user,
+ @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
+ Pair<Drawable, CharSequence> bannerAndLabel;
+ int apduServiceInfoSize = apduServiceInfos.size();
+ for (int i = 0; i < apduServiceInfoSize; i++) {
+ ApduServiceInfo serviceInfo = apduServiceInfos.get(i);
+ if (serviceInfo.getAids().isEmpty()) {
+ bannerAndLabel = loadBannerAndLabel(serviceInfo, userPackageManager);
+ if (bannerAndLabel != null) {
+ return bannerAndLabel;
+ }
+ } else {
+ List<String> aids = serviceInfo.getAids();
+ int aidsSize = aids.size();
+ for (int j = 0; j < aidsSize; j++) {
+ String aid = aids.get(j);
+ String category = serviceInfo.getCategoryForAid(aid);
+ if (!CardEmulation.CATEGORY_PAYMENT.equals(category)) {
+ bannerAndLabel = loadBannerAndLabel(serviceInfo, userPackageManager);
+ if (bannerAndLabel != null) {
+ return bannerAndLabel;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private Pair<Drawable, CharSequence> loadBannerAndLabel(@NonNull ApduServiceInfo info,
+ @NonNull PackageManager userPackageManager) {
+ Drawable drawable = info.loadBanner(userPackageManager);
+ CharSequence label = info.loadLabel(userPackageManager);
+ if (drawable != null && !TextUtils.isEmpty(label)) {
+ return new Pair<>(drawable, label);
+ } else {
+ return null;
+ }
+ }
+
+ private static boolean isSystemApplication(@NonNull ApplicationInfo applicationInfo) {
+ return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessActivity.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessActivity.java
index 6ed105149..472464061 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessActivity.java
@@ -19,6 +19,7 @@ package com.android.permissioncontroller.role.ui.specialappaccess;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Process;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -30,7 +31,6 @@ import com.android.permissioncontroller.R;
import com.android.permissioncontroller.role.ui.SettingsActivity;
import com.android.permissioncontroller.role.ui.auto.AutoSpecialAppAccessFragment;
import com.android.permissioncontroller.role.ui.specialappaccess.handheld.HandheldSpecialAppAccessFragment;
-import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.Roles;
@@ -71,13 +71,13 @@ public class SpecialAppAccessActivity extends SettingsActivity {
finish();
return;
}
- if (!role.isAvailable(this)) {
+ if (!role.isAvailableAsUser(Process.myUserHandle(), this)) {
Log.e(LOG_TAG, "Role is unavailable: " + roleName);
finish();
return;
}
- if (!RoleUiBehaviorUtils.isVisible(role, this)) {
+ if (!role.isVisibleAsUser(Process.myUserHandle(), this)) {
Log.e(LOG_TAG, "Role is invisible: " + roleName);
finish();
return;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java
index 4b256cef0..b06904930 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java
@@ -115,7 +115,8 @@ public class SpecialAppAccessListChildFragment<PF extends PreferenceFragmentComp
} else {
preference = rolePreference.asPreference();
}
- RoleUiBehaviorUtils.preparePreferenceAsUser(role, rolePreference,
+ RoleUiBehaviorUtils.preparePreferenceAsUser(role, roleItem.getHolderApplicationInfos(),
+ rolePreference,
Process.myUserHandle(),
context);
preferenceScreen.addPreference(preference);
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppFragment.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppFragment.kt
new file mode 100644
index 000000000..156656e33
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppFragment.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.core.os.BundleCompat
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
+import com.android.permissioncontroller.role.ui.DefaultAppViewModel
+import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData
+import com.android.permissioncontroller.role.ui.wear.model.DefaultAppConfirmDialogViewModel
+import com.android.permissioncontroller.role.ui.wear.model.DefaultAppConfirmDialogViewModelFactory
+import com.android.role.controller.model.Role
+import com.android.role.controller.model.Roles
+
+/**
+ * Wear specific version of
+ * [com.android.permissioncontroller.role.ui.handheld.HandheldDefaultAppFragment]
+ */
+class WearDefaultAppFragment : Fragment() {
+ private lateinit var role: Role
+ private lateinit var viewModel: DefaultAppViewModel
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val roleName = arguments?.getString(Intent.EXTRA_ROLE_NAME) ?: ""
+ val user =
+ arguments?.let {
+ BundleCompat.getParcelable(it, Intent.EXTRA_USER, UserHandle::class.java)!!
+ }
+ ?: UserHandle.SYSTEM
+
+ val activity = requireActivity()
+ role =
+ Roles.get(activity)[roleName]
+ ?: let {
+ Log.e(TAG, "Unknown role: $roleName")
+ activity.finish()
+ return null
+ }
+
+ viewModel =
+ ViewModelProvider(this, DefaultAppViewModel.Factory(role, user, activity.application))
+ .get(DefaultAppViewModel::class.java)
+ viewModel.manageRoleHolderStateLiveData.observe(this, this::onManageRoleHolderStateChanged)
+
+ val confirmDialogViewModel =
+ ViewModelProvider(this, DefaultAppConfirmDialogViewModelFactory())
+ .get(DefaultAppConfirmDialogViewModel::class.java)
+
+ return ComposeView(activity).apply {
+ setContent {
+ WearPermissionTheme {
+ WearDefaultAppScreen(
+ WearDefaultAppHelper(
+ activity,
+ user,
+ role,
+ viewModel,
+ confirmDialogViewModel
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun onManageRoleHolderStateChanged(state: Int) {
+ val liveData = viewModel.manageRoleHolderStateLiveData
+ when (state) {
+ ManageRoleHolderStateLiveData.STATE_SUCCESS -> {
+ val packageName = liveData.lastPackageName
+ if (packageName != null) {
+ role.onHolderSelectedAsUser(packageName, liveData.lastUser, requireContext())
+ }
+ liveData.resetState()
+ }
+ ManageRoleHolderStateLiveData.STATE_FAILURE -> liveData.resetState()
+ }
+ }
+
+ companion object {
+ const val TAG = "WearDefaultAppFragment"
+
+ /** Creates a new instance of [WearDefaultAppFragment]. */
+ fun newInstance(roleName: String, user: UserHandle): WearDefaultAppFragment {
+ return WearDefaultAppFragment().apply {
+ arguments =
+ Bundle().apply {
+ putString(Intent.EXTRA_ROLE_NAME, roleName)
+ putParcelable(Intent.EXTRA_USER, user)
+ }
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt
new file mode 100644
index 000000000..d8928d608
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppHelper.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.os.UserHandle
+import android.util.Pair
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.role.ui.DefaultAppViewModel
+import com.android.permissioncontroller.role.ui.wear.model.ConfirmDialogArgs
+import com.android.permissioncontroller.role.ui.wear.model.DefaultAppConfirmDialogViewModel
+import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils
+import com.android.role.controller.model.Role
+
+/** A helper class to retrieve default apps to [WearDefaultAppScreen]. */
+class WearDefaultAppHelper(
+ val context: Context,
+ val user: UserHandle,
+ val role: Role,
+ val viewModel: DefaultAppViewModel,
+ val confirmDialogViewModel: DefaultAppConfirmDialogViewModel
+) {
+ fun getTitle() = context.getString(role.labelResource)
+
+ fun getNonePreference(
+ qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>
+ ): WearRoleApplicationPreference? =
+ if (role.shouldShowNone()) {
+ WearRoleApplicationPreference(
+ context = context,
+ label = context.getString(R.string.default_app_none),
+ checked = !hasHolderApplication(qualifyingApplications),
+ onDefaultCheckChanged = { _ -> viewModel.setNoneDefaultApp() }
+ )
+ .apply { icon = context.getDrawable(R.drawable.ic_remove_circle) }
+ } else {
+ null
+ }
+
+ fun getPreferences(
+ qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>
+ ): List<WearRoleApplicationPreference> {
+ return qualifyingApplications
+ .map { pair ->
+ WearRoleApplicationPreference(
+ context = context,
+ label = Utils.getFullAppLabel(pair.first, context),
+ checked = pair.second,
+ onDefaultCheckChanged = { _ ->
+ run {
+ val packageName = pair.first.packageName
+ val confirmationMessage =
+ RoleUiBehaviorUtils.getConfirmationMessage(
+ role,
+ packageName,
+ context
+ )
+ if (confirmationMessage != null) {
+ showConfirmDialog(packageName, confirmationMessage.toString())
+ } else {
+ setDefaultApp(packageName)
+ }
+ }
+ }
+ )
+ .apply { icon = pair.first.loadIcon(context.packageManager) }
+ .let {
+ RoleUiBehaviorUtils.prepareApplicationPreferenceAsUser(
+ role,
+ it,
+ pair.first,
+ user,
+ context
+ )
+ return@map it
+ }
+ }
+ .toList()
+ }
+
+ private fun showConfirmDialog(packageName: String, message: String) {
+ confirmDialogViewModel.confirmDialogArgs =
+ ConfirmDialogArgs(
+ message = message,
+ onOkButtonClick = {
+ setDefaultApp(packageName)
+ dismissConfirmDialog()
+ },
+ onCancelButtonClick = { dismissConfirmDialog() }
+ )
+ confirmDialogViewModel.showConfirmDialogLiveData.value = true
+ }
+
+ private fun dismissConfirmDialog() {
+ confirmDialogViewModel.confirmDialogArgs = null
+ confirmDialogViewModel.showConfirmDialogLiveData.value = false
+ }
+ private fun setDefaultApp(packageName: String) {
+ viewModel.setDefaultApp(packageName)
+ }
+
+ fun getDescription() = context.getString(role.descriptionResource)
+
+ private fun hasHolderApplication(
+ qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>
+ ): Boolean = qualifyingApplications.map { it.second }.find { true } ?: false
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListFragment.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListFragment.kt
new file mode 100644
index 000000000..5e001483a
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListFragment.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.role.ui.DefaultAppListViewModel
+
+class WearDefaultAppListFragment : Fragment() {
+ companion object {
+ /** @return a new instance of [WearDefaultAppListFragment]. */
+ fun newInstance(): WearDefaultAppListFragment {
+ return WearDefaultAppListFragment()
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val context = requireContext()
+ val viewModel = ViewModelProvider(this).get(DefaultAppListViewModel::class.java)
+ val user = viewModel.user
+ return ComposeView(requireContext()).apply {
+ setContent {
+ WearDefaultAppListScreen(
+ WearDefaultAppListHelper(context, user),
+ viewModel.liveData
+ )
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt
new file mode 100644
index 000000000..bbcedea53
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListHelper.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.content.Context
+import android.os.UserHandle
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.role.ui.DefaultAppActivity
+import com.android.permissioncontroller.role.ui.RoleItem
+import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils
+import com.android.role.controller.model.Roles
+
+/** A helper class to retrieve default apps to [WearDefaultAppListScreen]. */
+class WearDefaultAppListHelper(val context: Context, val user: UserHandle) {
+ fun getPreferences(defaultRole: List<RoleItem>): List<WearRolePreference> {
+ return defaultRole
+ .map { roleItem ->
+ WearRolePreference(
+ context = context,
+ label = context.getString(roleItem.role.shortLabelResource),
+ onDefaultClicked = {
+ run {
+ val roleName: String = roleItem.role.name
+ val role = Roles.get(context)[roleName]
+ var intent =
+ RoleUiBehaviorUtils.getManageIntentAsUser(role!!, user, context)
+ if (intent == null) {
+ intent =
+ DefaultAppActivity.createIntent(roleName, user, context)
+ }
+ context.startActivity(intent)
+ }
+ }
+ )
+ .apply {
+ val holderApplicationInfos = roleItem.holderApplicationInfos
+ if (holderApplicationInfos.isEmpty()) {
+ icon = null
+ summary = context.getString(R.string.default_app_none)
+ } else {
+ val holderApplicationInfo = holderApplicationInfos[0]
+ icon = Utils.getBadgedIcon(context, holderApplicationInfo)
+ summary = Utils.getAppLabel(holderApplicationInfo, context)
+ }
+ }
+ .let {
+ RoleUiBehaviorUtils.preparePreferenceAsUser(
+ roleItem.role,
+ roleItem.holderApplicationInfos,
+ it,
+ user,
+ context
+ )
+ return@map it
+ }
+ }
+ .toList()
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListScreen.kt
new file mode 100644
index 000000000..afee50389
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppListScreen.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.LiveData
+import androidx.wear.compose.material.Text
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.ui.wear.elements.chipDefaultColors
+import com.android.permissioncontroller.permission.ui.wear.elements.chipDisabledColors
+import com.android.permissioncontroller.role.ui.RoleItem
+
+@Composable
+fun WearDefaultAppListScreen(
+ helper: WearDefaultAppListHelper,
+ defaultAppsLiveData: LiveData<List<RoleItem>>,
+) {
+ val defaultAppsState = defaultAppsLiveData.observeAsState(emptyList())
+ val defaultApps: List<RoleItem> by remember { derivedStateOf { defaultAppsState.value } }
+ val preferences = helper.getPreferences(defaultApps)
+ var isLoading by remember { mutableStateOf(true) }
+
+ ScrollableScreen(title = stringResource(R.string.default_apps), isLoading = isLoading) {
+ if (preferences.isEmpty()) {
+ item { Text(stringResource(R.string.no_default_apps)) }
+ return@ScrollableScreen
+ }
+ preferences.forEach { pref ->
+ item {
+ Chip(
+ label = pref.label,
+ icon = pref.icon,
+ colors =
+ if (pref.isEnabled()) {
+ chipDefaultColors()
+ } else {
+ chipDisabledColors()
+ },
+ secondaryLabel = pref.summary?.toString(),
+ onClick = pref.getOnClicked(),
+ modifier = Modifier.fillMaxWidth(),
+ labelMaxLines = Int.MAX_VALUE,
+ secondaryLabelMaxLines = Integer.MAX_VALUE
+ )
+ }
+ }
+ }
+ if (isLoading && defaultApps.isNotEmpty()) {
+ isLoading = false
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt
new file mode 100644
index 000000000..a133aa2c3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.content.pm.ApplicationInfo
+import android.util.Pair
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
+import androidx.wear.compose.material.ToggleChipDefaults
+import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
+import com.android.permissioncontroller.permission.ui.wear.elements.toggleChipDisabledColors
+import com.android.permissioncontroller.role.ui.wear.model.ConfirmDialogArgs
+
+@Composable
+fun WearDefaultAppScreen(helper: WearDefaultAppHelper) {
+ val roleLiveData = helper.viewModel.roleLiveData.observeAsState(emptyList())
+ val showConfirmDialog =
+ helper.confirmDialogViewModel.showConfirmDialogLiveData.observeAsState(false)
+ var isLoading by remember { mutableStateOf(true) }
+ Box {
+ WearDefaultAppContent(isLoading, roleLiveData.value, helper)
+ ConfirmDialog(
+ showDialog = showConfirmDialog.value,
+ args = helper.confirmDialogViewModel.confirmDialogArgs
+ )
+ }
+ if (isLoading && roleLiveData.value.isNotEmpty()) {
+ isLoading = false
+ }
+}
+
+@Composable
+private fun WearDefaultAppContent(
+ isLoading: Boolean,
+ qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>,
+ helper: WearDefaultAppHelper
+) {
+ ScrollableScreen(title = helper.getTitle(), isLoading = isLoading) {
+ helper.getNonePreference(qualifyingApplications)?.let {
+ item {
+ ToggleChip(
+ label = it.label,
+ icon = it.icon,
+ checked = it.checked,
+ onCheckedChanged = it.onDefaultCheckChanged,
+ toggleControl = ToggleChipToggleControl.Radio,
+ labelMaxLine = Integer.MAX_VALUE
+ )
+ }
+ }
+ for (pref in helper.getPreferences(qualifyingApplications)) {
+ item {
+ ToggleChip(
+ label = pref.label,
+ icon = pref.icon,
+ colors =
+ if (pref.isEnabled()) {
+ ToggleChipDefaults.toggleChipColors()
+ } else {
+ toggleChipDisabledColors()
+ },
+ secondaryLabel = pref.summary?.toString(),
+ checked = pref.checked,
+ onCheckedChanged = pref.getOnCheckChanged(),
+ toggleControl = ToggleChipToggleControl.Radio,
+ labelMaxLine = Integer.MAX_VALUE,
+ secondaryLabelMaxLine = Integer.MAX_VALUE
+ )
+ }
+ }
+
+ item { ListFooter(description = helper.getDescription()) }
+ }
+}
+
+@Composable
+private fun ConfirmDialog(showDialog: Boolean, args: ConfirmDialogArgs?) {
+ args?.let {
+ AlertDialog(
+ showDialog = showDialog,
+ message = it.message,
+ onOKButtonClick = it.onOkButtonClick,
+ onCancelButtonClick = it.onCancelButtonClick,
+ scalingLazyListState = rememberScalingLazyListState()
+ )
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleFragment.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleFragment.kt
new file mode 100644
index 000000000..728ea8e99
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleFragment.kt
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.app.Activity
+import android.app.role.RoleManager
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.Process
+import android.os.UserHandle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.PermissionControllerStatsLog
+import com.android.permissioncontroller.permission.utils.PackageRemovalMonitor
+import com.android.permissioncontroller.role.model.UserDeniedManager
+import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData
+import com.android.permissioncontroller.role.ui.RequestRoleViewModel
+import com.android.permissioncontroller.role.ui.wear.model.WearRequestRoleViewModel
+import com.android.permissioncontroller.role.ui.wear.model.WearRequestRoleViewModelFactory
+import com.android.permissioncontroller.role.utils.PackageUtils
+import com.android.role.controller.model.Role
+import com.android.role.controller.model.Roles
+import java.util.Objects
+
+/** Wear specific version of [com.android.permissioncontroller.role.ui.RequestRoleFragment] */
+class WearRequestRoleFragment : Fragment() {
+ private lateinit var packageName: String
+ private lateinit var roleName: String
+ private lateinit var role: Role
+ private lateinit var viewModel: RequestRoleViewModel
+ private lateinit var wearViewModel: WearRequestRoleViewModel
+ private lateinit var helper: WearRequestRoleHelper
+
+ private var packageRemovalMonitor: PackageRemovalMonitor? = null
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ roleName = arguments?.getString(Intent.EXTRA_ROLE_NAME) ?: ""
+ packageName = arguments?.getString(Intent.EXTRA_PACKAGE_NAME) ?: ""
+ val context: Context = requireContext()
+
+ role =
+ Roles.get(context)[roleName]
+ ?: let {
+ Log.e(TAG, "Unknown role: $roleName")
+ finish()
+ return null
+ }
+ val currentPackageNames =
+ context.getSystemService(RoleManager::class.java)!!.getRoleHolders(roleName)
+ if (currentPackageNames.contains(packageName)) {
+ Log.i(
+ TAG,
+ "Application is already a role holder, role: $roleName, package: $packageName"
+ )
+ reportRequestResult(
+ PermissionControllerStatsLog
+ .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED_ALREADY_GRANTED,
+ null
+ )
+ clearDeniedSetResultOkAndFinish()
+ return null
+ }
+ val appInfo = PackageUtils.getApplicationInfo(packageName, context)
+ if (appInfo == null) {
+ Log.w(TAG, "Unknown application: $packageName")
+ reportRequestResult(
+ PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED,
+ null
+ )
+ finish()
+ return null
+ }
+
+ viewModel =
+ ViewModelProvider(
+ this,
+ RequestRoleViewModel.Factory(role, requireActivity().application)
+ )
+ .get(RequestRoleViewModel::class.java)
+ viewModel.manageRoleHolderStateLiveData.observe(this, this::onManageRoleHolderStateChanged)
+
+ wearViewModel =
+ ViewModelProvider(this, WearRequestRoleViewModelFactory())
+ .get(WearRequestRoleViewModel::class.java)
+
+ savedInstanceState?.let { wearViewModel.onRestoreInstanceState(it) }
+
+ helper =
+ WearRequestRoleHelper(
+ context,
+ appInfo,
+ role,
+ roleName,
+ packageName,
+ viewModel,
+ wearViewModel
+ )
+
+ val onSetAsDefault: (Boolean, String?) -> Unit = { dontAskAgain, selectedPackageName ->
+ run {
+ if (dontAskAgain) {
+ Log.i(
+ TAG,
+ "Request denied with don't ask again, role: $roleName" +
+ ", package: $packageName"
+ )
+ reportRequestResult(
+ PermissionControllerStatsLog
+ .ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_ALWAYS,
+ null
+ )
+ setDeniedAlwaysAndFinish()
+ } else {
+ setRoleHolder(selectedPackageName)
+ }
+ }
+ }
+ val onCanceled: () -> Unit = {
+ Log.i(TAG, "Dialog cancelled, role: $roleName , package: $packageName")
+ reportRequestResult(
+ PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED,
+ null
+ )
+ setDeniedOnceAndFinish()
+ }
+
+ return ComposeView(context).apply {
+ setContent { WearRequestRoleScreen(helper, onSetAsDefault, onCanceled) }
+ }
+ }
+
+ private fun onManageRoleHolderStateChanged(state: Int) {
+ val liveData = viewModel.manageRoleHolderStateLiveData
+ when (state) {
+ ManageRoleHolderStateLiveData.STATE_SUCCESS -> {
+ val lastPackageName = liveData.lastPackageName
+ if (lastPackageName != null) {
+ role.onHolderSelectedAsUser(
+ lastPackageName,
+ liveData.lastUser,
+ requireContext()
+ )
+ }
+ if (lastPackageName == packageName) {
+ Log.i(
+ TAG,
+ "Application added as a role holder, role: $roleName, package: " +
+ packageName
+ )
+ clearDeniedSetResultOkAndFinish()
+ } else {
+ Log.i(
+ TAG,
+ "Request denied with another application added as a role holder, " +
+ "role: $roleName, package: $packageName"
+ )
+ setDeniedOnceAndFinish()
+ }
+ }
+ ManageRoleHolderStateLiveData.STATE_FAILURE -> finish()
+ }
+ }
+
+ private fun clearDeniedSetResultOkAndFinish() {
+ UserDeniedManager.getInstance(requireContext()).clearDenied(roleName, packageName)
+ requireActivity().setResult(Activity.RESULT_OK)
+ finish()
+ }
+
+ private fun setDeniedOnceAndFinish() {
+ UserDeniedManager.getInstance(requireContext()).setDeniedOnce(roleName, packageName)
+ finish()
+ }
+
+ private fun reportRequestResult(result: Int, grantedAnotherPackageName: String?) {
+ val holderPackageName: String? = getHolderPackageName()
+ reportRequestResult(
+ getApplicationUid(packageName),
+ packageName,
+ roleName,
+ getQualifyingApplicationCount(),
+ getQualifyingApplicationUid(holderPackageName),
+ holderPackageName,
+ getQualifyingApplicationUid(grantedAnotherPackageName),
+ grantedAnotherPackageName,
+ result
+ )
+ }
+
+ private fun getApplicationUid(packageName: String): Int {
+ val uid: Int = getQualifyingApplicationUid(packageName)
+ if (uid != -1) {
+ return uid
+ }
+ val applicationInfo =
+ PackageUtils.getApplicationInfo(packageName, requireActivity()) ?: return -1
+ return applicationInfo.uid
+ }
+
+ private fun getQualifyingApplicationUid(packageName: String?): Int {
+ if (packageName == null) {
+ return -1
+ }
+ viewModel.roleLiveData.value?.let { qualifyingApplications ->
+ for (qualifyingApplication in qualifyingApplications) {
+ val qualifyingApplicationInfo = qualifyingApplication.first
+ if (Objects.equals(qualifyingApplicationInfo.packageName, packageName)) {
+ return qualifyingApplicationInfo.uid
+ }
+ }
+ }
+ return -1
+ }
+
+ private fun getHolderPackageName(): String? {
+ viewModel.roleLiveData.value?.let { qualifyingApplications ->
+ for (qualifyingApplication in qualifyingApplications) {
+ val isHolderApplication = qualifyingApplication.second
+ if (isHolderApplication) {
+ return qualifyingApplication.first.packageName
+ }
+ }
+ }
+ return null
+ }
+
+ private fun getQualifyingApplicationCount(): Int {
+ return viewModel.roleLiveData.value?.size ?: -1
+ }
+
+ private fun setDeniedAlwaysAndFinish() {
+ UserDeniedManager.getInstance(requireContext()).setDeniedAlways(roleName, packageName)
+ finish()
+ }
+
+ private fun finish() {
+ requireActivity().finish()
+ }
+
+ private fun setRoleHolder(selectedPackageName: String?) {
+ val context: Context = requireContext()
+ val user: UserHandle = Process.myUserHandle()
+ if (selectedPackageName == null) {
+ reportRequestResult(
+ PermissionControllerStatsLog
+ .ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_GRANTED_ANOTHER,
+ null
+ )
+ role.onNoneHolderSelectedAsUser(user, context)
+ viewModel.manageRoleHolderStateLiveData.clearRoleHoldersAsUser(
+ roleName,
+ 0,
+ user,
+ context
+ )
+ } else {
+ val isRequestingApplication = selectedPackageName == packageName
+ if (isRequestingApplication) {
+ reportRequestResult(
+ PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED,
+ null
+ )
+ } else {
+ reportRequestResult(
+ PermissionControllerStatsLog
+ .ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_GRANTED_ANOTHER,
+ selectedPackageName
+ )
+ }
+ val flags =
+ if (isRequestingApplication) RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP else 0
+ viewModel.manageRoleHolderStateLiveData.setRoleHolderAsUser(
+ roleName,
+ selectedPackageName,
+ true,
+ flags,
+ user,
+ context
+ )
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ wearViewModel.onSaveInstanceState(outState)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ packageRemovalMonitor =
+ object : PackageRemovalMonitor(requireContext(), packageName) {
+ override fun onPackageRemoved() {
+ Log.w(
+ TAG,
+ "Application is uninstalled, role: $roleName" +
+ ", package: " +
+ packageName
+ )
+ reportRequestResult(
+ PermissionControllerStatsLog
+ .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED,
+ null
+ )
+ finish()
+ }
+ }
+ .apply { register() }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ packageRemovalMonitor?.let {
+ it.unregister()
+ packageRemovalMonitor = null
+ }
+ }
+
+ companion object {
+ const val TAG = "WearRequestRoleFragment"
+
+ /** Creates a new instance of [WearRequestRoleFragment]. */
+ @JvmStatic
+ fun newInstance(roleName: String, packageName: String): WearRequestRoleFragment {
+ return WearRequestRoleFragment().apply {
+ arguments =
+ Bundle().apply {
+ putString(Intent.EXTRA_ROLE_NAME, roleName)
+ putString(Intent.EXTRA_PACKAGE_NAME, packageName)
+ }
+ }
+ }
+
+ @JvmStatic
+ fun reportRequestResult(
+ requestingUid: Int,
+ requestingPackageName: String,
+ roleName: String,
+ qualifyingCount: Int,
+ currentUid: Int,
+ currentPackageName: String?,
+ grantedAnotherUid: Int,
+ grantedAnotherPackageName: String?,
+ result: Int
+ ) {
+ Log.i(
+ TAG,
+ "Role request result requestingUid=$requestingUid" +
+ " requestingPackageName=$requestingPackageName" +
+ " roleName=$roleName" +
+ " qualifyingCount=$qualifyingCount" +
+ " currentUid=$currentUid" +
+ " currentPackageName=$currentPackageName" +
+ " grantedAnotherUid=$grantedAnotherUid" +
+ " grantedAnotherPackageName=$grantedAnotherPackageName" +
+ " result=$result"
+ )
+ PermissionControllerStatsLog.write(
+ PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED,
+ requestingUid,
+ requestingPackageName,
+ roleName,
+ qualifyingCount,
+ currentUid,
+ currentPackageName,
+ grantedAnotherUid,
+ grantedAnotherPackageName,
+ result
+ )
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleHelper.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleHelper.kt
new file mode 100644
index 000000000..f1d6ba97b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleHelper.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.graphics.drawable.Drawable
+import android.util.Pair
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.role.model.UserDeniedManager
+import com.android.permissioncontroller.role.ui.RequestRoleViewModel
+import com.android.permissioncontroller.role.ui.wear.model.WearRequestRoleViewModel
+import com.android.role.controller.model.Role
+
+/** A helper class for [WearRequestRoleScreen]. */
+class WearRequestRoleHelper(
+ val context: Context,
+ val applicationInfo: ApplicationInfo,
+ val role: Role,
+ val roleName: String,
+ val packageName: String,
+ val viewModel: RequestRoleViewModel,
+ val wearViewModel: WearRequestRoleViewModel
+) {
+ fun getIcon() = Utils.getBadgedIcon(context, applicationInfo)
+
+ fun getTitle() =
+ context.getString(role.requestTitleResource, Utils.getAppLabel(applicationInfo, context))
+
+ // Only show this button when the user denied once
+ fun showDontAskButton() =
+ UserDeniedManager.getInstance(context).isDeniedOnce(roleName, packageName)
+
+ fun getNonePreference(
+ qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>,
+ selectedPackage: String?
+ ): RequestRolePreference? =
+ if (role.shouldShowNone()) {
+ val hasHolderApplication = hasHolderApplication(qualifyingApplications)
+ RequestRolePreference(
+ packageName = null,
+ label = context.getString(R.string.default_app_none),
+ subTitle =
+ if (!hasHolderApplication) {
+ context.getString(R.string.request_role_current_default)
+ } else {
+ null
+ },
+ icon = context.getDrawable(R.drawable.ic_remove_circle),
+ checked = selectedPackage?.isNullOrEmpty() ?: false,
+ enabled =
+ if (!wearViewModel.dontAskAgain()) {
+ true
+ } else {
+ !hasHolderApplication
+ },
+ isHolder = !hasHolderApplication
+ )
+ } else {
+ null
+ }
+
+ fun getPreferences(
+ qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>,
+ selectedPackage: String?
+ ): List<RequestRolePreference> {
+ return qualifyingApplications
+ .map { qualifyingApplication ->
+ RequestRolePreference(
+ packageName = qualifyingApplication.first.packageName,
+ label = Utils.getAppLabel(qualifyingApplication.first, context),
+ subTitle =
+ if (qualifyingApplication.second) {
+ context.getString(R.string.request_role_current_default)
+ } else {
+ context.getString(role.requestDescriptionResource)
+ },
+ icon = Utils.getBadgedIcon(context, qualifyingApplication.first),
+ checked = qualifyingApplication.first.packageName.equals(selectedPackage),
+ enabled =
+ if (!wearViewModel.dontAskAgain()) {
+ true
+ } else {
+ qualifyingApplication.second
+ },
+ isHolder = qualifyingApplication.second
+ )
+ }
+ .toList()
+ }
+
+ private fun hasHolderApplication(
+ qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>
+ ): Boolean = qualifyingApplications.map { it.second }.find { true } ?: false
+
+ fun shouldSetAsDefaultEnabled(enabled: Boolean): Boolean {
+ return enabled && (wearViewModel.dontAskAgain() || !wearViewModel.isHolderChecked)
+ }
+
+ fun initializeHolderPackageName(qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>) {
+ wearViewModel.holderPackageName =
+ qualifyingApplications.find { it.second }?.first?.packageName
+ }
+
+ fun initializeSelectedPackageName() {
+ if (wearViewModel.holderPackageName == null) {
+ wearViewModel.selectedPackageName.value = null
+ } else {
+ wearViewModel.selectedPackageName.value = packageName
+ }
+ }
+
+ data class RequestRolePreference(
+ val label: String,
+ val subTitle: String?,
+ val icon: Drawable?,
+ val checked: Boolean,
+ val enabled: Boolean,
+ val packageName: String?,
+ val isHolder: Boolean
+ )
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt
new file mode 100644
index 000000000..13a9cb6d6
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.content.pm.ApplicationInfo
+import android.util.Pair
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.MaterialTheme
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter
+import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
+import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
+import com.android.permissioncontroller.permission.ui.wear.elements.toggleChipBackgroundColors
+import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData
+
+@Composable
+fun WearRequestRoleScreen(
+ helper: WearRequestRoleHelper,
+ onSetAsDefault: (Boolean, String?) -> Unit,
+ onCanceled: () -> Unit
+) {
+ val roleLiveData = helper.viewModel.roleLiveData.observeAsState(emptyList())
+ val manageRoleHolderState =
+ helper.viewModel.manageRoleHolderStateLiveData.observeAsState(
+ ManageRoleHolderStateLiveData.STATE_WORKING
+ )
+ val dontAskAgain = helper.wearViewModel.dontAskAgain.observeAsState(false)
+ val selectedPackageName = helper.wearViewModel.selectedPackageName.observeAsState(null)
+ var isLoading by remember { mutableStateOf(true) }
+
+ if (isLoading && roleLiveData.value.isNotEmpty()) {
+ helper.initializeHolderPackageName(roleLiveData.value)
+ helper.initializeSelectedPackageName()
+ }
+
+ val onCheckedChanged: (Boolean, String?, Boolean) -> Unit = { checked, packageName, isHolder ->
+ if (checked) {
+ helper.wearViewModel.selectedPackageName.value = packageName
+ helper.wearViewModel.isHolderChecked = isHolder
+ }
+ }
+
+ val onDontAskAgainCheckedChanged: (Boolean) -> Unit = { checked ->
+ helper.wearViewModel.dontAskAgain.value = checked
+ if (checked) {
+ helper.initializeSelectedPackageName()
+ }
+ }
+
+ WearRequestRoleContent(
+ isLoading,
+ helper,
+ roleLiveData.value,
+ manageRoleHolderState.value == ManageRoleHolderStateLiveData.STATE_IDLE,
+ dontAskAgain.value,
+ selectedPackageName.value,
+ onCheckedChanged,
+ onDontAskAgainCheckedChanged,
+ onSetAsDefault,
+ onCanceled
+ )
+
+ if (isLoading && roleLiveData.value.isNotEmpty()) {
+ isLoading = false
+ }
+}
+
+@Composable
+internal fun WearRequestRoleContent(
+ isLoading: Boolean,
+ helper: WearRequestRoleHelper,
+ qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>,
+ enabled: Boolean,
+ dontAskAgain: Boolean,
+ selectedPackageName: String?,
+ onCheckedChanged: (Boolean, String?, Boolean) -> Unit,
+ onDontAskAgainCheckedChanged: (Boolean) -> Unit,
+ onSetAsDefault: (Boolean, String?) -> Unit,
+ onCanceled: () -> Unit
+) {
+ ScrollableScreen(
+ image = helper.getIcon(),
+ title = helper.getTitle(),
+ showTimeText = false,
+ isLoading = isLoading
+ ) {
+ helper.getNonePreference(qualifyingApplications, selectedPackageName)?.let {
+ item {
+ ToggleChip(
+ label = it.label,
+ icon = it.icon,
+ enabled = enabled && it.enabled,
+ checked = it.checked,
+ onCheckedChanged = { checked ->
+ run { onCheckedChanged(checked, it.packageName, it.isHolder) }
+ },
+ toggleControl = ToggleChipToggleControl.Radio,
+ labelMaxLine = Integer.MAX_VALUE
+ )
+ }
+ it.subTitle?.let { subTitle -> item { ListFooter(description = subTitle) } }
+ }
+
+ for (pref in helper.getPreferences(qualifyingApplications, selectedPackageName)) {
+ item {
+ ToggleChip(
+ label = pref.label,
+ icon = pref.icon,
+ enabled = enabled && pref.enabled,
+ checked = pref.checked,
+ onCheckedChanged = { checked ->
+ run { onCheckedChanged(checked, pref.packageName, pref.isHolder) }
+ },
+ toggleControl = ToggleChipToggleControl.Radio,
+ )
+ }
+ pref.subTitle?.let { subTitle -> item { ListFooter(description = subTitle) } }
+ }
+
+ if (helper.showDontAskButton()) {
+ item {
+ ToggleChip(
+ checked = dontAskAgain,
+ enabled = enabled,
+ onCheckedChanged = { checked -> run { onDontAskAgainCheckedChanged(checked) } },
+ label = stringResource(R.string.request_role_dont_ask_again),
+ toggleControl = ToggleChipToggleControl.Checkbox,
+ colors = toggleChipBackgroundColors(),
+ modifier =
+ Modifier.testTag("com.android.permissioncontroller:id/dont_ask_again"),
+ )
+ }
+ }
+
+ item { Spacer(modifier = Modifier.height(14.dp)) }
+
+ item {
+ Chip(
+ label = stringResource(R.string.request_role_set_as_default),
+ textColor = MaterialTheme.colors.background,
+ colors = ChipDefaults.primaryChipColors(),
+ enabled = helper.shouldSetAsDefaultEnabled(enabled),
+ onClick = { onSetAsDefault(dontAskAgain, selectedPackageName) },
+ modifier = Modifier.testTag("android:id/button1"),
+ )
+ }
+ item {
+ Chip(
+ label = stringResource(R.string.cancel),
+ enabled = enabled,
+ onClick = { onCanceled() },
+ modifier = Modifier.testTag("android:id/button2"),
+ )
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt
new file mode 100644
index 000000000..29f90ddc3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.app.admin.DevicePolicyManager
+import android.content.Context
+import android.content.Intent
+import android.provider.Settings
+import androidx.preference.TwoStatePreference
+import com.android.permissioncontroller.role.ui.RoleApplicationPreference
+
+/**
+ * Role application preference for Wear. The preference is only used to hand over the properties to
+ * ToggleChip.
+ */
+class WearRoleApplicationPreference(
+ context: Context,
+ val label: String,
+ val checked: Boolean,
+ val onDefaultCheckChanged: (Boolean) -> Unit = {},
+ private var restriction: String? = null
+) : TwoStatePreference(context), RoleApplicationPreference {
+ fun getOnCheckChanged(): (Boolean) -> Unit =
+ restriction?.let {
+ return { _ ->
+ context.startActivity(
+ Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)
+ .putExtra(DevicePolicyManager.EXTRA_RESTRICTION, restriction)
+ )
+ }
+ }
+ ?: onDefaultCheckChanged
+
+ override fun setUserRestriction(userRestriction: String?) {
+ restriction = userRestriction
+ setEnabled(restriction == null)
+ }
+
+ override fun asTwoStatePreference(): TwoStatePreference {
+ return this
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt
new file mode 100644
index 000000000..16d35ed76
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear
+
+import android.app.admin.DevicePolicyManager
+import android.content.Context
+import android.content.Intent
+import android.provider.Settings
+import androidx.preference.Preference
+import com.android.permissioncontroller.role.ui.RolePreference
+import com.android.permissioncontroller.role.ui.TwoTargetPreference.OnSecondTargetClickListener
+import com.android.settingslib.widget.TwoTargetPreference
+
+/** Role preference for Wear. The preference is only used to hand over the properties to Chip. */
+class WearRolePreference(
+ context: Context,
+ val label: String,
+ val onDefaultClicked: () -> Unit = {},
+ private var restriction: String? = null
+) : TwoTargetPreference(context), RolePreference {
+
+ override fun setOnSecondTargetClickListener(listener: OnSecondTargetClickListener?) {
+ // no-op
+ }
+
+ override fun setUserRestriction(userRestriction: String?) {
+ restriction = userRestriction
+ setEnabled(restriction == null)
+ }
+
+ override fun asPreference(): Preference {
+ return this
+ }
+
+ fun getOnClicked(): () -> Unit =
+ restriction?.let {
+ return {
+ context.startActivity(
+ Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)
+ .putExtra(DevicePolicyManager.EXTRA_RESTRICTION, restriction)
+ )
+ }
+ }
+ ?: onDefaultClicked
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/model/DefaultAppConfirmDialogViewModel.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/model/DefaultAppConfirmDialogViewModel.kt
new file mode 100644
index 000000000..514fd9618
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/model/DefaultAppConfirmDialogViewModel.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear.model
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+
+/** ViewModel for a default app confirm dialog. */
+class DefaultAppConfirmDialogViewModel : ViewModel() {
+ /** A livedata which stores whether confirmation dialog is visible. */
+ val showConfirmDialogLiveData = MutableLiveData<Boolean>()
+
+ /** Arguments for a confirmation dialog. */
+ var confirmDialogArgs: ConfirmDialogArgs? = null
+
+ init {
+ showConfirmDialogLiveData.value = false
+ }
+}
+
+/** Factory for a DefaultAppConfirmDialogViewModel */
+class DefaultAppConfirmDialogViewModelFactory : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return DefaultAppConfirmDialogViewModel() as T
+ }
+}
+
+/** Data class for arguments of a default app confirm dialog. */
+data class ConfirmDialogArgs(
+ val message: String,
+ val onOkButtonClick: () -> Unit,
+ val onCancelButtonClick: () -> Unit
+)
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/model/WearRequestRoleViewModel.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/model/WearRequestRoleViewModel.kt
new file mode 100644
index 000000000..692533916
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/model/WearRequestRoleViewModel.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.role.ui.wear.model
+
+import android.os.Bundle
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+
+/** ViewModel for WearRequestRoleScreen. */
+class WearRequestRoleViewModel : ViewModel() {
+ val dontAskAgain = MutableLiveData<Boolean>(false)
+ val selectedPackageName = MutableLiveData<String?>(null)
+ var isHolderChecked: Boolean = false
+ var holderPackageName: String? = null
+
+ fun dontAskAgain(): Boolean {
+ return dontAskAgain.value ?: false
+ }
+
+ fun onSaveInstanceState(outState: Bundle) {
+ outState.putBoolean(STATE_DONT_ASK_AGAIN, dontAskAgain())
+ outState.putString(STATE_SELECTED_PACKAGE_NAME, selectedPackageName.value)
+ outState.putBoolean(STATE_IS_HOLDER_CHECKED, isHolderChecked)
+ }
+
+ fun onRestoreInstanceState(savedInstanceState: Bundle) {
+ dontAskAgain.value = savedInstanceState.getBoolean(STATE_DONT_ASK_AGAIN)
+ selectedPackageName.value = savedInstanceState.getString(STATE_SELECTED_PACKAGE_NAME)
+ isHolderChecked = savedInstanceState.getBoolean(STATE_IS_HOLDER_CHECKED)
+ }
+
+ companion object {
+ const val STATE_DONT_ASK_AGAIN = "WearRequestRoleViewModel.state.DONT_ASK_AGAIN"
+ const val STATE_SELECTED_PACKAGE_NAME =
+ "WearRequestRoleViewModel.state.SELECTED_PACKAGE_NAME"
+ const val STATE_IS_HOLDER_CHECKED = "WearRequestRoleViewModel.state.IS_HOLDER_CHECKED"
+ }
+}
+
+/** Factory for a WearRequestRoleViewModel */
+class WearRequestRoleViewModelFactory : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return WearRequestRoleViewModel() as T
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
index 6081695b5..5114af536 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
@@ -19,7 +19,6 @@ package com.android.permissioncontroller.role.utils;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -34,6 +33,8 @@ import com.android.permissioncontroller.role.ui.UserRestrictionAwarePreference;
import com.android.permissioncontroller.role.ui.behavior.RoleUiBehavior;
import com.android.role.controller.model.Role;
+import java.util.List;
+
/**
* Utility methods for Role UI behavior
*/
@@ -63,30 +64,6 @@ public final class RoleUiBehaviorUtils {
}
/**
- * @see RoleUiBehavior#isVisibleAsUser
- */
- public static boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- RoleUiBehavior uiBehavior = getUiBehavior(role);
- if (uiBehavior == null) {
- return role.isVisible();
- }
- return role.isVisible() && uiBehavior.isVisibleAsUser(role, user, context);
- }
-
- /**
- * Check whether this role should be visible to user, for current user.
- *
- * @param context the `Context` to retrieve system services
- *
- * @return whether this role should be visible to user.
- */
- public static boolean isVisible(@NonNull Role role, @NonNull Context context) {
- return isVisibleAsUser(role, Process.myUserHandle(), context);
- }
-
-
- /**
* @see RoleUiBehavior#getManageIntentAsUser
*/
@Nullable
@@ -103,28 +80,15 @@ public final class RoleUiBehaviorUtils {
* @see RoleUiBehavior#preparePreferenceAsUser
*/
public static void preparePreferenceAsUser(@NonNull Role role,
- @NonNull RolePreference preference, @NonNull UserHandle user,
- @NonNull Context context) {
+ @NonNull List<ApplicationInfo> applicationInfos, @NonNull RolePreference preference,
+ @NonNull UserHandle user, @NonNull Context context) {
prepareUserRestrictionAwarePreferenceAsUser(role, preference, user, context);
RoleUiBehavior uiBehavior = getUiBehavior(role);
if (uiBehavior == null) {
return;
}
- uiBehavior.preparePreferenceAsUser(role, preference, user, context);
- }
-
- /**
- * @see RoleUiBehavior#isApplicationVisibleAsUser
- */
- public static boolean isApplicationVisibleAsUser(@NonNull Role role,
- @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user,
- @NonNull Context context) {
- RoleUiBehavior uiBehavior = getUiBehavior(role);
- if (uiBehavior == null) {
- return true;
- }
- return uiBehavior.isApplicationVisibleAsUser(role, applicationInfo, user, context);
+ uiBehavior.preparePreferenceAsUser(role, preference, applicationInfos, user, context);
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java
index e959d20be..d23a23f7c 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java
@@ -39,6 +39,8 @@ import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
+import java.time.Duration;
+
/**
* Uses {@link android.app.job.JobScheduler} to schedule periodic calls to {@link
* SafetyCenterManager#refreshSafetySources} after boot completed if safety center is already
@@ -46,7 +48,6 @@ import com.android.modules.utils.build.SdkLevel;
*
* <p>The job waits until the device is in idle mode to minimize impact on system health.
*/
-// TODO(b/243493200): Add tests
public final class SafetyCenterBackgroundRefreshJobService extends JobService {
private static final String TAG = "SafetyCenterBackgroundR";
@@ -76,7 +77,7 @@ public final class SafetyCenterBackgroundRefreshJobService extends JobService {
Context context, @Nullable String actionString) {
if (!isActionStringValid(actionString)) {
- Log.v(TAG, "Ignoring a " + actionString + " broadcast.");
+ Log.i(TAG, "Ignoring a " + actionString + " broadcast.");
return;
}
@@ -94,7 +95,7 @@ public final class SafetyCenterBackgroundRefreshJobService extends JobService {
}
if (!safetyCenterManager.isSafetyCenterEnabled()) {
- Log.v(
+ Log.i(
TAG,
"Received a "
+ actionString
@@ -104,30 +105,26 @@ public final class SafetyCenterBackgroundRefreshJobService extends JobService {
return;
}
+ Duration periodicBackgroundRefreshInterval =
+ SafetyCenterJobServiceFlags.getPeriodicBackgroundRefreshInterval();
JobInfo jobInfo =
new JobInfo.Builder(
SAFETY_CENTER_BACKGROUND_REFRESH_JOB_ID,
new ComponentName(
context, SafetyCenterBackgroundRefreshJobService.class))
.setRequiresDeviceIdle(true)
- .setRequiresCharging(
- SafetyCenterJobServiceFlags.getBackgroundRefreshRequiresCharging())
- .setPeriodic(
- SafetyCenterJobServiceFlags.getPeriodicBackgroundRefreshInterval()
- .toMillis())
+ .setRequiresCharging(true)
+ .setPeriodic(periodicBackgroundRefreshInterval.toMillis())
.build();
Log.v(
TAG,
- "Scheduling a periodic background refresh with "
- + ", interval="
- + jobInfo.getIntervalMillis()
- + "requires charging="
- + jobInfo.isRequireCharging());
+ "Scheduling a periodic background refresh with interval="
+ + periodicBackgroundRefreshInterval);
int scheduleResult = jobScheduler.schedule(jobInfo);
if (scheduleResult != RESULT_SUCCESS) {
- Log.e(
+ Log.w(
TAG,
"Could not schedule the background refresh job, scheduleResult="
+ scheduleResult);
@@ -138,7 +135,7 @@ public final class SafetyCenterBackgroundRefreshJobService extends JobService {
public boolean onStartJob(JobParameters params) {
// background thread not required, PC APK makes all API calls in main thread
if (!SafetyCenterJobServiceFlags.areBackgroundRefreshesEnabled()) {
- Log.v(TAG, "Background refreshes are not enabled, skipping job.");
+ Log.i(TAG, "Background refreshes are not enabled, skipping job.");
return false; // job is no longer running
}
SafetyCenterManager safetyCenterManager = this.getSystemService(SafetyCenterManager.class);
@@ -147,7 +144,7 @@ public final class SafetyCenterBackgroundRefreshJobService extends JobService {
return false; // job is no longer running
}
if (!safetyCenterManager.isSafetyCenterEnabled()) {
- Log.v(TAG, "Safety center is not enabled, skipping job.");
+ Log.i(TAG, "Safety center is not enabled, skipping job.");
return false; // job is no longer running
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java
index bdca4d77d..23e048e7b 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java
@@ -26,8 +26,6 @@ public class SafetyCenterJobServiceFlags {
private static final Duration DEFAULT_PERIODIC_BACKGROUND_REFRESH_INTERVAL = Duration.ofDays(1);
private static final String PROPERTY_BACKGROUND_REFRESH_IS_ENABLED =
"safety_center_background_refresh_is_enabled";
- private static final String PROPERTY_BACKGROUND_REFRESH_REQUIRES_CHARGING =
- "safety_center_background_requires_charging";
private static final String PROPERTY_PERIODIC_BACKGROUND_REFRESH_INTERVAL_MILLIS =
"safety_center_periodic_background_interval_millis";
@@ -47,15 +45,4 @@ public class SafetyCenterJobServiceFlags {
PROPERTY_PERIODIC_BACKGROUND_REFRESH_INTERVAL_MILLIS,
DEFAULT_PERIODIC_BACKGROUND_REFRESH_INTERVAL.toMillis()));
}
-
- /**
- * Returns whether we should constrain background refresh jobs to only run when the device is
- * charging.
- */
- static boolean getBackgroundRefreshRequiresCharging() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_BACKGROUND_REFRESH_REQUIRES_CHARGING,
- true);
- }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterSearchIndexablesProvider.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterSearchIndexablesProvider.kt
index 8e5e63452..88dd8a6e3 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterSearchIndexablesProvider.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterSearchIndexablesProvider.kt
@@ -52,7 +52,7 @@ import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsVie
import com.android.safetycenter.internaldata.SafetyCenterBundles
import com.android.safetycenter.internaldata.SafetyCenterEntryId
import com.android.safetycenter.internaldata.SafetyCenterIds
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
/** [android.provider.SearchIndexablesProvider] for Safety Center. */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@@ -67,7 +67,7 @@ class SafetyCenterSearchIndexablesProvider : BaseSearchIndexablesProvider() {
val context = requireContext()
val safetyCenterManager =
context.getSystemService(SafetyCenterManager::class.java) ?: return cursor
- val resourcesContext = SafetyCenterResourcesContext(context)
+ val safetyCenterResourcesApk = SafetyCenterResourcesApk(context)
val screenTitle = context.getString(R.string.safety_center_dashboard_page_title)
@@ -76,7 +76,11 @@ class SafetyCenterSearchIndexablesProvider : BaseSearchIndexablesProvider() {
SdkLevel.isAtLeastU() &&
safetySourcesGroup.type == SAFETY_SOURCES_GROUP_TYPE_STATEFUL
) {
- cursor.addSafetySourcesGroupRow(safetySourcesGroup, resourcesContext, screenTitle)
+ cursor.addSafetySourcesGroupRow(
+ safetySourcesGroup,
+ safetyCenterResourcesApk,
+ screenTitle
+ )
}
safetySourcesGroup.safetySources
.asSequence()
@@ -85,7 +89,7 @@ class SafetyCenterSearchIndexablesProvider : BaseSearchIndexablesProvider() {
cursor.addSafetySourceRow(
context,
safetySource,
- resourcesContext,
+ safetyCenterResourcesApk,
safetyCenterManager,
screenTitle
)
@@ -139,11 +143,12 @@ class SafetyCenterSearchIndexablesProvider : BaseSearchIndexablesProvider() {
private fun MatrixCursor.addSafetySourcesGroupRow(
safetySourcesGroups: SafetySourcesGroup,
- resourcesContext: SafetyCenterResourcesContext,
+ safetyCenterResourcesApk: SafetyCenterResourcesApk,
screenTitle: String,
) {
val groupTitle =
- resourcesContext.getNotEmptyStringOrNull(safetySourcesGroups.titleResId) ?: return
+ safetyCenterResourcesApk.getNotEmptyStringOrNull(safetySourcesGroups.titleResId)
+ ?: return
newRow()
.add(COLUMN_RANK, 0)
@@ -157,11 +162,12 @@ class SafetyCenterSearchIndexablesProvider : BaseSearchIndexablesProvider() {
private fun MatrixCursor.addSafetySourceRow(
context: Context,
safetySource: SafetySource,
- resourcesContext: SafetyCenterResourcesContext,
+ safetyCenterResourcesApk: SafetyCenterResourcesApk,
safetyCenterManager: SafetyCenterManager,
screenTitle: String,
) {
- val searchTerms = resourcesContext.getNotEmptyStringOrNull(safetySource.searchTermsResId)
+ val searchTerms =
+ safetyCenterResourcesApk.getNotEmptyStringOrNull(safetySource.searchTermsResId)
var isPersonalEntryAdded = false
var isWorkEntryAdded = false
@@ -194,19 +200,19 @@ class SafetyCenterSearchIndexablesProvider : BaseSearchIndexablesProvider() {
}
if (!isPersonalEntryAdded) {
- resourcesContext.getNotEmptyStringOrNull(safetySource.titleResId)?.let {
+ safetyCenterResourcesApk.getNotEmptyStringOrNull(safetySource.titleResId)?.let {
addIndexableRow(title = it, isWorkProfile = false)
}
}
if (!isWorkEntryAdded && safetySource.profile == SafetySource.PROFILE_ALL) {
- resourcesContext.getNotEmptyStringOrNull(safetySource.titleForWorkResId)?.let {
+ safetyCenterResourcesApk.getNotEmptyStringOrNull(safetySource.titleForWorkResId)?.let {
addIndexableRow(title = it, isWorkProfile = true)
}
}
}
- private fun Context.getNotEmptyStringOrNull(resId: Int): String? =
+ private fun SafetyCenterResourcesApk.getNotEmptyStringOrNull(resId: Int): String? =
if (resId != Resources.ID_NULL) {
getString(resId).takeIf { it.isNotEmpty() }
} else {
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java
index 79fc41249..3ab4faa66 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java
@@ -111,9 +111,9 @@ public class ClickableDisabledSwitchPreference extends SwitchPreference {
});
if (prefState.getAdmin() != null && prefState.getChecked()) {
- setSummary(R.string.enabled_by_admin);
+ setSummary(com.android.settingslib.widget.restricted.R.string.enabled_by_admin);
} else if (prefState.getAdmin() != null) {
- setSummary(R.string.disabled_by_admin);
+ setSummary(com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
} else if (prefType.equals(Pref.MIC)) {
setSummary(R.string.mic_toggle_description);
} else if (prefType.equals(Pref.CAMERA)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt
index cdc5cc1f3..20ac4c7a5 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt
@@ -27,7 +27,7 @@ internal class CollapsableGroupCardHelper {
private companion object {
private const val EXPANDED_ENTRY_GROUPS_SAVED_INSTANCE_STATE_KEY =
- "expanded_entry_groups_saved_instance_state_key"
+ "expanded_entry_groups_saved_instance_state_key"
}
fun restoreState(state: Bundle?) {
@@ -39,8 +39,8 @@ internal class CollapsableGroupCardHelper {
fun saveState(outState: Bundle) {
outState.putCharSequenceArray(
- EXPANDED_ENTRY_GROUPS_SAVED_INSTANCE_STATE_KEY,
- expandedGroups.toTypedArray()
+ EXPANDED_ENTRY_GROUPS_SAVED_INSTANCE_STATE_KEY,
+ expandedGroups.toTypedArray()
)
}
@@ -52,6 +52,5 @@ internal class CollapsableGroupCardHelper {
expandedGroups.add(groupId)
}
- fun isGroupExpanded(groupId: CharSequence): Boolean =
- expandedGroups.contains(groupId)
+ fun isGroupExpanded(groupId: CharSequence): Boolean = expandedGroups.contains(groupId)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt
index 1950a0976..d5c7c3738 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt
@@ -17,14 +17,15 @@ package com.android.permissioncontroller.safetycenter.ui
import androidx.preference.Preference
-/** Allows comparison with a [Preference] to determine if it has been changed.
+/**
+ * Allows comparison with a [Preference] to determine if it has been changed.
*
* @see SafetyPreferenceComparisonCallback
*/
internal interface ComparablePreference {
- /** Returns true if given Preference represents an item of the same kind. */
+ /** Returns true if given Preference represents an item of the same kind. */
fun isSameItem(preference: Preference): Boolean
- /** Returns true if given Preference contains the same data. */
+ /** Returns true if given Preference contains the same data. */
fun hasSameContents(preference: Preference): Boolean
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreferenceCategory.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreferenceCategory.kt
index 55d27dbb3..f08614bf4 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreferenceCategory.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreferenceCategory.kt
@@ -25,13 +25,17 @@ import androidx.preference.PreferenceCategory
import com.android.permissioncontroller.R
/** A {@link PreferenceCategory} that implements {@link ComparablePreference} interface. */
-internal class ComparablePreferenceCategory @JvmOverloads constructor(
+internal class ComparablePreferenceCategory
+@JvmOverloads
+constructor(
context: Context,
attrs: AttributeSet? = null,
- defStyleAttr: Int = getAttr(
+ defStyleAttr: Int =
+ getAttr(
context,
- R.attr.preferenceCategoryStyle,
- android.R.attr.preferenceCategoryStyle),
+ androidx.preference.R.attr.preferenceCategoryStyle,
+ android.R.attr.preferenceCategoryStyle
+ ),
defStyleRes: Int = 0
) : PreferenceCategory(context, attrs, defStyleAttr, defStyleRes), ComparablePreference {
@@ -47,8 +51,8 @@ internal class ComparablePreferenceCategory @JvmOverloads constructor(
}
override fun isSameItem(preference: Preference): Boolean =
- preference is ComparablePreferenceCategory && TextUtils.equals(key, preference.key)
+ preference is ComparablePreferenceCategory && TextUtils.equals(key, preference.key)
override fun hasSameContents(preference: Preference): Boolean =
- preference is ComparablePreferenceCategory && TextUtils.equals(title, preference.title)
+ preference is ComparablePreferenceCategory && TextUtils.equals(title, preference.title)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EntriesTopPaddingPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EntriesTopPaddingPreference.kt
new file mode 100644
index 000000000..077ccfa2d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EntriesTopPaddingPreference.kt
@@ -0,0 +1,13 @@
+package com.android.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.preference.Preference
+import com.android.permissioncontroller.R
+
+class EntriesTopPaddingPreference(context: Context, attrs: AttributeSet) :
+ Preference(context, attrs) {
+ init {
+ layoutResource = R.layout.preference_entries_top_padding
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt
index 6f56874eb..1bdc0dc39 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt
@@ -43,7 +43,8 @@ class EqualWidthContainer @JvmOverloads constructor(context: Context, attrs: Att
nonSpaceItems.forEach {
it.measure(
MeasureSpec.makeMeasureSpec(neededWidthPerNonSpaceItem, EXACTLY),
- MeasureSpec.makeMeasureSpec(it.measuredHeight, EXACTLY))
+ MeasureSpec.makeMeasureSpec(it.measuredHeight, EXACTLY)
+ )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt
index 58bec87b8..51f550944 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt
@@ -43,10 +43,7 @@ import java.math.BigInteger
import java.security.MessageDigest
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
-class InteractionLogger
-private constructor(
- private val noLogSourceIds: Set<String?>
-) {
+class InteractionLogger private constructor(private val noLogSourceIds: Set<String?>) {
var sessionId: Long = Constants.INVALID_SESSION_ID
var viewType: ViewType = ViewType.UNKNOWN
var navigationSource: NavigationSource = NavigationSource.UNKNOWN
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt
index 2bc83eb10..c83737649 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt
@@ -91,9 +91,11 @@ class IssueCardAnimator(val callback: AnimationCallback) {
// view groups.
defaultIssueContentGroup.visibility = View.INVISIBLE
- // These two views are outside of the group since their visibility must be set
+ // These views are outside of the group since their visibility must be set
// independently of the rest of the group, and some frustrating constraints of
// constraint layout's behavior. See b/242705351 for context.
+ makeInvisibleIfVisible(holder.findViewById(R.id.issue_card_attribution_title))
+ makeInvisibleIfVisible(holder.findViewById(R.id.issue_card_dismiss_btn))
makeInvisibleIfVisible(holder.findViewById(R.id.issue_card_subtitle))
makeInvisibleIfVisible(holder.findViewById(R.id.issue_card_protected_by_android))
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java
index c56cce0a5..7622270b9 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java
@@ -30,6 +30,7 @@ import android.os.Bundle;
import android.safetycenter.SafetyCenterIssue;
import android.text.TextUtils;
import android.util.Log;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
@@ -134,9 +135,7 @@ public class IssueCardPreference extends Preference implements ComparablePrefere
configureSafetyProtectionView(holder);
maybeStartResolutionAnimation(holder);
- mSafetyCenterViewModel
- .getInteractionLogger()
- .recordIssueViewed(mIssue, mIsDismissed);
+ mSafetyCenterViewModel.getInteractionLogger().recordIssueViewed(mIssue, mIsDismissed);
}
private void maybeDisplayText(@Nullable CharSequence maybeText, TextView textView) {
@@ -424,8 +423,14 @@ public class IssueCardPreference extends Preference implements ComparablePrefere
ActionButtonBuilder(SafetyCenterIssue.Action action, Context context) {
mAction = action;
mContext = context;
- mContextThemeWrapper =
- new ContextThemeWrapper(context, R.style.Theme_MaterialComponents_DayNight);
+
+ TypedValue buttonThemeValue = new TypedValue();
+ mContext.getTheme()
+ .resolveAttribute(
+ R.attr.scActionButtonTheme,
+ buttonThemeValue,
+ /* resolveRefs= */ false);
+ mContextThemeWrapper = new ContextThemeWrapper(context, buttonThemeValue.data);
}
public ActionButtonBuilder setIndex(int index) {
@@ -540,9 +545,11 @@ public class IssueCardPreference extends Preference implements ComparablePrefere
return;
}
- int margin =
- mContext.getResources()
- .getDimensionPixelSize(R.dimen.sc_action_button_list_margin);
+ int marginRes =
+ mIsLargeScreen
+ ? R.dimen.sc_action_button_list_margin_large_screen
+ : R.dimen.sc_action_button_list_margin;
+ int margin = mContext.getResources().getDimensionPixelSize(marginRes);
Space space = new Space(mContext);
space.setLayoutParams(new ViewGroup.LayoutParams(margin, margin));
buttonList.addView(space);
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt
index 55293f775..9121c76c2 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt
@@ -46,16 +46,19 @@ class MoreIssuesCardAnimator {
super.onAnimationEnd(drawable)
statusIcon.setImageResource(endSeverityLevelResId)
}
- })
+ }
+ )
setStatusIconDrawable.start()
}
}
fun cancelStatusAnimation(statusIcon: ImageView) {
val statusDrawable: Drawable? = statusIcon.drawable
- if (statusDrawable != null &&
- statusDrawable is AnimatedVectorDrawable &&
- statusDrawable.isRunning) {
+ if (
+ statusDrawable != null &&
+ statusDrawable is AnimatedVectorDrawable &&
+ statusDrawable.isRunning
+ ) {
statusDrawable.clearAnimationCallbacks()
statusDrawable.stop()
}
@@ -106,7 +109,10 @@ class MoreIssuesCardAnimator {
Log.e(
MoreIssuesCardPreference.TAG,
String.format(
- "Unexpected SafetyCenterIssue.IssueSeverityLevel: %d", endSeverityLevel))
+ "Unexpected SafetyCenterIssue.IssueSeverityLevel: %d",
+ endSeverityLevel
+ )
+ )
R.drawable.ic_safety_null_state
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt
index 6bf4b52e8..377c8d5f5 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt
@@ -41,7 +41,10 @@ data class ParsedSafetyCenterIntent(
getParcelableExtra(EXTRA_SAFETY_SOURCE_USER_HANDLE, UserHandle::class.java)
val safetyCenterIssueKey: SafetyCenterIssueKey? =
createSafetyCenterIssueKey(
- safetySourceId, safetySourceIssueId, safetySourceUserHandle)
+ safetySourceId,
+ safetySourceIssueId,
+ safetySourceUserHandle
+ )
// Check if we've navigated from QS or if focusing on single issue and issues should be
// expanded
@@ -56,8 +59,8 @@ data class ParsedSafetyCenterIntent(
*
* @param safetySourceId source ID for a {@link SafetySourceIssue}
* @param safetySourceIssueId an issue ID for a {@link SafetySourceIssue}
- * @param safetySourceUserHandle the specific a {@link android.os.UserHandle} associated with
- * issue
+ * @param safetySourceUserHandle the specific a {@link android.os.UserHandle} associated
+ * with issue
*/
private fun createSafetyCenterIssueKey(
safetySourceId: String?,
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt
index 01e8f8d15..b1c48befd 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt
@@ -51,10 +51,12 @@ internal enum class PositionInCardList(val backgroundDrawableResId: Int) {
fun getTopMargin(context: Context): Int =
when (this) {
- CARD_START, CARD_START_END, CARD_START_LIST_END ->
- context.resources.getDimensionPixelSize(R.dimen.sc_card_margin)
- LIST_START, LIST_START_CARD_END, LIST_START_END ->
- context.resources.getDimensionPixelSize(R.dimen.sc_list_margin_top)
+ CARD_START,
+ CARD_START_END,
+ CARD_START_LIST_END -> context.resources.getDimensionPixelSize(R.dimen.sc_card_margin)
+ LIST_START,
+ LIST_START_CARD_END,
+ LIST_START_END -> context.resources.getDimensionPixelSize(R.dimen.sc_list_margin_top)
else -> 0
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt
index 54ba9560f..ee23d3131 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt
@@ -81,7 +81,7 @@ class PrivacySubpageFragment : SafetyCenterFragment() {
}
override fun renderSafetyCenterData(uiData: SafetyCenterUiData?) {
- Log.d(TAG, "renderSafetyCenterEntryGroup called with $uiData")
+ Log.v(TAG, "renderSafetyCenterEntryGroup called with $uiData")
val entryGroup = uiData?.getMatchingGroup(PRIVACY_SOURCES_GROUP_ID)
if (entryGroup == null) {
Log.w(
@@ -114,11 +114,12 @@ class PrivacySubpageFragment : SafetyCenterFragment() {
subpageIssues,
subpageDismissedIssues,
uiData.resolvedIssues,
- requireActivity().getTaskId())
+ requireActivity().getTaskId()
+ )
}
private fun updateSafetyCenterEntries(entryGroup: SafetyCenterEntryGroup) {
- Log.d(TAG, "updateSafetyCenterEntries called with $entryGroup")
+ Log.v(TAG, "updateSafetyCenterEntries called with $entryGroup")
subpageGenericEntryGroup.removeAll()
subpageControlsExtraEntryGroup.removeAll()
@@ -130,9 +131,13 @@ class PrivacySubpageFragment : SafetyCenterFragment() {
SafetySubpageEntryPreference(
requireContext(),
PendingIntentSender.getTaskIdForEntry(
- entryId, sameTaskSourceIds, requireActivity()),
+ entryId,
+ sameTaskSourceIds,
+ requireActivity()
+ ),
entry,
- safetyCenterViewModel)
+ safetyCenterViewModel
+ )
if (sourceId == "AndroidPrivacyControls") {
// No action required here because the privacy controls are rendered separately
@@ -149,7 +154,11 @@ class PrivacySubpageFragment : SafetyCenterFragment() {
fun setSwitchPreference(prefType: Pref) {
val switchPreference: ClickableDisabledSwitchPreference? = findPreference(prefType.key)
switchPreference?.setupState(
- prefStates[prefType], prefType, privacyControlsViewModel, this)
+ prefStates[prefType],
+ prefType,
+ privacyControlsViewModel,
+ this
+ )
}
setSwitchPreference(Pref.MIC)
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
index 8f31da828..ae67250a5 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
@@ -30,12 +30,14 @@ import static com.android.permissioncontroller.safetycenter.SafetyCenterConstant
import android.app.ActionBar;
import android.content.Intent;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.provider.Settings;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.config.SafetyCenterConfig;
import android.safetycenter.config.SafetySource;
import android.safetycenter.config.SafetySourcesGroup;
+import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -103,11 +105,35 @@ public final class SafetyCenterActivity extends CollapsingToolbarBaseActivity {
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
- .add(R.id.content_frame, frag)
+ .add(com.android.settingslib.collapsingtoolbar.R.id.content_frame, frag)
.commitNow();
}
+ configureHomeButton();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ maybeRedirectIfDisabled();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ // We don't set configChanges, but small screen size changes may still be delivered here.
+ super.onConfigurationChanged(newConfig);
+ configureHomeButton();
+ }
+
+ /** Decide whether a home/back button should be shown or not. */
+ private void configureHomeButton() {
ActionBar actionBar = getActionBar();
+ Fragment frag = getSupportFragmentManager().findFragmentById(
+ com.android.settingslib.collapsingtoolbar.R.id.content_frame);
+ if (actionBar == null || frag == null) {
+ return;
+ }
+
// Only the homepage can be considered a "second layer" page as it's the only one that
// can be reached from the Settings menu. The other pages are only reachable using
// a direct intent (e.g. notification, "first layer") and/or by navigating within Safety
@@ -115,30 +141,33 @@ public final class SafetyCenterActivity extends CollapsingToolbarBaseActivity {
// Note that the homepage can also be a "first layer" page, but that would only happen
// if the activity is not embedded.
boolean isSecondLayerPage = frag instanceof SafetyCenterScrollWrapperFragment;
- if (actionBar != null
- && ActivityEmbeddingUtils.shouldHideNavigateUpButton(this, isSecondLayerPage)) {
+ if (ActivityEmbeddingUtils.shouldHideNavigateUpButton(this, isSecondLayerPage)) {
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setHomeButtonEnabled(false);
}
}
- @Override
- protected void onStart() {
- super.onStart();
- maybeRedirectIfDisabled();
- }
-
private boolean maybeRedirectIfDisabled() {
if (mSafetyCenterManager == null || !mSafetyCenterManager.isSafetyCenterEnabled()) {
Log.w(TAG, "Safety Center disabled, redirecting to settings page");
startActivity(
- new Intent(Settings.ACTION_SETTINGS).addFlags(FLAG_ACTIVITY_FORWARD_RESULT));
+ new Intent(getActionToRedirectWhenDisabled())
+ .addFlags(FLAG_ACTIVITY_FORWARD_RESULT));
finish();
return true;
}
return false;
}
+ private String getActionToRedirectWhenDisabled() {
+ boolean isPrivacyControls =
+ TextUtils.equals(getIntent().getAction(), PRIVACY_CONTROLS_ACTION);
+ if (isPrivacyControls) {
+ return Settings.ACTION_PRIVACY_SETTINGS;
+ }
+ return Settings.ACTION_SETTINGS;
+ }
+
private boolean maybeRedirectIntoTwoPaneSettings() {
return shouldUseTwoPaneSettings() && tryRedirectTwoPaneSettings();
}
@@ -192,7 +221,7 @@ public final class SafetyCenterActivity extends CollapsingToolbarBaseActivity {
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
long sessionId =
intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID);
- Log.v(
+ Log.i(
TAG,
"privacy source notification metric, source "
+ privacySource
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
index 940cb2f69..874e3c750 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
@@ -38,18 +38,22 @@ import android.safetycenter.SafetyCenterIssue;
import android.safetycenter.SafetyCenterStaticEntry;
import android.safetycenter.SafetyCenterStaticEntryGroup;
import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
+import androidx.recyclerview.widget.RecyclerView;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterUiData;
import com.android.permissioncontroller.safetycenter.ui.model.StatusUiData;
import com.android.safetycenter.internaldata.SafetyCenterBundles;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import kotlin.Unit;
@@ -113,6 +117,7 @@ public final class SafetyCenterDashboardFragment extends SafetyCenterFragment {
mIssuesGroup = getPreferenceScreen().findPreference(ISSUES_GROUP_KEY);
mEntriesGroup = getPreferenceScreen().findPreference(ENTRIES_GROUP_KEY);
mStaticEntriesGroup = getPreferenceScreen().findPreference(STATIC_ENTRIES_GROUP_KEY);
+
if (mIsQuickSettingsFragment) {
getPreferenceScreen().removePreference(mEntriesGroup);
mEntriesGroup = null;
@@ -126,6 +131,19 @@ public final class SafetyCenterDashboardFragment extends SafetyCenterFragment {
prerenderCurrentSafetyCenterData();
}
+ @Override
+ public RecyclerView onCreateRecyclerView(
+ LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+ RecyclerView recyclerView =
+ super.onCreateRecyclerView(inflater, parent, savedInstanceState);
+
+ if (mIsQuickSettingsFragment) {
+ recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
+ recyclerView.setVerticalScrollBarEnabled(false);
+ }
+ return recyclerView;
+ }
+
// Set the default divider line between preferences to be transparent
@Override
public void setDivider(Drawable divider) {
@@ -162,10 +180,10 @@ public final class SafetyCenterDashboardFragment extends SafetyCenterFragment {
private void updateStatus(StatusUiData statusUiData) {
if (mIsQuickSettingsFragment) {
- SafetyCenterResourcesContext safetyCenterResourcesContext =
- new SafetyCenterResourcesContext(requireContext());
+ SafetyCenterResourcesApk safetyCenterResourcesApk =
+ new SafetyCenterResourcesApk(requireContext());
boolean hasPendingActions =
- safetyCenterResourcesContext
+ safetyCenterResourcesApk
.getStringByName("overall_severity_level_ok_review_summary")
.equals(statusUiData.getOriginalSummary().toString());
@@ -180,8 +198,7 @@ public final class SafetyCenterDashboardFragment extends SafetyCenterFragment {
if (uiData == null) return;
SafetyCenterData data = uiData.getSafetyCenterData();
- Log.i(TAG, String.format("renderSafetyCenterData called with: %s", data));
-
+ Log.v(TAG, String.format("renderSafetyCenterData called with: %s", data));
Context context = getContext();
if (context == null) {
return;
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt
index c435a0f1a..9feecf5d4 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt
@@ -32,7 +32,7 @@ import com.android.permissioncontroller.safetycenter.ui.ParsedSafetyCenterIntent
import com.android.permissioncontroller.safetycenter.ui.model.LiveSafetyCenterViewModelFactory
import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterUiData
import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
/** A base fragment that represents a page in Safety Center. */
@RequiresApi(TIRAMISU)
@@ -72,7 +72,7 @@ abstract class SafetyCenterFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
sameTaskSourceIds =
- SafetyCenterResourcesContext(requireContext())
+ SafetyCenterResourcesApk(requireContext())
.getStringByName("config_same_task_safety_source_ids")
.split(",")
safetyCenterSessionId = requireArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID)
@@ -92,7 +92,7 @@ abstract class SafetyCenterFragment : PreferenceFragmentCompat() {
}
val safetyCenterIntent: ParsedSafetyCenterIntent =
- requireActivity().getIntent().toSafetyCenterIntent()
+ requireActivity().intent.toSafetyCenterIntent()
val isQsFragment =
getArguments()?.getBoolean(QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT, false) ?: false
collapsableIssuesCardHelper =
@@ -120,7 +120,7 @@ abstract class SafetyCenterFragment : PreferenceFragmentCompat() {
override fun onStart() {
super.onStart()
configureInteractionLogger()
- safetyCenterViewModel.interactionLogger.record(Action.SAFETY_CENTER_VIEWED)
+ logSafetyCenterViewedEvent()
}
override fun onResume() {
@@ -162,6 +162,26 @@ abstract class SafetyCenterFragment : PreferenceFragmentCompat() {
abstract fun configureInteractionLogger()
+ private fun logSafetyCenterViewedEvent() {
+ // If Safety Center was opened due to an associated notification click (i.e. intent has an
+ // associated issue), record that issue's metadata on the SAFETY_CENTER_VIEWED event
+ val maybeIssueKey = requireActivity().intent.toSafetyCenterIntent().safetyCenterIssueKey
+ val maybeIssue =
+ maybeIssueKey?.let {
+ safetyCenterViewModel.getCurrentSafetyCenterDataAsUiData().getMatchingIssue(it)
+ }
+
+ if (maybeIssue == null) {
+ safetyCenterViewModel.interactionLogger.record(Action.SAFETY_CENTER_VIEWED)
+ } else {
+ safetyCenterViewModel.interactionLogger.recordForIssue(
+ Action.SAFETY_CENTER_VIEWED,
+ maybeIssue,
+ isDismissed = false
+ )
+ }
+ }
+
private fun displayErrorDetails(errorDetails: SafetyCenterErrorDetails?) {
if (errorDetails == null) return
Toast.makeText(requireContext(), errorDetails.errorMessage, Toast.LENGTH_LONG).show()
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java
index f69746e39..8804b3c29 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java
@@ -149,6 +149,7 @@ public class SafetyCenterQsFragment extends Fragment {
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.safety_center_qs, container, false);
root.setVisibility(View.GONE);
+ root.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS);
View closeButton = root.findViewById(R.id.close_button);
closeButton.setOnClickListener((v) -> requireActivity().finish());
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt
index 5e45d2b3c..fdade2189 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt
@@ -26,7 +26,7 @@ import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
import com.android.permissioncontroller.R
import com.android.permissioncontroller.safetycenter.ui.SafetyBrandChipPreference.Companion.closeSubpage
import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterUiData
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
import com.android.settingslib.widget.FooterPreference
/** A fragment that represents a generic subpage in Safety Center. */
@@ -72,7 +72,7 @@ class SafetyCenterSubpageFragment : SafetyCenterFragment() {
}
override fun renderSafetyCenterData(uiData: SafetyCenterUiData?) {
- Log.d(TAG, "renderSafetyCenterEntryGroup called with $uiData")
+ Log.v(TAG, "renderSafetyCenterEntryGroup called with $uiData")
val entryGroup = uiData?.getMatchingGroup(sourceGroupId)
if (entryGroup == null) {
Log.w(TAG, "$sourceGroupId doesn't match any of the existing SafetySourcesGroup IDs")
@@ -88,8 +88,7 @@ class SafetyCenterSubpageFragment : SafetyCenterFragment() {
private fun setupIllustration() {
val resName = "illustration_${SnakeCaseConverter.fromCamelCase(sourceGroupId)}"
val context = requireContext()
- val drawable =
- SafetyCenterResourcesContext(context).getDrawableByName(resName, context.theme)
+ val drawable = SafetyCenterResourcesApk(context).getDrawableByName(resName, context.theme)
if (drawable == null) {
Log.w(TAG, "$sourceGroupId doesn't have any matching illustration")
subpageIllustration.setVisible(false)
@@ -100,7 +99,7 @@ class SafetyCenterSubpageFragment : SafetyCenterFragment() {
private fun setupFooter() {
val resName = "${SnakeCaseConverter.fromCamelCase(sourceGroupId)}_footer"
- val footerText = SafetyCenterResourcesContext(requireContext()).getStringByName(resName)
+ val footerText = SafetyCenterResourcesApk(requireContext()).getStringByName(resName)
if (footerText.isEmpty()) {
Log.w(TAG, "$sourceGroupId doesn't have any matching footer")
subpageFooter.setVisible(false)
@@ -137,7 +136,7 @@ class SafetyCenterSubpageFragment : SafetyCenterFragment() {
}
private fun updateSafetyCenterEntries(entryGroup: SafetyCenterEntryGroup) {
- Log.d(TAG, "updateSafetyCenterEntries called with $entryGroup")
+ Log.v(TAG, "updateSafetyCenterEntries called with $entryGroup")
subpageEntryGroup.removeAll()
for (entry in entryGroup.entries) {
subpageEntryGroup.addPreference(
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt
index 0e368291e..01d23241f 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt
@@ -28,6 +28,7 @@ import androidx.annotation.RequiresApi
object SafetyCenterTouchTarget {
/**
* Resizes the touch target of views by delegating to the parent component.
+ *
* @param view component that will be expanded
* @param minTouchTargetSizeResource required minimum touch target size
*/
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt
index c48ad734b..a9cab3f85 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt
@@ -24,7 +24,7 @@ import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
* [onStartScanningAnimationStart], [onStartScanningAnimationEnd], etc.) it changes its internal
* state and may provide a presentation instruction in the form of [Action].
*/
-internal class SafetyStatusAnimationSequencer {
+class SafetyStatusAnimationSequencer {
private var isIconChangeAnimationRunning: Boolean = false
private var isScanAnimationRunning: Boolean = false
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java
index 0b8706a38..811841845 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java
@@ -27,6 +27,7 @@ import android.os.Looper;
import android.safetycenter.SafetyCenterStatus;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;
@@ -49,6 +50,8 @@ import java.util.Objects;
@RequiresApi(TIRAMISU)
public class SafetyStatusPreference extends Preference implements ComparablePreference {
+ private static final String TAG = "SafetyStatusPreference";
+
@Nullable private StatusUiData mStatus;
@Nullable private SafetyCenterViewModel mViewModel;
@@ -72,6 +75,7 @@ public class SafetyStatusPreference extends Preference implements ComparablePref
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
+ Log.v(TAG, String.format("onBindViewHolder called for status %s", mStatus));
if (mStatus == null) {
return;
@@ -140,12 +144,14 @@ public class SafetyStatusPreference extends Preference implements ComparablePref
if (mIsTextChangeAnimationRunning) {
return;
}
+ Log.v(TAG, "Starting status text animation");
String titleText = mStatus.getTitle().toString();
String summaryText = mStatus.getSummary(getContext()).toString();
boolean titleEquals = titleView.getText().toString().equals(titleText);
boolean summaryEquals = summaryView.getText().toString().equals(summaryText);
Runnable onFinish =
() -> {
+ Log.v(TAG, "Finishing status text animation");
mIsTextChangeAnimationRunning = false;
runTextAnimationIfNeeded(titleView, summaryView);
};
@@ -334,7 +340,12 @@ public class SafetyStatusPreference extends Preference implements ComparablePref
}
void setData(StatusUiData statusUiData) {
+ if (Objects.equals(mStatus, statusUiData)) {
+ return;
+ }
+
mStatus = statusUiData;
+ Log.v(TAG, String.format("setData called for status %s", mStatus));
safeNotifyChanged();
}
@@ -349,7 +360,14 @@ public class SafetyStatusPreference extends Preference implements ComparablePref
// Calling notifyChanged while recyclerview is scrolling or computing layout will result in an
// IllegalStateException. Post to handler to wait for UI to settle.
private void safeNotifyChanged() {
- new Handler(Looper.getMainLooper()).post(this::notifyChanged);
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
+ Log.v(
+ TAG,
+ String.format("Calling notifyChanged for status %s", mStatus));
+ notifyChanged();
+ });
}
@Override
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt
index 313798088..f4761d3a9 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt
@@ -94,7 +94,7 @@ class SafetySubpageEntryPreference(
private fun setupPreferenceKey() {
val entryId: SafetyCenterEntryId = SafetyCenterIds.entryIdFromString(entry.id)
val isWorkProfile =
- context.getSystemService(UserManager::class.java).isManagedProfile(entryId.userId)
+ context.getSystemService(UserManager::class.java)!!.isManagedProfile(entryId.userId)
val keySuffix = if (isWorkProfile) WORK_PROFILE_SUFFIX else PERSONAL_PROFILE_SUFFIX
setKey("${entryId.safetySourceId}_$keySuffix")
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt
index 4456bfa4d..45d97f05d 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt
@@ -17,7 +17,7 @@
package com.android.permissioncontroller.safetycenter.ui
/** Class used to convert a [String] to the `snake_case` format */
-internal object SnakeCaseConverter {
+object SnakeCaseConverter {
/** Converts a [String] from `camelCase` to `snake_case` */
fun fromCamelCase(input: String): String {
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt
index bb09783be..030b67be9 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt
@@ -62,21 +62,24 @@ internal class SpacerPreference(context: Context, attrs: AttributeSet) :
// we should ensure we won't add multiple listeners to the same view,
// and Preferences API does not allow to do cleanups when onViewRecycled,
// so we are keeping a track of the added listener attaching it as a tag to the View
- val listener: View.OnLayoutChangeListener = spacer.tag as? View.OnLayoutChangeListener
- ?: object : View.OnLayoutChangeListener {
- override fun onLayoutChange(
- v: View?,
- left: Int,
- top: Int,
- right: Int,
- bottom: Int,
- oldLeft: Int,
- oldTop: Int,
- oldRight: Int,
- oldBottom: Int
- ) {
- adjustHeight(spacer)
- }}.also { spacer.tag = it }
+ val listener: View.OnLayoutChangeListener =
+ spacer.tag as? View.OnLayoutChangeListener
+ ?: object : View.OnLayoutChangeListener {
+ override fun onLayoutChange(
+ v: View?,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ adjustHeight(spacer)
+ }
+ }
+ .also { spacer.tag = it }
spacer.removeOnLayoutChangeListener(listener)
spacer.addOnLayoutChangeListener(listener)
@@ -88,7 +91,10 @@ internal class SpacerPreference(context: Context, attrs: AttributeSet) :
return
}
- val contentParent = root.findViewById<ViewGroup>(R.id.content_parent)
+ val contentParent =
+ root.findViewById<ViewGroup>(
+ com.android.settingslib.collapsingtoolbar.R.id.content_parent
+ )
if (contentParent == null) {
return
}
@@ -96,27 +102,32 @@ internal class SpacerPreference(context: Context, attrs: AttributeSet) :
// differently due to the auto-scroll to highlight a specific item,
// and in this case we need to wait the content parent to be measured
if (contentParent.height == 0) {
- val globalLayoutObserver = object : ViewTreeObserver.OnGlobalLayoutListener {
- override fun onGlobalLayout() {
- contentParent.viewTreeObserver.removeOnGlobalLayoutListener(this)
- adjustHeight(spacer)
+ val globalLayoutObserver =
+ object : ViewTreeObserver.OnGlobalLayoutListener {
+ override fun onGlobalLayout() {
+ contentParent.viewTreeObserver.removeOnGlobalLayoutListener(this)
+ adjustHeight(spacer)
+ }
}
- }
contentParent.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutObserver)
return
}
- val collapsingToolbar = root.findViewById<View>(R.id.collapsing_toolbar)
- maxKnownToolbarHeight = max(maxKnownToolbarHeight, collapsingToolbar.height)
+ val collapsingToolbar =
+ root.findViewById<View>(
+ com.android.settingslib.collapsingtoolbar.R.id.collapsing_toolbar
+ )
+ maxKnownToolbarHeight = max(maxKnownToolbarHeight, collapsingToolbar!!.height)
val contentHeight = spacer.top + maxKnownToolbarHeight
- val desiredSpacerHeight = if (contentHeight > contentParent.height) {
- // making it 0 height will remove if from recyclerview
- 1
- } else {
- // to unlock the scrolling we need spacer to go slightly beyond the screen
- contentParent.height - contentHeight + 1
- }
+ val desiredSpacerHeight =
+ if (contentHeight > contentParent.height) {
+ // making it 0 height will remove if from recyclerview
+ 1
+ } else {
+ // to unlock the scrolling we need spacer to go slightly beyond the screen
+ contentParent.height - contentHeight + 1
+ }
val layoutParams = spacer.layoutParams
if (layoutParams.height != desiredSpacerHeight) {
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.kt
index 55288564c..8409ca75d 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.kt
@@ -129,21 +129,24 @@ object StatusAnimationResolver {
@JvmStatic
fun getStatusChangeAnimation(fromSeverity: Int, toSeverity: Int): Int =
- if (fromSeverity == toSeverity &&
- fromSeverity != SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK) {
+ if (
+ fromSeverity == toSeverity &&
+ fromSeverity != SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK
+ ) {
0
- } else when (fromSeverity) {
- SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK ->
- R.drawable.safety_status_info_to_info_anim
- SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
- R.drawable.safety_status_recommend_to_info_anim
- SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING -> {
- if (toSeverity == SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK) {
- R.drawable.safety_status_warn_to_info_anim
- } else {
- R.drawable.safety_status_warn_to_recommend_anim
+ } else
+ when (fromSeverity) {
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK ->
+ R.drawable.safety_status_info_to_info_anim
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.safety_status_recommend_to_info_anim
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING -> {
+ if (toSeverity == SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK) {
+ R.drawable.safety_status_warn_to_info_anim
+ } else {
+ R.drawable.safety_status_warn_to_recommend_anim
+ }
}
+ else -> 0
}
- else -> 0
- }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt
index a98fcf2ad..48acad438 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt
@@ -21,6 +21,7 @@ import android.transition.Transition
import android.transition.TransitionListenerAdapter
import android.transition.TransitionManager
import android.transition.TransitionSet
+import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
@@ -64,6 +65,9 @@ constructor(targetIds: List<Int>, changeDuration: Duration = DEFAULT_TEXT_CHANGE
if (textChanges.isEmpty()) {
return
}
+
+ Log.v(TAG, "Starting text animation")
+
val firstView = textChanges[0].first
val parentViewGroup: ViewGroup = firstView.parent as ViewGroup
val fadeOutTransition =
@@ -71,16 +75,14 @@ constructor(targetIds: List<Int>, changeDuration: Duration = DEFAULT_TEXT_CHANGE
.clone()
.addListener(
object : TransitionListenerAdapter() {
- override fun onTransitionStart(transition: Transition?) {
- super.onTransitionStart(transition)
- }
override fun onTransitionEnd(transition: Transition?) {
- super.onTransitionEnd(transition)
fadeTextIn(textChanges, parentViewGroup, onFinish)
}
- })
+ }
+ )
parentViewGroup.post {
TransitionManager.beginDelayedTransition(parentViewGroup, fadeOutTransition)
+ Log.v(TAG, "Starting text fade-out transition")
for ((textView, _) in textChanges) {
textView.visibility = View.INVISIBLE
}
@@ -98,13 +100,15 @@ constructor(targetIds: List<Int>, changeDuration: Duration = DEFAULT_TEXT_CHANGE
.addListener(
object : TransitionListenerAdapter() {
override fun onTransitionEnd(transition: Transition?) {
- super.onTransitionEnd(transition)
+ Log.v(TAG, String.format("Finishing text animation"))
onFinish?.run()
}
- })
+ }
+ )
parent.post {
TransitionManager.beginDelayedTransition(parent, fadeInTransition)
+ Log.v(TAG, "Starting text fade-in transition")
for ((textView, text) in textChanges) {
textView.text = text
textView.visibility = View.VISIBLE
@@ -117,6 +121,7 @@ constructor(targetIds: List<Int>, changeDuration: Duration = DEFAULT_TEXT_CHANGE
}
companion object {
+ private const val TAG = "TextFadeAnimator"
// Duration is for fade-out & fade-in individually, not combined
private val DEFAULT_TEXT_CHANGE_DURATION = Duration.ofMillis(167)
private val linearInterpolator = LinearInterpolator()
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterQsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterQsViewModel.kt
index 73c7da99f..fc7af5b84 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterQsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterQsViewModel.kt
@@ -45,6 +45,7 @@ import androidx.lifecycle.ViewModelProvider
import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
+import com.android.permissioncontroller.permission.data.get
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.LocationUtils
@@ -83,7 +84,10 @@ class SafetyCenterQsViewModel(
val userHandle = UserHandle.getUserHandleForUid(permGroupUsage.uid)
val lightAppPermissionGroupUsageKey =
LightAppPermissionGroupUsageKey(
- packageName, permissionGroupName, userHandle)
+ packageName,
+ permissionGroupName,
+ userHandle
+ )
val appPermGroupLiveData: LightAppPermGroupLiveData =
LightAppPermGroupLiveData[
Triple(packageName, permissionGroupName, userHandle)]
@@ -110,7 +114,8 @@ class SafetyCenterQsViewModel(
LightAppPermissionGroupUsageKey(
usage.packageName,
usage.permissionGroupName,
- UserHandle.getUserHandleForUid(usage.uid))]
+ UserHandle.getUserHandleForUid(usage.uid)
+ )]
?: return false
return group.supportsRuntimePerms &&
!group.hasInstallToRuntimeSplit &&
@@ -125,7 +130,8 @@ class SafetyCenterQsViewModel(
LightAppPermissionGroupUsageKey(
usage.packageName,
usage.permissionGroupName,
- UserHandle.getUserHandleForUid(usage.uid))]
+ UserHandle.getUserHandleForUid(usage.uid)
+ )]
?: return
KotlinUtils.revokeForegroundRuntimePermissions(app, group)
@@ -177,13 +183,16 @@ class SafetyCenterQsViewModel(
getSensorState(
Sensors.CAMERA,
UserManager.DISALLOW_CAMERA_TOGGLE,
- configCameraToggleEnabled),
+ configCameraToggleEnabled
+ ),
MICROPHONE to
getSensorState(
Sensors.MICROPHONE,
UserManager.DISALLOW_MICROPHONE_TOGGLE,
- configMicToggleEnabled),
- LOCATION to SensorState(true, locationEnabled, locationEnforcedAdmin))
+ configMicToggleEnabled
+ ),
+ LOCATION to SensorState(true, locationEnabled, locationEnforcedAdmin)
+ )
}
@Suppress("OVERRIDE_DEPRECATION")
@@ -221,13 +230,14 @@ class SafetyCenterQsViewModel(
return SensorState(
sensorConfigEnabled && sensorPrivacyManager.supportsSensorToggle(sensor),
!sensorPrivacyManager.isSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, sensor),
- getEnforcedAdmin(restriction))
+ getEnforcedAdmin(restriction)
+ )
}
private fun getEnforcedAdmin(restriction: String) =
- if (userManager
- .getUserRestrictionSources(restriction, Process.myUserHandle())
- .isNotEmpty()) {
+ if (
+ userManager.getUserRestrictionSources(restriction, Process.myUserHandle()).isNotEmpty()
+ ) {
RestrictedLockUtils.getProfileOrDeviceOwner(app, Process.myUserHandle())
} else {
null
@@ -250,10 +260,12 @@ class SafetyCenterQsViewModel(
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val resolveInfo: ResolveInfo? =
context.packageManager.resolveActivity(intent, PackageManager.ResolveInfoFlags.of(0))
- if (resolveInfo != null &&
- resolveInfo.activityInfo != null &&
- resolveInfo.activityInfo.permission ==
- android.Manifest.permission.START_VIEW_PERMISSION_USAGE) {
+ if (
+ resolveInfo != null &&
+ resolveInfo.activityInfo != null &&
+ resolveInfo.activityInfo.permission ==
+ android.Manifest.permission.START_VIEW_PERMISSION_USAGE
+ ) {
intent.component = ComponentName(usage.packageName, resolveInfo.activityInfo.name)
return intent
}
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 39241ff9a..69a315f08 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt
@@ -16,19 +16,30 @@
package com.android.permissioncontroller.safetycenter.ui.model
+import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.SafetyCenterData
import android.safetycenter.SafetyCenterEntryGroup
import android.safetycenter.SafetyCenterEntryOrGroup
import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK
import androidx.annotation.RequiresApi
import com.android.safetycenter.internaldata.SafetyCenterBundles.ISSUES_TO_GROUPS_BUNDLE_KEY
+import com.android.safetycenter.internaldata.SafetyCenterIds
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey
/** UI model representation of Safety Center Data */
data class SafetyCenterUiData(
val safetyCenterData: SafetyCenterData,
val resolvedIssues: Map<IssueId, ActionId> = emptyMap()
) {
+ @RequiresApi(TIRAMISU)
+ fun getMatchingIssue(issueKey: SafetyCenterIssueKey): SafetyCenterIssue? {
+ return safetyCenterData.issues.find {
+ SafetyCenterIds.issueIdFromString(it.id).safetyCenterIssueKey == issueKey
+ }
+ }
+
/** Returns the [SafetyCenterEntryGroup] corresponding to the provided ID */
@RequiresApi(UPSIDE_DOWN_CAKE)
fun getMatchingGroup(groupId: String): SafetyCenterEntryGroup? {
@@ -51,7 +62,7 @@ data class SafetyCenterUiData(
*/
@RequiresApi(UPSIDE_DOWN_CAKE)
fun getMatchingDismissedIssues(groupId: String): List<SafetyCenterIssue> =
- selectMatchingIssuesForGroup(groupId, safetyCenterData.dismissedIssues)
+ selectMatchingIssuesForGroup(groupId, safetyCenterData.visibleDismissedIssues())
@RequiresApi(UPSIDE_DOWN_CAKE)
private fun selectMatchingIssuesForGroup(
@@ -68,4 +79,9 @@ data class SafetyCenterUiData(
if (mappingExists) matchesInMapping else matchesByDefault
}
}
+
+ /** Returns the [SafetyCenterData.getDismissedIssues] that are meant to be visible in the UI. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ fun SafetyCenterData.visibleDismissedIssues() =
+ dismissedIssues.filter { it.severityLevel > ISSUE_SEVERITY_LEVEL_OK }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/LazyProperties.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/LazyProperties.kt
new file mode 100644
index 000000000..c02eafc77
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/LazyProperties.kt
@@ -0,0 +1,12 @@
+package com.android.permissioncontroller.safetycenter.ui.view
+
+import android.view.View
+
+/** Returns a lazy property wrapping a view with a given ID. */
+fun <T : View> View.lazyView(childViewId: Int): Lazy<T> = lazyView { requireViewById(childViewId) }
+
+/** Returns a lazy property wrapping a view produced by the given function. */
+fun <T> lazyView(viewProducer: () -> T): Lazy<T> =
+ // Lazy by default uses synchronization to ensure a variable is only initialized once. This
+ // is unnecessary and expensive for view properties, so we don't use synchronization here.
+ lazy(LazyThreadSafetyMode.NONE) { viewProducer() }
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt
index 264aa488e..7b95c3609 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt
@@ -43,14 +43,14 @@ constructor(
}
private val moreIssuesCardAnimator = MoreIssuesCardAnimator()
- private val statusIconView: ImageView by lazy { findViewById(R.id.status_icon) }
- private val titleView: TextView by lazy { findViewById(R.id.title) }
- private val expandCollapseLayout: View by lazy { findViewById(android.R.id.widget_frame) }
- private val counterView: TextView by lazy {
- expandCollapseLayout.findViewById(R.id.widget_title)
+ private val statusIconView: ImageView by lazyView(R.id.status_icon)
+ private val titleView: TextView by lazyView(R.id.title)
+ private val expandCollapseLayout: View by lazyView(android.R.id.widget_frame)
+ private val counterView: TextView by lazyView {
+ expandCollapseLayout.requireViewById(R.id.widget_title)
}
- private val expandCollapseIcon: ImageView by lazy {
- expandCollapseLayout.findViewById(R.id.widget_icon)
+ private val expandCollapseIcon: ImageView by lazyView {
+ expandCollapseLayout.requireViewById(R.id.widget_icon)
}
private var cornerAnimator: ValueAnimator? = null
@@ -168,6 +168,7 @@ constructor(
if (animateTextChange) {
counterView.text = previousText
+ Log.v(TAG, "Starting more issues card text animation")
moreIssuesCardAnimator.animateChangeText(counterView, newText)
} else {
counterView.text = newText
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt
index 4be327285..34565421a 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt
@@ -29,11 +29,11 @@ import com.android.permissioncontroller.safetycenter.ui.SeverityIconPicker
internal class SafetyEntryCommonViewsManager(rootEntryView: ViewGroup?) {
- val titleView: TextView? by lazy { rootEntryView?.findViewById(R.id.title) }
- val summaryView: TextView? by lazy { rootEntryView?.findViewById(R.id.summary) }
- private val iconView: ImageView? by lazy { rootEntryView?.findViewById(R.id.icon) }
- private val iconFrame: View? by lazy { rootEntryView?.findViewById(R.id.icon_frame) }
- private val emptySpace: View? by lazy { rootEntryView?.findViewById(R.id.empty_space) }
+ val titleView: TextView? by lazyView { rootEntryView?.findViewById(R.id.title) }
+ val summaryView: TextView? by lazyView { rootEntryView?.findViewById(R.id.summary) }
+ private val iconView: ImageView? by lazyView { rootEntryView?.findViewById(R.id.icon) }
+ private val iconFrame: View? by lazyView { rootEntryView?.findViewById(R.id.icon_frame) }
+ private val emptySpace: View? by lazyView { rootEntryView?.findViewById(R.id.empty_space) }
fun showDetails(
id: String,
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt
index 318ade5cb..b00b7f765 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt
@@ -51,7 +51,6 @@ constructor(
) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
private companion object {
- val TAG = SafetyEntryGroupView::class.java.simpleName
const val EXPAND_COLLAPSE_ANIMATION_DURATION_MS = 183L
}
@@ -59,20 +58,20 @@ constructor(
inflate(context, R.layout.safety_center_group, this)
}
- private val groupHeaderView: LinearLayout? by lazy { findViewById(R.id.group_header) }
+ private val groupHeaderView: LinearLayout? by lazyView(R.id.group_header)
- private val expandedHeaderView: ViewGroup? by lazy { findViewById(R.id.expanded_header) }
- private val expandedTitleView: TextView? by lazy {
+ private val expandedHeaderView: ViewGroup? by lazyView(R.id.expanded_header)
+ private val expandedTitleView: TextView? by lazyView {
expandedHeaderView?.findViewById(R.id.title)
}
- private val collapsedHeaderView: ViewGroup? by lazy { findViewById(R.id.collapsed_header) }
- private val commonEntryView: SafetyEntryCommonViewsManager? by lazy {
+ private val collapsedHeaderView: ViewGroup? by lazyView(R.id.collapsed_header)
+ private val commonEntryView: SafetyEntryCommonViewsManager? by lazyView {
SafetyEntryCommonViewsManager(collapsedHeaderView)
}
- private val chevronIconView: ImageView? by lazy { findViewById(R.id.chevron_icon) }
- private val entriesContainerView: LinearLayout? by lazy { findViewById(R.id.entries_container) }
+ private val chevronIconView: ImageView? by lazyView(R.id.chevron_icon)
+ private val entriesContainerView: LinearLayout? by lazyView(R.id.entries_container)
private var isExpanded: Boolean? = null
@@ -107,8 +106,15 @@ constructor(
val params = layoutParams as MarginLayoutParams
if (params.topMargin != topMargin) {
params.topMargin = topMargin
- layoutParams = params
}
+
+ if (isLastCard) {
+ params.bottomMargin = context.resources.getDimensionPixelSize(R.dimen.sc_spacing_large)
+ } else {
+ params.bottomMargin = 0
+ }
+
+ layoutParams = params
}
private fun showGroupDetails(group: SafetyCenterEntryGroup) {
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt
index ff7233686..7d7214ab0 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt
@@ -52,10 +52,10 @@ constructor(
inflate(context, R.layout.view_entry, this)
}
- private val commonEntryView: SafetyEntryCommonViewsManager? by lazy {
+ private val commonEntryView: SafetyEntryCommonViewsManager? by lazyView {
SafetyEntryCommonViewsManager(this)
}
- private val widgetFrame: ViewGroup? by lazy { findViewById(R.id.widget_frame) }
+ private val widgetFrame: ViewGroup? by lazyView(R.id.widget_frame)
fun showEntry(
entry: SafetyCenterEntry,
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt
index 013f32c85..6a415c563 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt
@@ -42,14 +42,12 @@ constructor(
inflate(context, R.layout.view_status_card, this)
}
- val statusImageView: ImageView by lazy { findViewById(R.id.status_image) }
- val titleAndSummaryContainerView: LinearLayout by lazy {
- findViewById(R.id.status_title_and_summary)
- }
- val titleView: TextView by lazy { findViewById(R.id.status_title) }
- val summaryView: TextView by lazy { findViewById(R.id.status_summary) }
- val reviewSettingsButton: MaterialButton by lazy { findViewById(R.id.review_settings_button) }
- val rescanButton: MaterialButton by lazy { findViewById(R.id.rescan_button) }
+ val statusImageView: ImageView by lazyView(R.id.status_image)
+ val titleAndSummaryContainerView: LinearLayout by lazyView(R.id.status_title_and_summary)
+ val titleView: TextView by lazyView(R.id.status_title)
+ val summaryView: TextView by lazyView(R.id.status_summary)
+ val reviewSettingsButton: MaterialButton by lazyView(R.id.review_settings_button)
+ val rescanButton: MaterialButton by lazyView(R.id.rescan_button)
fun showButtons(statusUiData: StatusUiData) {
rescanButton.isEnabled = !statusUiData.isRefreshInProgress
diff --git a/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt b/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt
index 26f327e96..69e696695 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt
@@ -59,7 +59,8 @@ data class AppsSafetyLabelHistory(val appSafetyLabelHistories: List<AppSafetyLab
.toMutableList()
.apply { add(safetyLabel) }
.sortedBy { it.receivedAt }
- .takeLast(maxToPersist))
+ .takeLast(maxToPersist)
+ )
}
/** Data class representing the information about an app. */
@@ -90,7 +91,8 @@ data class AppsSafetyLabelHistory(val appSafetyLabelHistories: List<AppSafetyLab
SafetyLabel(
AppInfo(packageName),
receivedAt,
- DataLabel.extractLocationSharingDataLabel(appMetadataSafetyLabel.dataLabel))
+ DataLabel.extractLocationSharingDataLabel(appMetadataSafetyLabel.dataLabel)
+ )
}
}
@@ -113,7 +115,8 @@ data class AppsSafetyLabelHistory(val appSafetyLabelHistories: List<AppSafetyLab
.filter { it.key == DataCategoryConstants.CATEGORY_LOCATION }
.mapValues { categoryEntry ->
DataCategory.fromAppMetadataDataCategory(categoryEntry.value)
- })
+ }
+ )
}
}
@@ -134,7 +137,8 @@ data class AppsSafetyLabelHistory(val appSafetyLabelHistories: List<AppSafetyLab
DataCategory(
appMetadataDataCategory.dataTypes.values.any {
it.purposeSet.contains(PURPOSE_ADVERTISING)
- })
+ }
+ )
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt b/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt
index 9bb7e819f..ce6233fdf 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt
@@ -90,10 +90,14 @@ object AppsSafetyLabelHistoryPersistence {
Log.e(LOG_TAG, "File not found: $file")
} catch (e: IOException) {
Log.e(
- LOG_TAG, "Failed to read file: $file, encountered exception ${e.localizedMessage}")
+ LOG_TAG,
+ "Failed to read file: $file, encountered exception ${e.localizedMessage}"
+ )
} catch (e: XmlPullParserException) {
Log.e(
- LOG_TAG, "Failed to parse file: $file, encountered exception ${e.localizedMessage}")
+ LOG_TAG,
+ "Failed to parse file: $file, encountered exception ${e.localizedMessage}"
+ )
}
return AppsSafetyLabelHistoryFileContent(appsSafetyLabelHistory = null, INITIAL_VERSION)
@@ -133,13 +137,15 @@ object AppsSafetyLabelHistoryPersistence {
AppsSafetyLabelHistory(
currentHistories.toMutableList().apply {
add(AppSafetyLabelHistory(appInfo, listOf(safetyLabel)))
- })
+ }
+ )
} else {
AppsSafetyLabelHistory(
currentHistories.map {
if (it.appInfo != appInfo) it
else it.addSafetyLabelIfChanged(safetyLabel)
- })
+ }
+ )
}
write(file, updatedAppsSafetyLabelHistory)
@@ -231,7 +237,9 @@ object AppsSafetyLabelHistoryPersistence {
// to startTime. The aim is retain one safety label prior to start time to
// be used as the "before" safety label when determining updates.
AppSafetyLabelHistory(
- appHistory.appInfo, history.subList(last, history.size))
+ appHistory.appInfo,
+ history.subList(last, history.size)
+ )
}
}
@@ -265,7 +273,10 @@ object AppsSafetyLabelHistoryPersistence {
listeners.forEach { it.onSafetyLabelHistoryChanged() }
} catch (e: Exception) {
Log.i(
- LOG_TAG, "Failed to write to $file. Previous version of file will be restored.", e)
+ LOG_TAG,
+ "Failed to write to $file. Previous version of file will be restored.",
+ e
+ )
atomicFile.failWrite(outputStream)
} finally {
try {
@@ -284,10 +295,12 @@ object AppsSafetyLabelHistoryPersistence {
return currentAppsSafetyLabelHistory.appSafetyLabelHistories.mapNotNull {
val before = it.getSafetyLabelAt(startTime)
val after = it.getLatestSafetyLabel()
- if (before == null ||
- after == null ||
- before == after ||
- before.receivedAt.isAfter(after.receivedAt))
+ if (
+ before == null ||
+ after == null ||
+ before == after ||
+ before.receivedAt.isAfter(after.receivedAt)
+ )
null
else AppSafetyLabelDiff(before, after)
}
@@ -332,7 +345,8 @@ object AppsSafetyLabelHistoryPersistence {
else ->
throw IllegalArgumentException(
"Unexpected attribute ${getAttributeName(i)} in tag" +
- " $TAG_APPS_SAFETY_LABEL_HISTORY")
+ " $TAG_APPS_SAFETY_LABEL_HISTORY"
+ )
}
}
if (version == null) {
@@ -350,7 +364,9 @@ object AppsSafetyLabelHistoryPersistence {
next()
return AppsSafetyLabelHistoryFileContent(
- AppsSafetyLabelHistory(appSafetyLabelHistories), version)
+ AppsSafetyLabelHistory(appSafetyLabelHistories),
+ version
+ )
}
private fun XmlPullParser.parseAppSafetyLabelHistory(): AppSafetyLabelHistory {
@@ -379,7 +395,8 @@ object AppsSafetyLabelHistoryPersistence {
ATTRIBUTE_RECEIVED_AT -> receivedAt = parseInstant(getAttributeValue(i))
else ->
throw IllegalArgumentException(
- "Unexpected attribute ${getAttributeName(i)} in tag $TAG_SAFETY_LABEL")
+ "Unexpected attribute ${getAttributeName(i)} in tag $TAG_SAFETY_LABEL"
+ )
}
}
if (receivedAt == null) {
@@ -432,7 +449,8 @@ object AppsSafetyLabelHistoryPersistence {
ATTRIBUTE_CONTAINS_ADS -> hasAds = getAttributeValue(i).toBoolean()
else ->
throw IllegalArgumentException(
- "Unexpected attribute ${getAttributeName(i)} in tag $TAG_DATA_SHARED_ENTRY")
+ "Unexpected attribute ${getAttributeName(i)} in tag $TAG_DATA_SHARED_ENTRY"
+ )
}
}
if (category == null) {
@@ -440,7 +458,8 @@ object AppsSafetyLabelHistoryPersistence {
}
if (hasAds == null) {
throw IllegalArgumentException(
- "Missing $ATTRIBUTE_CONTAINS_ADS in $TAG_DATA_SHARED_ENTRY")
+ "Missing $ATTRIBUTE_CONTAINS_ADS in $TAG_DATA_SHARED_ENTRY"
+ )
}
nextTag()
@@ -458,7 +477,8 @@ object AppsSafetyLabelHistoryPersistence {
ATTRIBUTE_PACKAGE_NAME -> packageName = getAttributeValue(i)
else ->
throw IllegalArgumentException(
- "Unexpected attribute ${getAttributeName(i)} in tag $TAG_APP_INFO")
+ "Unexpected attribute ${getAttributeName(i)} in tag $TAG_APP_INFO"
+ )
}
}
if (packageName == null) {
@@ -540,7 +560,8 @@ object AppsSafetyLabelHistoryPersistence {
attribute(
null,
ATTRIBUTE_CONTAINS_ADS,
- dataSharedEntry.value.containsAdvertisingPurpose.toString())
+ dataSharedEntry.value.containsAdvertisingPurpose.toString()
+ )
endTag(null, TAG_DATA_SHARED_ENTRY)
}
@@ -592,7 +613,10 @@ object AppsSafetyLabelHistoryPersistence {
*/
private fun getMaxSafetyLabelsToPersist() =
DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP, 20)
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP,
+ 20
+ )
/** An interface to listen to changes to persisted safety labels. */
interface ChangeListener {
diff --git a/PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt b/PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt
index 99f4adb02..7378b77fe 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt
@@ -31,6 +31,7 @@ import androidx.annotation.MainThread
import androidx.annotation.RequiresApi
import com.android.permission.safetylabel.SafetyLabel as AppMetadataSafetyLabel
import com.android.permissioncontroller.permission.data.LightPackageInfoLiveData
+import com.android.permissioncontroller.permission.data.get
import com.android.permissioncontroller.permission.data.v34.LightInstallSourceInfoLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.utils.KotlinUtils
@@ -56,8 +57,10 @@ class SafetyLabelChangedBroadcastReceiver : BroadcastReceiver() {
}
val packageChangeEvent = getPackageChangeEvent(intent)
- if (!(packageChangeEvent == PackageChangeEvent.NEW_INSTALL ||
- packageChangeEvent == PackageChangeEvent.UPDATE)) {
+ if (
+ !(packageChangeEvent == PackageChangeEvent.NEW_INSTALL ||
+ packageChangeEvent == PackageChangeEvent.UPDATE)
+ ) {
return
}
@@ -74,7 +77,8 @@ class SafetyLabelChangedBroadcastReceiver : BroadcastReceiver() {
"received broadcast packageName: $packageName, current user: $currentUser," +
" packageChangeEvent: $packageChangeEvent, intent user:" +
" ${intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle::class.java)
- ?: currentUser}")
+ ?: currentUser}"
+ )
}
val userManager = Utils.getSystemServiceSafe(context, UserManager::class.java)
if (userManager.isProfile) {
@@ -127,7 +131,8 @@ class SafetyLabelChangedBroadcastReceiver : BroadcastReceiver() {
Log.i(
TAG,
"writeSafetyLabel called for packageName: $packageName, currentUser:" +
- " ${Process.myUserHandle()}")
+ " ${Process.myUserHandle()}"
+ )
}
// Get the context for the user in which the app is installed.
@@ -155,7 +160,10 @@ class SafetyLabelChangedBroadcastReceiver : BroadcastReceiver() {
val safetyLabelForPersistence: SafetyLabelForPersistence =
AppsSafetyLabelHistory.SafetyLabel.extractLocationSharingSafetyLabel(
- packageName, Instant.ofEpochMilli(receivedAtMs), safetyLabel)
+ packageName,
+ Instant.ofEpochMilli(receivedAtMs),
+ safetyLabel
+ )
val historyFile = AppsSafetyLabelHistoryPersistence.getSafetyLabelHistoryFile(context)
AppsSafetyLabelHistoryPersistence.recordSafetyLabel(safetyLabelForPersistence, historyFile)
@@ -212,12 +220,14 @@ class SafetyLabelChangedBroadcastReceiver : BroadcastReceiver() {
Log.i(
TAG,
"Forwarding intent from current user: $currentUser to profile parent" +
- " $profileParent")
+ " $profileParent"
+ )
context.sendBroadcastAsUser(
Intent(intent)
.setAction(ACTION_PACKAGE_ADDED_PERMISSIONCONTROLLER_FORWARDED)
.putExtra(Intent.EXTRA_USER, currentUser),
- profileParent)
+ profileParent
+ )
}
/** Types of package change events. */
diff --git a/PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING
index b6e659353..1503c5e57 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING
@@ -11,17 +11,40 @@
],
"presubmit-large": [
{
- "name": "CtsPermission3TestCases",
+ "name": "CtsPermissionUiTestCases",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
],
"mainline-presubmit": [
{
- "name": "CtsPermission3TestCases[com.google.android.permission.apex]"
+ "name": "CtsPermissionUiTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "PermissionControllerMockingTests",
+ "options": [
+ {
+ "include-filter": "com.android.permissioncontroller.tests.mocking.safetylabel"
+ }
+ ]
+ },
+ {
+ "name": "CtsPermissionUiTestCases"
+ }
+ ],
+ "mainline-postsubmit": [
+ {
+ "name": "CtsPermissionUiTestCases[com.google.android.permission.apex]"
}
]
} \ No newline at end of file
diff --git a/PermissionController/tests/inprocess/Android.bp b/PermissionController/tests/inprocess/Android.bp
index 78c767f1d..7d55ff9cc 100644
--- a/PermissionController/tests/inprocess/Android.bp
+++ b/PermissionController/tests/inprocess/Android.bp
@@ -33,10 +33,7 @@ android_test {
target_sdk_version: "30",
min_sdk_version: "30",
- srcs: [
- "src/**/*.kt",
- "src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java",
- ],
+ srcs: ["src/**/*.kt"],
libs: [
"android.test.base",
diff --git a/PermissionController/tests/inprocess/AndroidTest.xml b/PermissionController/tests/inprocess/AndroidTest.xml
index 8971a7270..e09fe556b 100644
--- a/PermissionController/tests/inprocess/AndroidTest.xml
+++ b/PermissionController/tests/inprocess/AndroidTest.xml
@@ -30,14 +30,14 @@
<!-- Create place to store apks -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="mkdir -p /data/local/tmp/permissioncontroller/tests/inprocess" />
- <option name="teardown-command" value="rm -rf /data/local/tmp/permissioncontroller/"/>
+ <option name="run-command" value="mkdir -p /data/local/tmp/pc-inprocess" />
+ <option name="teardown-command" value="rm -fr /data/local/tmp/pc-inprocess"/>
</target_preparer>
<!-- Load additional APKs onto device -->
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="push-file" key="AppThatUsesCameraPermission.apk"
- value="/data/local/tmp/permissioncontroller/tests/inprocess/AppThatUsesCameraPermission.apk" />
+ value="/data/local/tmp/pc-inprocess/AppThatUsesCameraPermission.apk" />
</target_preparer>
<!-- Uninstall test-apps -->
diff --git a/PermissionController/tests/inprocess/AppThatUsesCameraPermission/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt b/PermissionController/tests/inprocess/AppThatUsesCameraPermission/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt
index 2a4900ce4..58f0a8968 100644
--- a/PermissionController/tests/inprocess/AppThatUsesCameraPermission/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt
+++ b/PermissionController/tests/inprocess/AppThatUsesCameraPermission/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt
@@ -18,5 +18,4 @@ package com.android.permissioncontroller.tests.appthatrequestpermission
import android.app.Activity
-class DummyActivity : Activity() {
-} \ No newline at end of file
+class DummyActivity : Activity() {}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/GetPermissionGroupInfoTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/GetPermissionGroupInfoTest.kt
index 1dd13be2a..b20e99c38 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/GetPermissionGroupInfoTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/GetPermissionGroupInfoTest.kt
@@ -22,9 +22,9 @@ import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.google.common.truth.Truth.assertThat
-import org.junit.Test
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
+import org.junit.Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
class GetPermissionGroupInfoTest {
@@ -43,8 +43,8 @@ class GetPermissionGroupInfoTest {
latch.countDown()
}
latch.await(timeoutMs, TimeUnit.MILLISECONDS)
- assertThat(returnedPerms).isEqualTo(
- PermissionMapping.getPlatformPermissionNamesOfGroup(group))
+ assertThat(returnedPerms)
+ .isEqualTo(PermissionMapping.getPlatformPermissionNamesOfGroup(group))
}
}
@@ -61,8 +61,8 @@ class GetPermissionGroupInfoTest {
latch.countDown()
}
latch.await(timeoutMs, TimeUnit.MILLISECONDS)
- assertThat(permGroup).isEqualTo(
- PermissionMapping.getGroupOfPlatformPermission(permName))
+ assertThat(permGroup)
+ .isEqualTo(PermissionMapping.getGroupOfPlatformPermission(permName))
}
}
}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java
deleted file mode 100644
index b4b18dbbe..000000000
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2023 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.permission.compat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.SystemClock;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.Spanned;
-import android.text.method.MovementMethod;
-import android.text.style.ClickableSpan;
-import android.util.TypedValue;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-/**
- * Test for {@link LinkMovementMethodCompat} without using Mockito, which is unavailable for
- * in-process tests.
- *
- * @see android.text.method.cts.LinkMovementMethodTest
- */
-public class LinkMovementMethodCompatTest {
- private static final String CONTENT = "clickable\nunclickable\nclickable";
-
- private Activity mActivity;
- private LinkMovementMethodCompat mMethod;
- private TextView mView;
- private Spannable mSpannable;
- private MockClickableSpan mClickable0;
- private MockClickableSpan mClickable1;
-
- @Rule
- public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
-
- @Before
- public void setup() throws Throwable {
- mActivity = mActivityRule.getActivity();
- mMethod = new LinkMovementMethodCompat();
-
- // Set the content view with a text view which contains 3 lines,
- mActivityRule.runOnUiThread(() -> mView = new TextViewNoIme(mActivity));
- mView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
- mView.setText(CONTENT, TextView.BufferType.SPANNABLE);
-
- mActivityRule.runOnUiThread(() -> mActivity.setContentView(mView));
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
- mSpannable = (Spannable) mView.getText();
- // make first line clickable
- mClickable0 = markClickable(0, CONTENT.indexOf('\n'));
- // make last line clickable
- mClickable1 = markClickable(CONTENT.lastIndexOf('\n'), CONTENT.length());
- }
-
- @Test
- public void testConstructor() {
- new LinkMovementMethodCompat();
- }
-
- @Test
- public void testGetInstance() {
- MovementMethod method0 = LinkMovementMethodCompat.getInstance();
- assertTrue(method0 instanceof LinkMovementMethodCompat);
-
- MovementMethod method1 = LinkMovementMethodCompat.getInstance();
- assertNotNull(method1);
- assertSame(method0, method1);
- }
-
- @UiThreadTest
- @Test
- public void testOnTouchEvent() {
- assertSelection(mSpannable, -1);
-
- // press on first line (Clickable)
- assertTrue(pressOnLine(0));
- assertSelectClickableLeftToRight(mSpannable, mClickable0);
-
- // release on first line
- mClickable0.clearClickCount();
- assertTrue(releaseOnLine(0));
- mClickable0.assertClickCount(1);
-
- // press on second line (unclickable)
- assertSelectClickableLeftToRight(mSpannable, mClickable0);
- // just clear selection
- pressOnLine(1);
- assertSelection(mSpannable, -1);
-
- // press on last line (Clickable)
- assertTrue(pressOnLine(2));
- assertSelectClickableLeftToRight(mSpannable, mClickable1);
-
- // release on last line
- mClickable1.clearClickCount();
- assertTrue(releaseOnLine(2));
- mClickable1.assertClickCount(1);
-
- // release on second line (unclickable)
- assertSelectClickableLeftToRight(mSpannable, mClickable1);
- // just clear selection
- releaseOnLine(1);
- assertSelection(mSpannable, -1);
- }
-
- @UiThreadTest
- @Test
- public void testOnTouchEvent_outsideLineBounds() {
- assertSelection(mSpannable, -1);
-
- // press on first line (clickable)
- assertTrue(pressOnLine(0));
- assertSelectClickableLeftToRight(mSpannable, mClickable0);
-
- // release above first line
- mClickable0.clearClickCount();
- float x = (mView.getLayout().getLineLeft(0) + mView.getLayout().getLineRight(0)) / 2f;
- float y = -1f;
- assertFalse(performMotionAtPoint(x, y, MotionEvent.ACTION_UP));
- mClickable0.assertClickCount(0);
-
- // press on first line (clickable)
- assertTrue(pressOnLine(0));
- assertSelectClickableLeftToRight(mSpannable, mClickable0);
-
- // release to left of first line
- mClickable0.clearClickCount();
- x = mView.getLayout().getLineLeft(0) - 1f;
- y = (mView.getLayout().getLineTop(0) + mView.getLayout().getLineBottom(0)) / 2f;
- assertFalse(performMotionAtPoint(x, y, MotionEvent.ACTION_UP));
- mClickable0.assertClickCount(0);
-
- // press on first line (clickable)
- assertTrue(pressOnLine(0));
- assertSelectClickableLeftToRight(mSpannable, mClickable0);
-
- // release to right of first line
- mClickable0.clearClickCount();
- x = mView.getLayout().getLineRight(0) + 1f;
- y = (mView.getLayout().getLineTop(0) + mView.getLayout().getLineBottom(0)) / 2f;
- assertFalse(performMotionAtPoint(x, y, MotionEvent.ACTION_UP));
- mClickable0.assertClickCount(0);
-
- // press on last line (clickable)
- assertTrue(pressOnLine(2));
- assertSelectClickableLeftToRight(mSpannable, mClickable1);
-
- // release below last line
- mClickable1.clearClickCount();
- x = (mView.getLayout().getLineLeft(0) + mView.getLayout().getLineRight(0)) / 2f;
- y = mView.getLayout().getHeight() + 1f;
- assertFalse(performMotionAtPoint(x, y, MotionEvent.ACTION_UP));
- mClickable1.assertClickCount(0);
- }
-
- private MockClickableSpan markClickable(final int start, final int end) throws Throwable {
- final MockClickableSpan clickableSpan = new MockClickableSpan();
- mActivityRule.runOnUiThread(() -> mSpannable.setSpan(clickableSpan, start, end,
- Spanned.SPAN_MARK_MARK));
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
- return clickableSpan;
- }
- private boolean performMotionAtPoint(float x, float y, int action) {
- long now = SystemClock.uptimeMillis();
- return mMethod.onTouchEvent(mView, mSpannable,
- MotionEvent.obtain(now, now, action, x, y, 0));
- }
-
- private boolean performMotionOnLine(int line, int action) {
- float x = (mView.getLayout().getLineLeft(line) + mView.getLayout().getLineRight(line)) / 2f;
- float y = (mView.getLayout().getLineTop(line) + mView.getLayout().getLineBottom(line)) / 2f;
- return performMotionAtPoint(x, y, action);
- }
-
- private boolean pressOnLine(int line) {
- return performMotionOnLine(line, MotionEvent.ACTION_DOWN);
- }
-
- private boolean releaseOnLine(int line) {
- return performMotionOnLine(line, MotionEvent.ACTION_UP);
- }
-
- private void assertSelection(Spannable spannable, int start, int end) {
- assertEquals(start, Selection.getSelectionStart(spannable));
- assertEquals(end, Selection.getSelectionEnd(spannable));
- }
-
- private void assertSelection(Spannable spannable, int position) {
- assertSelection(spannable, position, position);
- }
-
- private void assertSelectClickableLeftToRight(Spannable spannable,
- ClickableSpan clickableSpan) {
- assertSelection(spannable, spannable.getSpanStart(clickableSpan),
- spannable.getSpanEnd(clickableSpan));
- }
-
- public static class TextViewNoIme extends TextView {
- public TextViewNoIme(@NonNull Context context) {
- super(context);
- }
-
- @Override
- public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
- return null;
- }
- }
-
- public static class MockClickableSpan extends ClickableSpan {
- private int mClickCount = 0;
-
- @Override
- public void onClick(@NonNull View widget) {
- ++mClickCount;
- }
-
- public void assertClickCount(int expectedClickCount) {
- assertEquals(expectedClickCount, mClickCount);
- }
-
- public void clearClickCount() {
- mClickCount = 0;
- }
- }
-}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveDataTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveDataTest.kt
index 24ea039a1..bc9e5d6ff 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveDataTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/AttributionLabelLiveDataTest.kt
@@ -28,8 +28,7 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
-private const val APK =
- "/data/local/tmp/permissioncontroller/tests/inprocess/AppThatUsesCameraPermission.apk"
+private const val APK = "/data/local/tmp/pc-inprocess/AppThatUsesCameraPermission.apk"
private const val PKG = "com.android.permissioncontroller.tests.appthatrequestpermission"
class AttributionLabelLiveDataTest {
@@ -43,8 +42,8 @@ class AttributionLabelLiveDataTest {
@Test
fun getValidTag() {
AttributionLabelLiveData["testTag", PKG, myUserHandle()].withLoadedValue {
- assertThat(context.packageManager.getResourcesForApplication(PKG)
- .getString(it!!)).isEqualTo("Test Attribution Label")
+ assertThat(context.packageManager.getResourcesForApplication(PKG).getString(it!!))
+ .isEqualTo("Test Attribution Label")
}
}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/DataUtils.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/DataUtils.kt
index 519a7ef64..b34c151c3 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/DataUtils.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/data/DataUtils.kt
@@ -23,11 +23,12 @@ import java.util.concurrent.CompletableFuture
fun <T> SmartUpdateMediatorLiveData<T>.withLoadedValue(block: (T?) -> Unit) {
val v = CompletableFuture<T?>()
- val observer = Observer<T?> {
- if (isInitialized) {
- v.complete(it)
+ val observer =
+ Observer<T?> {
+ if (isInitialized) {
+ v.complete(it)
+ }
}
- }
Handler(Looper.getMainLooper()).post { observeForever(observer) }
try {
@@ -35,4 +36,4 @@ fun <T> SmartUpdateMediatorLiveData<T>.withLoadedValue(block: (T?) -> Unit) {
} finally {
Handler(Looper.getMainLooper()).post { removeObserver(observer) }
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt
index 305dcdfb7..708d4222f 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt
@@ -23,8 +23,7 @@ import org.junit.Test
class ArrayUtilsTest {
@Test
fun appendString_appendToNull_returnsArrayWithString() {
- assertThat(ArrayUtils.appendString(null, TEST_STRING))
- .isEqualTo(arrayOf(TEST_STRING))
+ assertThat(ArrayUtils.appendString(null, TEST_STRING)).isEqualTo(arrayOf(TEST_STRING))
}
@Test
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt
index 8f54da579..37aa8d988 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt
@@ -34,18 +34,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.argThat
import org.mockito.Mockito.mock
-import kotlin.test.assertFailsWith
import org.mockito.Mockito.`when` as whenever
-/**
- * Unit tests for [KotlinUtils].
- */
+/** Unit tests for [KotlinUtils]. */
@RunWith(AndroidJUnit4::class)
class KotlinUtilsTest {
private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext
@@ -85,19 +83,25 @@ class KotlinUtilsTest {
whenever(mockContext.packageManager).thenReturn(mockPackageManager)
val installerIntent = Intent(ACTION_SHOW_APP_INFO).setPackage(installerPackage)
whenever(
- mockPackageManager.resolveActivity(
- argThat { intent -> intent.filterEquals(installerIntent) }, /* flags= */ anyInt()))
- .thenReturn(ResolveInfo().apply {
- activityInfo = ActivityInfo().apply {
- packageName = installerPackage
- name = installerActivity
+ mockPackageManager.resolveActivity(
+ argThat { intent -> intent.filterEquals(installerIntent) },
+ /* flags= */ anyInt()
+ )
+ )
+ .thenReturn(
+ ResolveInfo().apply {
+ activityInfo =
+ ActivityInfo().apply {
+ packageName = installerPackage
+ name = installerActivity
+ }
}
- })
+ )
val intent = KotlinUtils.getAppStoreIntent(mockContext, installerPackage, appPackage)
assertThat(intent).isNotNull()
- with (intent!!) {
+ with(intent!!) {
assertThat(action).isEqualTo(ACTION_SHOW_APP_INFO)
assertThat(component?.packageName).isEqualTo(installerPackage)
assertThat(component?.className).isEqualTo(installerActivity)
@@ -110,14 +114,16 @@ class KotlinUtilsTest {
val mockContext = mock(Context::class.java)
val mockPackageManager = mock(PackageManager::class.java)
whenever(mockContext.packageManager).thenReturn(mockPackageManager)
- whenever(
- mockPackageManager.resolveActivity(any(), /* flags= */ anyInt()))
- .thenReturn(ResolveInfo().apply {
- activityInfo = ActivityInfo().apply {
- packageName = ""
- name = ""
+ whenever(mockPackageManager.resolveActivity(any(), /* flags= */ anyInt()))
+ .thenReturn(
+ ResolveInfo().apply {
+ activityInfo =
+ ActivityInfo().apply {
+ packageName = ""
+ name = ""
+ }
}
- })
+ )
val intent = KotlinUtils.getAppStoreIntent(mockContext, "com.installer", appPackage)
@@ -149,7 +155,8 @@ class KotlinUtilsTest {
@Test
fun getMimeTypeForPermissions_bothReadMediaPermissions_returnsNull() {
assertThat(
- KotlinUtils.getMimeTypeForPermissions(listOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO)))
+ KotlinUtils.getMimeTypeForPermissions(listOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO))
+ )
.isNull()
}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt
index 64a13df60..4d942f815 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt
@@ -29,31 +29,41 @@ import org.junit.runner.RunWith
class PermissionMappingTest {
@Test
fun testGetPlatformPermissionGroupForOp_healthPermissionGroup() {
- assertThat(PermissionMapping.getPlatformPermissionGroupForOp(
- AppOpsManager.OPSTR_READ_WRITE_HEALTH_DATA
- )).isEqualTo(HealthPermissions.HEALTH_PERMISSION_GROUP)
+ assertThat(
+ PermissionMapping.getPlatformPermissionGroupForOp(
+ AppOpsManager.OPSTR_READ_WRITE_HEALTH_DATA
+ )
+ )
+ .isEqualTo(HealthPermissions.HEALTH_PERMISSION_GROUP)
}
@Test
fun testGetPlatformPermissionGroupForOp_microphone() {
- assertThat(PermissionMapping.getPlatformPermissionGroupForOp(
- AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE
- )).isEqualTo(Manifest.permission_group.MICROPHONE)
+ assertThat(
+ PermissionMapping.getPlatformPermissionGroupForOp(
+ AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE
+ )
+ )
+ .isEqualTo(Manifest.permission_group.MICROPHONE)
}
@Test
fun testGetPlatformPermissionGroupForOp_camera() {
assertThat(
- PermissionMapping.getPlatformPermissionGroupForOp(AppOpsManager.OPSTR_PHONE_CALL_CAMERA)
- ).isEqualTo(Manifest.permission_group.CAMERA)
+ PermissionMapping.getPlatformPermissionGroupForOp(
+ AppOpsManager.OPSTR_PHONE_CALL_CAMERA
+ )
+ )
+ .isEqualTo(Manifest.permission_group.CAMERA)
}
@Test
fun testGetPlatformPermissionGroupForOp_readContacts() {
assertThat(
- PermissionMapping.getPlatformPermissionGroupForOp(AppOpsManager.OPSTR_READ_CONTACTS)
- ).isEqualTo(
- PermissionMapping.getGroupOfPlatformPermission(Manifest.permission.READ_CONTACTS)
- )
+ PermissionMapping.getPlatformPermissionGroupForOp(AppOpsManager.OPSTR_READ_CONTACTS)
+ )
+ .isEqualTo(
+ PermissionMapping.getGroupOfPlatformPermission(Manifest.permission.READ_CONTACTS)
+ )
}
}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
index 15218024e..11bcca356 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
@@ -45,9 +45,9 @@ import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.privacysources.WorkPolicyInfo
import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
import org.junit.Ignore
import org.junit.Test
-import kotlin.test.assertFailsWith
class UtilsTest {
private val context = InstrumentationRegistry.getInstrumentation().targetContext as Context
@@ -110,8 +110,14 @@ class UtilsTest {
@Test
@Ignore("b/277782895")
fun getEnterpriseString() {
- assertThat(Utils.getEnterpriseString(context, WorkPolicyInfo.WORK_POLICY_TITLE,
- R.string.work_policy_title)).isInstanceOf(String::class.java)
+ assertThat(
+ Utils.getEnterpriseString(
+ context,
+ WorkPolicyInfo.WORK_POLICY_TITLE,
+ R.string.work_policy_title
+ )
+ )
+ .isInstanceOf(String::class.java)
}
@Test
@@ -148,12 +154,26 @@ class UtilsTest {
@Test
fun getPermissionGroupDescriptionString_validPermissionGroup() {
- val permissionGroupNames = listOf(ACTIVITY_RECOGNITION, CALENDAR, CALL_LOG,
- CAMERA, CONTACTS, LOCATION, MICROPHONE, NEARBY_DEVICES, PHONE, READ_MEDIA_AURAL,
- READ_MEDIA_VISUAL, SENSORS, SMS, STORAGE)
+ val permissionGroupNames =
+ listOf(
+ ACTIVITY_RECOGNITION,
+ CALENDAR,
+ CALL_LOG,
+ CAMERA,
+ CONTACTS,
+ LOCATION,
+ MICROPHONE,
+ NEARBY_DEVICES,
+ PHONE,
+ READ_MEDIA_AURAL,
+ READ_MEDIA_VISUAL,
+ SENSORS,
+ SMS,
+ STORAGE
+ )
for (permissionGroupName in permissionGroupNames) {
assertThat(Utils.getPermissionGroupDescriptionString(context, permissionGroupName, ""))
- .isNotNull()
+ .isNotNull()
}
}
@@ -167,8 +187,12 @@ class UtilsTest {
@Test
fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsToday() {
- val result = Utils.getPermissionLastAccessSummaryTimestamp(System.currentTimeMillis(),
- context, LOCATION)
+ val result =
+ Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis(),
+ context,
+ LOCATION
+ )
assertThat(result.first).isNotEmpty()
assertThat(result.second).isEqualTo(Utils.LAST_24H_SENSOR_TODAY)
assertThat(result.third).isNotEmpty()
@@ -176,8 +200,12 @@ class UtilsTest {
@Test
fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsYesterday() {
- val result = Utils.getPermissionLastAccessSummaryTimestamp(
- System.currentTimeMillis() - 24 * 60 * 60 * 1000, context, LOCATION)
+ val result =
+ Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis() - 24 * 60 * 60 * 1000,
+ context,
+ LOCATION
+ )
assertThat(result.first).isNotEmpty()
assertThat(result.second).isEqualTo(Utils.LAST_24H_SENSOR_YESTERDAY)
assertThat(result.third).isNotEmpty()
@@ -185,8 +213,12 @@ class UtilsTest {
@Test
fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsLast7Days() {
- val result = Utils.getPermissionLastAccessSummaryTimestamp(
- System.currentTimeMillis() - 5 * 24 * 60 * 60 * 1000, context, LOCATION)
+ val result =
+ Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis() - 5 * 24 * 60 * 60 * 1000,
+ context,
+ LOCATION
+ )
assertThat(result.first).isNotEmpty()
assertThat(result.second).isEqualTo(Utils.LAST_7D_SENSOR)
assertThat(result.third).isNotEmpty()
@@ -194,8 +226,12 @@ class UtilsTest {
@Test
fun getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIsLast24Hrs() {
- val result = Utils.getPermissionLastAccessSummaryTimestamp(
- System.currentTimeMillis(), context, STORAGE)
+ val result =
+ Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis(),
+ context,
+ STORAGE
+ )
assertThat(result.first).isNotEmpty()
assertThat(result.second).isEqualTo(Utils.LAST_24H_CONTENT_PROVIDER)
assertThat(result.third).isNotEmpty()
@@ -203,8 +239,12 @@ class UtilsTest {
@Test
fun getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIs7Days() {
- val result = Utils.getPermissionLastAccessSummaryTimestamp(
- System.currentTimeMillis() - 5 * 60 * 60 * 24 * 1000, context, STORAGE)
+ val result =
+ Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis() - 5 * 60 * 60 * 24 * 1000,
+ context,
+ STORAGE
+ )
assertThat(result.first).isNotEmpty()
assertThat(result.second).isEqualTo(Utils.LAST_7D_CONTENT_PROVIDER)
assertThat(result.third).isNotEmpty()
diff --git a/PermissionController/tests/mocking/Android.bp b/PermissionController/tests/mocking/Android.bp
index 0c7c3e675..416e14847 100644
--- a/PermissionController/tests/mocking/Android.bp
+++ b/PermissionController/tests/mocking/Android.bp
@@ -33,13 +33,10 @@ android_test {
min_sdk_version: "30",
resource_dirs: [
- "main_res",
"test_res",
],
srcs: [
- ":permissioncontroller-sources",
-
"src/**/*.kt",
],
@@ -50,9 +47,14 @@ android_test {
],
static_libs: [
+ "PermissionController-lib",
"iconloader_sc_mainline_prod",
"com.google.android.material_material",
"androidx.transition_transition",
+ "androidx.compose.foundation_foundation",
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.runtime_runtime-livedata",
+ "androidx.compose.ui_ui",
"androidx-constraintlayout_constraintlayout",
"androidx.core_core",
"androidx.media_media",
@@ -67,6 +69,7 @@ android_test {
"androidx.leanback_leanback-preference",
"androidx.lifecycle_lifecycle-extensions",
"androidx.lifecycle_lifecycle-common-java8",
+ "androidx.wear.compose_compose-material",
"kotlin-stdlib",
"kotlinx-coroutines-android",
"androidx.navigation_navigation-common-ktx",
@@ -113,6 +116,8 @@ android_test {
"safety-label",
"role-controller",
"lottie",
+ "permissions-flags-lib",
+ "android.permission.flags-aconfig-java",
"androidx.test.rules",
"androidx.test.ext.truth",
@@ -121,19 +126,12 @@ android_test {
"mockito-target-extended-minus-junit4",
],
- proto: {
- type: "lite",
- include_dirs: ["packages/modules/Permission/PermissionController/src/com/android/permissioncontroller"],
- },
-
jni_libs: [
"libdexmakerjvmtiagent",
"libstaticjvmtiagent",
],
compile_multilib: "both",
- aaptflags: ["--custom-package com.android.permissioncontroller"],
-
test_suites: [
"device-tests",
"mts-permission",
diff --git a/PermissionController/tests/mocking/main_res b/PermissionController/tests/mocking/main_res
deleted file mode 120000
index 8f3459f94..000000000
--- a/PermissionController/tests/mocking/main_res
+++ /dev/null
@@ -1 +0,0 @@
-../../res \ No newline at end of file
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationControllerTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationControllerTest.kt
index e4cc110f0..3de8630bd 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationControllerTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationControllerTest.kt
@@ -31,6 +31,7 @@ import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.hibernation.v31.HibernationController
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
+import com.android.permissioncontroller.permission.utils.ContextCompat
import java.io.File
import org.junit.After
import org.junit.Assert.assertTrue
@@ -49,9 +50,7 @@ import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-/**
- * Unit tests for [HibernationController].
- */
+/** Unit tests for [HibernationController]. */
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
class HibernationControllerTest {
@@ -68,12 +67,9 @@ class HibernationControllerTest {
private var mockitoSession: MockitoSession? = null
- @Mock
- lateinit var context: Context
- @Mock
- lateinit var appHibernationManager: AppHibernationManager
- @Mock
- lateinit var usageStatsManager: UsageStatsManager
+ @Mock lateinit var context: Context
+ @Mock lateinit var appHibernationManager: AppHibernationManager
+ @Mock lateinit var usageStatsManager: UsageStatsManager
lateinit var filesDir: File
@@ -82,8 +78,11 @@ class HibernationControllerTest {
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- mockitoSession = mockitoSession().mockStatic(PermissionControllerApplication::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
whenever(PermissionControllerApplication.get()).thenReturn(application)
filesDir = InstrumentationRegistry.getInstrumentation().getTargetContext().getCacheDir()
whenever(application.filesDir).thenReturn(filesDir)
@@ -92,8 +91,8 @@ class HibernationControllerTest {
doReturn(appHibernationManager).`when`(context).getSystemService(APP_HIBERNATION_SERVICE)
doReturn(usageStatsManager).`when`(context).getSystemService(USAGE_STATS_SERVICE)
- hibernationController = HibernationController(
- context, TEST_UNUSED_THRESHOLD, true /* targetsPreS */)
+ hibernationController =
+ HibernationController(context, TEST_UNUSED_THRESHOLD, true /* targetsPreS */)
}
@After
@@ -123,8 +122,8 @@ class HibernationControllerTest {
// GIVEN an app that is globally unused (i.e. unused at a package level)
val userPackages = listOf(makePackageInfo(PACKAGE_NAME_1), makePackageInfo(PACKAGE_NAME_2))
val map = mapOf(UserHandle.of(USER_ID) to userPackages)
- whenever(usageStatsManager.getLastTimeAnyComponentUsed(PACKAGE_NAME_1)).thenReturn(
- System.currentTimeMillis() - (TEST_UNUSED_THRESHOLD + TEST_MOCK_DELAY))
+ whenever(usageStatsManager.getLastTimeAnyComponentUsed(PACKAGE_NAME_1))
+ .thenReturn(System.currentTimeMillis() - (TEST_UNUSED_THRESHOLD + TEST_MOCK_DELAY))
// WHEN the controller hibernates the apps
hibernationController.hibernateApps(map)
@@ -138,8 +137,8 @@ class HibernationControllerTest {
// GIVEN an app that has been used globally (i.e. used at a package level)
val userPackages = listOf(makePackageInfo(PACKAGE_NAME_1), makePackageInfo(PACKAGE_NAME_2))
val map = mapOf(UserHandle.of(USER_ID) to userPackages)
- whenever(usageStatsManager.getLastTimeAnyComponentUsed(PACKAGE_NAME_1)).thenReturn(
- System.currentTimeMillis() - (TEST_UNUSED_THRESHOLD - TEST_MOCK_DELAY))
+ whenever(usageStatsManager.getLastTimeAnyComponentUsed(PACKAGE_NAME_1))
+ .thenReturn(System.currentTimeMillis() - (TEST_UNUSED_THRESHOLD - TEST_MOCK_DELAY))
// WHEN the controller hibernates the apps
hibernationController.hibernateApps(map)
@@ -162,6 +161,8 @@ class HibernationControllerTest {
0 /* firstInstallTime */,
0 /* lastUpdateTime */,
false /* areAttributionsUserVisible */,
- emptyMap() /* attributionTagsToLabels */)
+ emptyMap() /* attributionTagsToLabels */,
+ ContextCompat.DEVICE_ID_DEFAULT
+ )
}
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt
index fadd35f82..d85cb40b0 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt
@@ -53,9 +53,7 @@ import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-/**
- * Unit tests for [HibernationPolicy].
- */
+/** Unit tests for [HibernationPolicy]. */
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
class HibernationPolicyTest {
@@ -77,10 +75,12 @@ class HibernationPolicyTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(DeviceConfig::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
`when`(PermissionControllerApplication.get()).thenReturn(application)
realContext = ApplicationProvider.getApplicationContext()
@@ -109,12 +109,14 @@ class HibernationPolicyTest {
fun onReceive_shouldInitializeAndAdjustStartTimeOfUnusedAppTracking() {
receiver.onReceive(context, Intent(Intent.ACTION_BOOT_COMPLETED))
val startTimeOfUnusedAppTracking =
- sharedPreferences.getLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
- SNAPSHOT_UNINITIALIZED)
+ sharedPreferences.getLong(
+ PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
+ SNAPSHOT_UNINITIALIZED
+ )
val systemTimeSnapshot =
- sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
- val realtimeSnapshot = sharedPreferences.getLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT,
- SNAPSHOT_UNINITIALIZED)
+ sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
+ val realtimeSnapshot =
+ sharedPreferences.getLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
val currentTimeMillis = System.currentTimeMillis()
val currentRealTime = SystemClock.elapsedRealtime()
assertThat(startTimeOfUnusedAppTracking).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
@@ -134,30 +136,28 @@ class HibernationPolicyTest {
@Test
fun getStartTimeOfUnusedAppTracking_shouldReturnExpectedValue() {
assertThat(getStartTimeOfUnusedAppTracking(sharedPreferences))
- .isNotEqualTo(SNAPSHOT_UNINITIALIZED)
+ .isNotEqualTo(SNAPSHOT_UNINITIALIZED)
receiver.onReceive(context, Intent(Intent.ACTION_BOOT_COMPLETED))
- val systemTimeSnapshot = sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT,
- SNAPSHOT_UNINITIALIZED)
+ val systemTimeSnapshot =
+ sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
sharedPreferences
- .edit()
- .putLong(PREF_KEY_BOOT_TIME_SNAPSHOT, systemTimeSnapshot - ONE_DAY_MS)
- .apply()
+ .edit()
+ .putLong(PREF_KEY_BOOT_TIME_SNAPSHOT, systemTimeSnapshot - ONE_DAY_MS)
+ .apply()
assertThat(getStartTimeOfUnusedAppTracking(sharedPreferences))
- .isNotEqualTo(systemTimeSnapshot)
+ .isNotEqualTo(systemTimeSnapshot)
}
- private fun assertAdjustedTime(
- systemTimeSnapshot: Long,
- realtimeSnapshot: Long
- ) {
+ private fun assertAdjustedTime(systemTimeSnapshot: Long, realtimeSnapshot: Long) {
val newStartTimeOfUnusedAppTracking =
- sharedPreferences.getLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
- SNAPSHOT_UNINITIALIZED)
+ sharedPreferences.getLong(
+ PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
+ SNAPSHOT_UNINITIALIZED
+ )
val newSystemTimeSnapshot =
- sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
+ sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
val newRealtimeSnapshot =
- sharedPreferences.getLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT,
- SNAPSHOT_UNINITIALIZED)
+ sharedPreferences.getLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
assertThat(newStartTimeOfUnusedAppTracking).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
assertThat(newSystemTimeSnapshot).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
assertThat(newSystemTimeSnapshot).isGreaterThan(systemTimeSnapshot)
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/FakeEventStorage.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/FakeEventStorage.kt
index de43bd2d5..057af89d1 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/FakeEventStorage.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/FakeEventStorage.kt
@@ -19,9 +19,7 @@ package com.android.permissioncontroller.tests.mocking.permission.data
import com.android.permissioncontroller.permission.data.PermissionEvent
import com.android.permissioncontroller.permission.service.PermissionEventStorage
-/**
- * Fake event storage class used for tests
- */
+/** Fake event storage class used for tests */
class FakeEventStorage<T : PermissionEvent> : PermissionEventStorage<T> {
val events: MutableList<T> = mutableListOf()
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/RecentPermissionDecisionsLiveDataTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/RecentPermissionDecisionsLiveDataTest.kt
index 43d599871..b6d63ecb0 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/RecentPermissionDecisionsLiveDataTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/RecentPermissionDecisionsLiveDataTest.kt
@@ -28,19 +28,17 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@RunWith(AndroidJUnit4::class)
class RecentPermissionDecisionsLiveDataTest {
- @Mock
- lateinit var job: Job
+ @Mock lateinit var job: Job
- @Mock
- lateinit var recentDecision: PermissionDecision
+ @Mock lateinit var recentDecision: PermissionDecision
private val recentPermissionDecisionStorage = FakeEventStorage<PermissionDecision>()
@@ -49,11 +47,9 @@ class RecentPermissionDecisionsLiveDataTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- runBlocking {
- recentPermissionDecisionStorage.storeEvent(recentDecision)
- }
- recentPermissionDecisionsLiveData = spy(RecentPermissionDecisionsLiveData(
- recentPermissionDecisionStorage))
+ runBlocking { recentPermissionDecisionStorage.storeEvent(recentDecision) }
+ recentPermissionDecisionsLiveData =
+ spy(RecentPermissionDecisionsLiveData(recentPermissionDecisionStorage))
}
@Test
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/BasePermissionEventStorageTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/BasePermissionEventStorageTest.kt
index 41a60101d..534342144 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/BasePermissionEventStorageTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/BasePermissionEventStorageTest.kt
@@ -27,6 +27,11 @@ import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.service.BasePermissionEventStorage
import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.io.InputStream
+import java.io.OutputStream
+import java.util.Date
+import java.util.concurrent.TimeUnit
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
@@ -34,16 +39,11 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.File
-import java.io.InputStream
-import java.io.OutputStream
-import java.util.Date
-import java.util.concurrent.TimeUnit
@RunWith(AndroidJUnit4::class)
class BasePermissionEventStorageTest {
@@ -66,11 +66,9 @@ class BasePermissionEventStorageTest {
private val parkingEvent = TestPermissionEvent("package.test.parking", jan22020)
private val podcastEvent = TestPermissionEvent("package.test.podcast", jan22020)
- @Mock
- lateinit var jobScheduler: JobScheduler
+ @Mock lateinit var jobScheduler: JobScheduler
- @Mock
- lateinit var existingJob: JobInfo
+ @Mock lateinit var existingJob: JobInfo
private lateinit var context: Context
private lateinit var storage: BasePermissionEventStorage<TestPermissionEvent>
@@ -80,10 +78,12 @@ class BasePermissionEventStorageTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(DeviceConfig::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
`when`(PermissionControllerApplication.get()).thenReturn(application)
context = ApplicationProvider.getApplicationContext()
filesDir = context.cacheDir
@@ -107,9 +107,7 @@ class BasePermissionEventStorageTest {
@Test
fun loadEvents_noData_returnsEmptyList() {
init()
- runBlocking {
- assertThat(storage.loadEvents()).isEmpty()
- }
+ runBlocking { assertThat(storage.loadEvents()).isEmpty() }
}
@Test
@@ -130,8 +128,7 @@ class BasePermissionEventStorageTest {
storage.storeEvent(parkingEvent)
storage.storeEvent(podcastEvent)
assertThat(storage.loadEvents())
- .containsExactly(musicEvent, mapEvent, parkingEvent,
- podcastEvent)
+ .containsExactly(musicEvent, mapEvent, parkingEvent, podcastEvent)
}
}
@@ -181,10 +178,10 @@ class BasePermissionEventStorageTest {
fun removeOldData_removesOnlyOldData() {
init()
val todayEvent = parkingEvent.copy(eventTime = System.currentTimeMillis())
- val sixDaysAgoEvent = podcastEvent.copy(
- eventTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(6))
- val eightDaysAgoEvent = parkingEvent.copy(
- eventTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(8))
+ val sixDaysAgoEvent =
+ podcastEvent.copy(eventTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(6))
+ val eightDaysAgoEvent =
+ parkingEvent.copy(eventTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(8))
runBlocking {
storage.storeEvent(eightDaysAgoEvent)
storage.storeEvent(sixDaysAgoEvent)
@@ -202,11 +199,10 @@ class BasePermissionEventStorageTest {
storage.storeEvent(musicEvent)
storage.updateEventsBySystemTimeDelta(TimeUnit.DAYS.toMillis(1))
- assertThat(storage.loadEvents()).containsExactly(
- musicEvent.copy(
- eventTime = musicEvent.eventTime + TimeUnit.DAYS.toMillis(1)
+ assertThat(storage.loadEvents())
+ .containsExactly(
+ musicEvent.copy(eventTime = musicEvent.eventTime + TimeUnit.DAYS.toMillis(1))
)
- )
}
}
@@ -217,18 +213,15 @@ class BasePermissionEventStorageTest {
storage.storeEvent(musicEvent)
storage.updateEventsBySystemTimeDelta(-TimeUnit.DAYS.toMillis(1))
- assertThat(storage.loadEvents()).containsExactly(
- musicEvent.copy(
- eventTime = musicEvent.eventTime - TimeUnit.DAYS.toMillis(1)
+ assertThat(storage.loadEvents())
+ .containsExactly(
+ musicEvent.copy(eventTime = musicEvent.eventTime - TimeUnit.DAYS.toMillis(1))
)
- )
}
}
- private class TestPermissionEventStorage(
- context: Context,
- jobScheduler: JobScheduler
- ) : BasePermissionEventStorage<TestPermissionEvent>(context, jobScheduler) {
+ private class TestPermissionEventStorage(context: Context, jobScheduler: JobScheduler) :
+ BasePermissionEventStorage<TestPermissionEvent>(context, jobScheduler) {
lateinit var fakeDiskStore: List<TestPermissionEvent>
override fun serialize(stream: OutputStream, events: List<TestPermissionEvent>) {
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionChangeStorageImplTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionChangeStorageImplTest.kt
index 761fff18b..21855c124 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionChangeStorageImplTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionChangeStorageImplTest.kt
@@ -28,6 +28,10 @@ import com.android.permissioncontroller.permission.data.PermissionChange
import com.android.permissioncontroller.permission.service.PermissionChangeStorageImpl
import com.android.permissioncontroller.permission.utils.Utils
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.util.Date
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
@@ -39,10 +43,6 @@ import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.ByteArrayInputStream
-import java.io.ByteArrayOutputStream
-import java.io.File
-import java.util.Date
@RunWith(AndroidJUnit4::class)
class PermissionChangeStorageImplTest {
@@ -57,8 +57,7 @@ class PermissionChangeStorageImplTest {
private val mapChange = PermissionChange(MAP_PACKAGE_NAME, jan12020)
- @Mock
- lateinit var jobScheduler: JobScheduler
+ @Mock lateinit var jobScheduler: JobScheduler
private lateinit var context: Context
private lateinit var storage: PermissionChangeStorageImpl
@@ -68,10 +67,12 @@ class PermissionChangeStorageImplTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(DeviceConfig::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
Mockito.`when`(PermissionControllerApplication.get()).thenReturn(application)
context = ApplicationProvider.getApplicationContext()
filesDir = context.cacheDir
@@ -101,8 +102,7 @@ class PermissionChangeStorageImplTest {
@Test
fun serialize_roundsTimeDownToDate() {
- val laterInTheDayGrant = mapChange.copy(
- eventTime = (mapChange.eventTime + FIVE_HOURS_MS))
+ val laterInTheDayGrant = mapChange.copy(eventTime = (mapChange.eventTime + FIVE_HOURS_MS))
val outStream = ByteArrayOutputStream()
storage.serialize(outStream, listOf(laterInTheDayGrant))
@@ -113,9 +113,12 @@ class PermissionChangeStorageImplTest {
@Test
fun serialize_exactTimeDataCanBeParsed() {
Mockito.`when`(
- DeviceConfig.getBoolean(ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
- ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
- ArgumentMatchers.anyBoolean()))
+ DeviceConfig.getBoolean(
+ ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
+ ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
+ ArgumentMatchers.anyBoolean()
+ )
+ )
.thenReturn(true)
val outStream = ByteArrayOutputStream()
@@ -131,9 +134,12 @@ class PermissionChangeStorageImplTest {
storage.serialize(outStream, listOf(mapChange))
Mockito.`when`(
- DeviceConfig.getBoolean(ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
- ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
- ArgumentMatchers.anyBoolean()))
+ DeviceConfig.getBoolean(
+ ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
+ ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
+ ArgumentMatchers.anyBoolean()
+ )
+ )
.thenReturn(true)
val inStream = ByteArrayInputStream(outStream.toByteArray())
@@ -143,20 +149,25 @@ class PermissionChangeStorageImplTest {
@Test
fun serialize_afterStoresExactTimeChangedToFalse_roundsTimeDownToDate() {
Mockito.`when`(
- DeviceConfig.getBoolean(ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
- ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
- ArgumentMatchers.anyBoolean()))
+ DeviceConfig.getBoolean(
+ ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
+ ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
+ ArgumentMatchers.anyBoolean()
+ )
+ )
.thenReturn(true)
- val laterInTheDayEvent = mapChange.copy(
- eventTime = (mapChange.eventTime + FIVE_HOURS_MS))
+ val laterInTheDayEvent = mapChange.copy(eventTime = (mapChange.eventTime + FIVE_HOURS_MS))
val outStream = ByteArrayOutputStream()
storage.serialize(outStream, listOf(laterInTheDayEvent))
Mockito.`when`(
- DeviceConfig.getBoolean(ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
- ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
- ArgumentMatchers.anyBoolean()))
+ DeviceConfig.getBoolean(
+ ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
+ ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
+ ArgumentMatchers.anyBoolean()
+ )
+ )
.thenReturn(false)
val inStream = ByteArrayInputStream(outStream.toByteArray())
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionEventCleanupJobServiceTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionEventCleanupJobServiceTest.kt
index b60fea123..2f95d467d 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionEventCleanupJobServiceTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionEventCleanupJobServiceTest.kt
@@ -28,6 +28,7 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.service.PermissionEventCleanupJobService
import com.android.permissioncontroller.permission.service.PermissionEventCleanupJobService.Companion.DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY
import com.android.permissioncontroller.permission.utils.Utils
+import java.io.File
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -38,7 +39,6 @@ import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.File
@RunWith(AndroidJUnit4::class)
class PermissionEventCleanupJobServiceTest {
@@ -47,10 +47,8 @@ class PermissionEventCleanupJobServiceTest {
val application = Mockito.mock(PermissionControllerApplication::class.java)
}
- @Mock
- lateinit var jobScheduler: JobScheduler
- @Mock
- lateinit var existingJob: JobInfo
+ @Mock lateinit var jobScheduler: JobScheduler
+ @Mock lateinit var existingJob: JobInfo
private lateinit var context: Context
private lateinit var mockitoSession: MockitoSession
@@ -59,19 +57,24 @@ class PermissionEventCleanupJobServiceTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(DeviceConfig::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
Mockito.`when`(PermissionControllerApplication.get()).thenReturn(application)
context = ApplicationProvider.getApplicationContext()
filesDir = context.cacheDir
Mockito.`when`(application.filesDir).thenReturn(filesDir)
Mockito.`when`(jobScheduler.schedule(Mockito.any())).thenReturn(JobScheduler.RESULT_SUCCESS)
Mockito.`when`(
- DeviceConfig.getLong(eq(DeviceConfig.NAMESPACE_PERMISSIONS),
- eq(Utils.PROPERTY_PERMISSION_EVENTS_CHECK_OLD_FREQUENCY_MILLIS),
- eq(DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY)))
+ DeviceConfig.getLong(
+ eq(DeviceConfig.NAMESPACE_PERMISSIONS),
+ eq(Utils.PROPERTY_PERMISSION_EVENTS_CHECK_OLD_FREQUENCY_MILLIS),
+ eq(DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY)
+ )
+ )
.thenReturn(DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY)
}
@@ -93,8 +96,8 @@ class PermissionEventCleanupJobServiceTest {
@Test
fun init_existingJob_doesNotScheduleNewJob() {
- Mockito.`when`(existingJob.intervalMillis).thenReturn(
- DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY)
+ Mockito.`when`(existingJob.intervalMillis)
+ .thenReturn(DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY)
Mockito.`when`(jobScheduler.getPendingJob(Constants.OLD_PERMISSION_EVENT_CLEANUP_JOB_ID))
.thenReturn(existingJob)
PermissionEventCleanupJobService.scheduleOldDataCleanupIfNecessary(context, jobScheduler)
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionStorageTimeChangeReceiverTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionStorageTimeChangeReceiverTest.kt
index cf5d92fe3..2ae4b0585 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionStorageTimeChangeReceiverTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionStorageTimeChangeReceiverTest.kt
@@ -34,6 +34,8 @@ import com.android.permissioncontroller.permission.service.PermissionStorageTime
import com.android.permissioncontroller.permission.service.PermissionStorageTimeChangeReceiver.Companion.PREF_KEY_SYSTEM_TIME_SNAPSHOT
import com.android.permissioncontroller.permission.service.PermissionStorageTimeChangeReceiver.Companion.SNAPSHOT_UNINITIALIZED
import com.android.permissioncontroller.permission.utils.TimeSource
+import java.io.File
+import java.util.concurrent.TimeUnit
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -43,17 +45,15 @@ import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.File
-import java.util.concurrent.TimeUnit
@RunWith(AndroidJUnit4::class)
class PermissionStorageTimeChangeReceiverTest {
@@ -62,20 +62,15 @@ class PermissionStorageTimeChangeReceiverTest {
val application = mock(PermissionControllerApplication::class.java)
}
- @Mock
- lateinit var context: Context
+ @Mock lateinit var context: Context
- @Mock
- lateinit var sharedPreferences: SharedPreferences
+ @Mock lateinit var sharedPreferences: SharedPreferences
- @Mock
- lateinit var editor: SharedPreferences.Editor
+ @Mock lateinit var editor: SharedPreferences.Editor
- @Mock
- lateinit var packageManager: PackageManager
+ @Mock lateinit var packageManager: PackageManager
- @Mock
- lateinit var permissionEventStorage: PermissionEventStorage<out PermissionEvent>
+ @Mock lateinit var permissionEventStorage: PermissionEventStorage<out PermissionEvent>
private val fakeTimeSource = FakeTimeSource()
private lateinit var mockitoSession: MockitoSession
@@ -85,25 +80,27 @@ class PermissionStorageTimeChangeReceiverTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(DeviceConfig::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
`when`(PermissionControllerApplication.get()).thenReturn(application)
`when`(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPreferences)
`when`(sharedPreferences.edit()).thenReturn(editor)
val context: Context = ApplicationProvider.getApplicationContext()
filesDir = context.cacheDir
`when`(application.filesDir).thenReturn(filesDir)
- `when`(DeviceConfig.getProperty(eq(DeviceConfig.NAMESPACE_PERMISSIONS),
- anyString())).thenReturn(null)
+ `when`(DeviceConfig.getProperty(eq(DeviceConfig.NAMESPACE_PERMISSIONS), anyString()))
+ .thenReturn(null)
`when`(sharedPreferences.getLong(eq(PREF_KEY_SYSTEM_TIME_SNAPSHOT), anyLong()))
.thenReturn(SNAPSHOT_UNINITIALIZED)
`when`(sharedPreferences.getLong(eq(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT), anyLong()))
.thenReturn(SNAPSHOT_UNINITIALIZED)
- receiver = spy(PermissionStorageTimeChangeReceiver(listOf(permissionEventStorage),
- fakeTimeSource))
+ receiver =
+ spy(PermissionStorageTimeChangeReceiver(listOf(permissionEventStorage), fakeTimeSource))
}
@After
@@ -123,8 +120,8 @@ class PermissionStorageTimeChangeReceiverTest {
@Test
fun onReceive_timeSetReceived_beforeBootCompleted_doesNothing() {
- fakeTimeSource.currentTimeMillis = fakeTimeSource.currentTimeMillis +
- TimeUnit.DAYS.toMillis(2)
+ fakeTimeSource.currentTimeMillis =
+ fakeTimeSource.currentTimeMillis + TimeUnit.DAYS.toMillis(2)
receiver.onReceive(context, Intent(Intent.ACTION_TIME_CHANGED))
verify(receiver, never()).onTimeChanged(anyLong())
@@ -143,8 +140,8 @@ class PermissionStorageTimeChangeReceiverTest {
fun onReceive_timeDiffBelowMinimum_doesNothing() {
mockBootCompletedSnapshot()
- fakeTimeSource.currentTimeMillis = fakeTimeSource.currentTimeMillis -
- TimeUnit.SECONDS.toMillis(30)
+ fakeTimeSource.currentTimeMillis =
+ fakeTimeSource.currentTimeMillis - TimeUnit.SECONDS.toMillis(30)
receiver.onReceive(context, Intent(Intent.ACTION_TIME_CHANGED))
verify(receiver, never()).onTimeChanged(anyLong())
@@ -155,10 +152,9 @@ class PermissionStorageTimeChangeReceiverTest {
mockBootCompletedSnapshot()
// in 3 days the time is set to one day from now (effectively set back by 2 days)
- fakeTimeSource.currentTimeMillis = fakeTimeSource.currentTimeMillis +
- TimeUnit.DAYS.toMillis(1)
- fakeTimeSource.elapsedRealtime = fakeTimeSource.elapsedRealtime +
- TimeUnit.DAYS.toMillis(3)
+ fakeTimeSource.currentTimeMillis =
+ fakeTimeSource.currentTimeMillis + TimeUnit.DAYS.toMillis(1)
+ fakeTimeSource.elapsedRealtime = fakeTimeSource.elapsedRealtime + TimeUnit.DAYS.toMillis(3)
receiver.onReceive(context, Intent(Intent.ACTION_TIME_CHANGED))
verify(receiver).onTimeChanged(-TimeUnit.DAYS.toMillis(2))
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PersistedStoragePackageUninstalledReceiverTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PersistedStoragePackageUninstalledReceiverTest.kt
index 2cefaab67..baa848960 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PersistedStoragePackageUninstalledReceiverTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PersistedStoragePackageUninstalledReceiverTest.kt
@@ -29,6 +29,8 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.service.PersistedStoragePackageUninstalledReceiver
import com.android.permissioncontroller.tests.mocking.permission.data.FakeEventStorage
import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.Date
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.junit.After
@@ -37,14 +39,12 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.spy
import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.File
-import java.util.Date
@RunWith(AndroidJUnit4::class)
class PersistedStoragePackageUninstalledReceiverTest {
@@ -55,14 +55,11 @@ class PersistedStoragePackageUninstalledReceiverTest {
private val musicEvent = TestPermissionEvent("package.test.music", Date(2020, 0, 1).time)
- @Mock
- lateinit var context: Context
+ @Mock lateinit var context: Context
- @Mock
- lateinit var packageManager: PackageManager
+ @Mock lateinit var packageManager: PackageManager
- @Mock
- lateinit var jobScheduler: JobScheduler
+ @Mock lateinit var jobScheduler: JobScheduler
private lateinit var mockitoSession: MockitoSession
private lateinit var filesDir: File
@@ -72,17 +69,24 @@ class PersistedStoragePackageUninstalledReceiverTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(PermissionControllerApplication::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
`when`(PermissionControllerApplication.get()).thenReturn(application)
val context: Context = ApplicationProvider.getApplicationContext()
filesDir = context.cacheDir
`when`(application.filesDir).thenReturn(filesDir)
permissionEventStorage = spy(FakeEventStorage())
- receiver = spy(PersistedStoragePackageUninstalledReceiver(
- listOf(permissionEventStorage), Dispatchers.Main.immediate))
+ receiver =
+ spy(
+ PersistedStoragePackageUninstalledReceiver(
+ listOf(permissionEventStorage),
+ Dispatchers.Main.immediate
+ )
+ )
}
@After
@@ -112,8 +116,6 @@ class PersistedStoragePackageUninstalledReceiverTest {
receiver.onReceive(context, intent)
- runBlocking {
- assertThat(permissionEventStorage.loadEvents().isEmpty())
- }
+ runBlocking { assertThat(permissionEventStorage.loadEvents().isEmpty()) }
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/RuntimePermissionsUpgradeControllerTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/RuntimePermissionsUpgradeControllerTest.kt
index d576f2924..bb84a2d05 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/RuntimePermissionsUpgradeControllerTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/RuntimePermissionsUpgradeControllerTest.kt
@@ -19,11 +19,14 @@ package com.android.permissioncontroller.tests.mocking.permission.service
import android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.Manifest.permission.ACCESS_MEDIA_LOCATION
+import android.Manifest.permission.BODY_SENSORS
+import android.Manifest.permission.BODY_SENSORS_BACKGROUND
import android.Manifest.permission.READ_CALL_LOG
import android.Manifest.permission.READ_EXTERNAL_STORAGE
import android.Manifest.permission.READ_MEDIA_AUDIO
import android.Manifest.permission.READ_MEDIA_IMAGES
import android.Manifest.permission.READ_MEDIA_VIDEO
+import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
import android.Manifest.permission.SEND_SMS
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.app.ActivityManager
@@ -51,6 +54,7 @@ import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.DeviceUtils
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.service.RuntimePermissionsUpgradeController
import com.android.permissioncontroller.tests.mocking.permission.data.dataRepositories
@@ -60,6 +64,7 @@ import org.junit.Assume
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.AdditionalMatchers
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
@@ -82,8 +87,7 @@ class RuntimePermissionsUpgradeControllerTest {
init {
whenever(application.applicationContext).thenReturn(application)
- whenever(application.createContextAsUser(any(), anyInt())).thenReturn(
- application)
+ whenever(application.createContextAsUser(any(), anyInt())).thenReturn(application)
whenever(application.registerComponentCallbacks(any())).thenAnswer {
val dataRepository = it.arguments[0] as ComponentCallbacks2
@@ -94,34 +98,31 @@ class RuntimePermissionsUpgradeControllerTest {
}
/** Latest permission database version known in this test */
- private val LATEST_VERSION = if (SdkLevel.isAtLeastT()) {
- 10
- } else {
- 9
- }
+ private val LATEST_VERSION =
+ if (SdkLevel.isAtLeastT()) {
+ 10
+ } else {
+ 9
+ }
/** Use a unique test package name for each test */
private val TEST_PKG_NAME: String
- get() = Thread.currentThread().stackTrace
- .filter { it.className == this::class.java.name }[1].methodName
+ get() =
+ Thread.currentThread()
+ .stackTrace
+ .filter { it.className == this::class.java.name }[1]
+ .methodName
/** Mockito session of this test */
private var mockitoSession: MockitoSession? = null
- @Mock
- lateinit var packageManager: PackageManager
- @Mock
- lateinit var permissionManager: PermissionManager
- @Mock
- lateinit var activityManager: ActivityManager
- @Mock
- lateinit var appOpsManager: AppOpsManager
- @Mock
- lateinit var locationManager: LocationManager
- @Mock
- lateinit var userManager: UserManager
- @Mock
- lateinit var jobScheduler: JobScheduler
+ @Mock lateinit var packageManager: PackageManager
+ @Mock lateinit var permissionManager: PermissionManager
+ @Mock lateinit var activityManager: ActivityManager
+ @Mock lateinit var appOpsManager: AppOpsManager
+ @Mock lateinit var locationManager: LocationManager
+ @Mock lateinit var userManager: UserManager
+ @Mock lateinit var jobScheduler: JobScheduler
/**
* Set up {@link #packageManager} as if the passed packages are installed.
@@ -130,24 +131,28 @@ class RuntimePermissionsUpgradeControllerTest {
*/
private fun setPackages(vararg pkgs: Package) {
val mockPackageInfo = { pkgs: List<Package>, flags: Long ->
- pkgs.filter { pkg ->
- (flags and MATCH_FACTORY_ONLY.toLong()) == 0L || pkg.isPreinstalled
- }.map { pkg ->
- PackageInfo().apply {
- packageName = pkg.name
- requestedPermissions = pkg.permissions.map { it.name }.toTypedArray()
- requestedPermissionsFlags = pkg.permissions.map {
- if (it.isGranted) {
- REQUESTED_PERMISSION_GRANTED
- } else {
- 0
- }
- }.toIntArray()
- applicationInfo = ApplicationInfo().apply {
- targetSdkVersion = pkg.targetSdkVersion
+ pkgs
+ .filter { pkg ->
+ (flags and MATCH_FACTORY_ONLY.toLong()) == 0L || pkg.isPreinstalled
+ }
+ .map { pkg ->
+ PackageInfo().apply {
+ packageName = pkg.name
+ requestedPermissions = pkg.permissions.map { it.name }.toTypedArray()
+ requestedPermissionsFlags =
+ pkg.permissions
+ .map {
+ if (it.isGranted) {
+ REQUESTED_PERMISSION_GRANTED
+ } else {
+ 0
+ }
+ }
+ .toIntArray()
+ applicationInfo =
+ ApplicationInfo().apply { targetSdkVersion = pkg.targetSdkVersion }
}
}
- }
}
whenever(packageManager.getInstalledPackagesAsUser(anyInt(), anyInt())).thenAnswer {
@@ -158,22 +163,22 @@ class RuntimePermissionsUpgradeControllerTest {
if (SdkLevel.isAtLeastT()) {
whenever(
- packageManager.getInstalledPackagesAsUser(
- any(PackageManager.PackageInfoFlags::class.java),
- anyInt()
+ packageManager.getInstalledPackagesAsUser(
+ any(PackageManager.PackageInfoFlags::class.java),
+ anyInt()
+ )
)
- ).thenAnswer {
- val flags = it.arguments[0] as PackageManager.PackageInfoFlags
+ .thenAnswer {
+ val flags = it.arguments[0] as PackageManager.PackageInfoFlags
- mockPackageInfo(pkgs.toList(), flags.value)
- }
+ mockPackageInfo(pkgs.toList(), flags.value)
+ }
}
whenever(packageManager.getPackageInfo(anyString(), anyInt())).thenAnswer {
val packageName = it.arguments[0] as String
- packageManager.getInstalledPackagesAsUser(0, 0)
- .find { it.packageName == packageName }
+ packageManager.getInstalledPackagesAsUser(0, 0).find { it.packageName == packageName }
?: throw PackageManager.NameNotFoundException()
}
@@ -181,8 +186,12 @@ class RuntimePermissionsUpgradeControllerTest {
val permissionName = it.arguments[0] as String
val packageName = it.arguments[1] as String
- pkgs.find { it.name == packageName }?.permissions
- ?.find { it.name == permissionName }?.flags ?: 0
+ pkgs
+ .find { it.name == packageName }
+ ?.permissions
+ ?.find { it.name == permissionName }
+ ?.flags
+ ?: 0
}
}
@@ -194,54 +203,68 @@ class RuntimePermissionsUpgradeControllerTest {
fun initSystem() {
initMocks(this)
- mockitoSession = mockitoSession().mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(Settings.Secure::class.java).strictness(LENIENT).startMocking()
+ mockitoSession =
+ mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(Settings.Secure::class.java)
+ .strictness(LENIENT)
+ .startMocking()
whenever(PermissionControllerApplication.get()).thenReturn(application)
- whenever(application.getSystemService(PermissionManager::class.java)).thenReturn(
- permissionManager)
- whenever(application.getSystemService(ActivityManager::class.java)).thenReturn(
- activityManager)
+ whenever(application.getSystemService(PermissionManager::class.java))
+ .thenReturn(permissionManager)
+ whenever(application.getSystemService(ActivityManager::class.java))
+ .thenReturn(activityManager)
whenever(application.getSystemService(AppOpsManager::class.java)).thenReturn(appOpsManager)
- whenever(application.getSystemService(LocationManager::class.java)).thenReturn(
- locationManager)
- whenever(application.getSystemService(UserManager::class.java)).thenReturn(
- userManager)
- whenever(application.getSystemService(JobScheduler::class.java)).thenReturn(
- jobScheduler)
+ whenever(application.getSystemService(LocationManager::class.java))
+ .thenReturn(locationManager)
+ whenever(application.getSystemService(UserManager::class.java)).thenReturn(userManager)
+ whenever(application.getSystemService(JobScheduler::class.java)).thenReturn(jobScheduler)
whenever(application.packageManager).thenReturn(packageManager)
whenever(packageManager.getPermissionInfo(any(), anyInt())).thenAnswer {
val permissionName = it.arguments[0] as String
- InstrumentationRegistry.getInstrumentation().getTargetContext().packageManager
- .getPermissionInfo(permissionName, 0)
+ InstrumentationRegistry.getInstrumentation()
+ .getTargetContext()
+ .packageManager
+ .getPermissionInfo(permissionName, 0)
}
whenever(packageManager.getPermissionGroupInfo(any(), anyInt())).thenAnswer {
val groupName = it.arguments[0] as String
- InstrumentationRegistry.getInstrumentation().getTargetContext().packageManager
- .getPermissionGroupInfo(groupName, 0)
+ InstrumentationRegistry.getInstrumentation()
+ .getTargetContext()
+ .packageManager
+ .getPermissionGroupInfo(groupName, 0)
}
// We cannot use thenReturn(mutableListOf()) because that would return the same instance.
whenever(packageManager.queryPermissionsByGroup(any(), anyInt())).thenAnswer {
mutableListOf<PermissionInfo>()
}
+
+ whenever(packageManager.hasSystemFeature(any())).thenAnswer {
+ val featureName = it.arguments[0] as String
+
+ InstrumentationRegistry.getInstrumentation()
+ .getTargetContext()
+ .packageManager
+ .hasSystemFeature(featureName)
+ }
}
- /**
- * Call {@link RuntimePermissionsUpgradeController#upgradeIfNeeded) and wait until finished.
- */
+ /** Call {@link RuntimePermissionsUpgradeController#upgradeIfNeeded) and wait until finished. */
private fun upgradeIfNeeded() {
val completionCallback = CompletableFuture<Unit>()
runWithShellPermissionIdentity {
- RuntimePermissionsUpgradeController.upgradeIfNeeded(application, Runnable {
- completionCallback.complete(Unit)
- })
+ RuntimePermissionsUpgradeController.upgradeIfNeeded(
+ application,
+ Runnable { completionCallback.complete(Unit) }
+ )
completionCallback.join()
}
}
@@ -252,37 +275,37 @@ class RuntimePermissionsUpgradeControllerTest {
private fun verifyWhitelisted(packageName: String, vararg permissionNames: String) {
for (permissionName in permissionNames) {
- verify(packageManager, timeout(100)).addWhitelistedRestrictedPermission(
- packageName, permissionName, FLAG_PERMISSION_WHITELIST_UPGRADE)
+ verify(packageManager, timeout(100))
+ .addWhitelistedRestrictedPermission(
+ packageName,
+ permissionName,
+ FLAG_PERMISSION_WHITELIST_UPGRADE
+ )
}
}
private fun verifyNotWhitelisted(packageName: String, vararg permissionNames: String) {
for (permissionName in permissionNames) {
- verify(packageManager, never()).addWhitelistedRestrictedPermission(eq(packageName),
- eq(permissionName), anyInt())
+ verify(packageManager, never())
+ .addWhitelistedRestrictedPermission(eq(packageName), eq(permissionName), anyInt())
}
}
private fun verifyGranted(packageName: String, permissionName: String) {
- verify(packageManager, timeout(100)).grantRuntimePermission(eq(packageName),
- eq(permissionName), any())
+ verify(packageManager, timeout(100))
+ .grantRuntimePermission(eq(packageName), eq(permissionName), any())
}
private fun verifyNotGranted(packageName: String, permissionName: String) {
- verify(packageManager, never()).grantRuntimePermission(eq(packageName),
- eq(permissionName), any())
+ verify(packageManager, never())
+ .grantRuntimePermission(eq(packageName), eq(permissionName), any())
}
@Test
fun restrictedPermissionsOfPreinstalledPackagesGetWhiteListed() {
setInitialDatabaseVersion(LATEST_VERSION)
- setPackages(
- PreinstalledPackage(TEST_PKG_NAME,
- Permission(SEND_SMS)
- )
- )
+ setPackages(PreinstalledPackage(TEST_PKG_NAME, Permission(SEND_SMS)))
upgradeIfNeeded()
@@ -293,11 +316,7 @@ class RuntimePermissionsUpgradeControllerTest {
fun nonRestrictedPermissionsOfPreinstalledPackagesDoNotGetWhiteListed() {
setInitialDatabaseVersion(LATEST_VERSION)
- setPackages(
- PreinstalledPackage(TEST_PKG_NAME,
- Permission(ACCESS_FINE_LOCATION)
- )
- )
+ setPackages(PreinstalledPackage(TEST_PKG_NAME, Permission(ACCESS_FINE_LOCATION)))
upgradeIfNeeded()
@@ -307,11 +326,7 @@ class RuntimePermissionsUpgradeControllerTest {
@Test
fun restrictedPermissionsOfNonPreinstalledPackagesDoNotGetWhiteListed() {
setInitialDatabaseVersion(LATEST_VERSION)
- setPackages(
- Package(TEST_PKG_NAME,
- Permission(SEND_SMS)
- )
- )
+ setPackages(Package(TEST_PKG_NAME, Permission(SEND_SMS)))
upgradeIfNeeded()
@@ -321,12 +336,7 @@ class RuntimePermissionsUpgradeControllerTest {
@Test
fun smsAndCallLogGetsWhitelistedWhenInitialVersionIs0() {
setInitialDatabaseVersion(0)
- setPackages(
- Package(TEST_PKG_NAME,
- Permission(SEND_SMS),
- Permission(READ_CALL_LOG)
- )
- )
+ setPackages(Package(TEST_PKG_NAME, Permission(SEND_SMS), Permission(READ_CALL_LOG)))
upgradeIfNeeded()
@@ -337,12 +347,7 @@ class RuntimePermissionsUpgradeControllerTest {
@Test
fun smsAndCallLogGDoesNotGetWhitelistedWhenInitialVersionIs1() {
setInitialDatabaseVersion(1)
- setPackages(
- Package(TEST_PKG_NAME,
- Permission(SEND_SMS),
- Permission(READ_CALL_LOG)
- )
- )
+ setPackages(Package(TEST_PKG_NAME, Permission(SEND_SMS), Permission(READ_CALL_LOG)))
upgradeIfNeeded()
@@ -353,11 +358,7 @@ class RuntimePermissionsUpgradeControllerTest {
@Test
fun backgroundLocationGetsWhitelistedWhenInitialVersionIs3() {
setInitialDatabaseVersion(3)
- setPackages(
- Package(TEST_PKG_NAME,
- Permission(ACCESS_BACKGROUND_LOCATION)
- )
- )
+ setPackages(Package(TEST_PKG_NAME, Permission(ACCESS_BACKGROUND_LOCATION)))
upgradeIfNeeded()
@@ -367,11 +368,7 @@ class RuntimePermissionsUpgradeControllerTest {
@Test
fun backgroundLocationGetsWhitelistedWhenInitialVersionIs4() {
setInitialDatabaseVersion(4)
- setPackages(
- Package(TEST_PKG_NAME,
- Permission(ACCESS_BACKGROUND_LOCATION)
- )
- )
+ setPackages(Package(TEST_PKG_NAME, Permission(ACCESS_BACKGROUND_LOCATION)))
upgradeIfNeeded()
@@ -381,11 +378,7 @@ class RuntimePermissionsUpgradeControllerTest {
@Test
fun storageGetsWhitelistedWhenInitialVersionIs5() {
setInitialDatabaseVersion(5)
- setPackages(
- Package(TEST_PKG_NAME,
- Permission(READ_EXTERNAL_STORAGE)
- )
- )
+ setPackages(Package(TEST_PKG_NAME, Permission(READ_EXTERNAL_STORAGE)))
upgradeIfNeeded()
@@ -395,11 +388,7 @@ class RuntimePermissionsUpgradeControllerTest {
@Test
fun storageGetsWhitelistedWhenInitialVersionIs6() {
setInitialDatabaseVersion(6)
- setPackages(
- Package(TEST_PKG_NAME,
- Permission(READ_EXTERNAL_STORAGE)
- )
- )
+ setPackages(Package(TEST_PKG_NAME, Permission(READ_EXTERNAL_STORAGE)))
upgradeIfNeeded()
@@ -410,7 +399,8 @@ class RuntimePermissionsUpgradeControllerTest {
fun locationGetsExpandedWhenUpgradingFromP() {
setInitialDatabaseVersion(-1)
setPackages(
- Package(TEST_PKG_NAME,
+ Package(
+ TEST_PKG_NAME,
Permission(ACCESS_FINE_LOCATION, isGranted = true),
Permission(ACCESS_BACKGROUND_LOCATION)
)
@@ -425,7 +415,8 @@ class RuntimePermissionsUpgradeControllerTest {
fun locationDoesNotGetExpandedWhenNotUpgradingFromP() {
setInitialDatabaseVersion(0)
setPackages(
- Package(TEST_PKG_NAME,
+ Package(
+ TEST_PKG_NAME,
Permission(ACCESS_FINE_LOCATION, isGranted = true),
Permission(ACCESS_BACKGROUND_LOCATION)
)
@@ -440,7 +431,8 @@ class RuntimePermissionsUpgradeControllerTest {
fun locationDoesNotGetExpandedWhenUpgradingFromPWhenForegroundPermissionIsDenied() {
setInitialDatabaseVersion(-1)
setPackages(
- Package(TEST_PKG_NAME,
+ Package(
+ TEST_PKG_NAME,
Permission(ACCESS_FINE_LOCATION),
Permission(ACCESS_BACKGROUND_LOCATION)
)
@@ -455,9 +447,13 @@ class RuntimePermissionsUpgradeControllerTest {
fun storageGetsExpandedWhenVersionIs7() {
setInitialDatabaseVersion(7)
setPackages(
- Package(TEST_PKG_NAME,
- Permission(READ_EXTERNAL_STORAGE, isGranted = true,
- flags = FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT),
+ Package(
+ TEST_PKG_NAME,
+ Permission(
+ READ_EXTERNAL_STORAGE,
+ isGranted = true,
+ flags = FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
+ ),
Permission(ACCESS_MEDIA_LOCATION)
)
)
@@ -471,9 +467,13 @@ class RuntimePermissionsUpgradeControllerTest {
fun storageDoesNotGetExpandedWhenVersionIs8() {
setInitialDatabaseVersion(8)
setPackages(
- Package(TEST_PKG_NAME,
- Permission(READ_EXTERNAL_STORAGE, isGranted = true,
- flags = FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT),
+ Package(
+ TEST_PKG_NAME,
+ Permission(
+ READ_EXTERNAL_STORAGE,
+ isGranted = true,
+ flags = FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
+ ),
Permission(ACCESS_MEDIA_LOCATION)
)
)
@@ -487,9 +487,12 @@ class RuntimePermissionsUpgradeControllerTest {
fun storageDoesNotGetExpandedWhenDenied() {
setInitialDatabaseVersion(7)
setPackages(
- Package(TEST_PKG_NAME,
- Permission(READ_EXTERNAL_STORAGE,
- flags = FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT),
+ Package(
+ TEST_PKG_NAME,
+ Permission(
+ READ_EXTERNAL_STORAGE,
+ flags = FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
+ ),
Permission(ACCESS_MEDIA_LOCATION)
)
)
@@ -503,9 +506,13 @@ class RuntimePermissionsUpgradeControllerTest {
fun storageDoesNotGetExpandedWhenNewUser() {
setInitialDatabaseVersion(0)
setPackages(
- Package(TEST_PKG_NAME,
- Permission(READ_EXTERNAL_STORAGE, isGranted = true,
- flags = FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT),
+ Package(
+ TEST_PKG_NAME,
+ Permission(
+ READ_EXTERNAL_STORAGE,
+ isGranted = true,
+ flags = FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
+ ),
Permission(ACCESS_MEDIA_LOCATION)
)
)
@@ -526,13 +533,23 @@ class RuntimePermissionsUpgradeControllerTest {
whenever(packageManager.isDeviceUpgrading).thenReturn(true)
setInitialDatabaseVersion(9)
setPackages(
- Package(TEST_PKG_NAME,
- Permission(READ_EXTERNAL_STORAGE, isGranted = true,
- flags = FLAG_PERMISSION_USER_SET),
- Permission(WRITE_EXTERNAL_STORAGE, isGranted = true,
- flags = FLAG_PERMISSION_USER_SET),
- Permission(ACCESS_MEDIA_LOCATION, isGranted = true,
- flags = FLAG_PERMISSION_USER_SET),
+ Package(
+ TEST_PKG_NAME,
+ Permission(
+ READ_EXTERNAL_STORAGE,
+ isGranted = true,
+ flags = FLAG_PERMISSION_USER_SET
+ ),
+ Permission(
+ WRITE_EXTERNAL_STORAGE,
+ isGranted = true,
+ flags = FLAG_PERMISSION_USER_SET
+ ),
+ Permission(
+ ACCESS_MEDIA_LOCATION,
+ isGranted = true,
+ flags = FLAG_PERMISSION_USER_SET
+ ),
Permission(READ_MEDIA_AUDIO, isGranted = false),
Permission(READ_MEDIA_VIDEO, isGranted = false),
Permission(READ_MEDIA_IMAGES, isGranted = false),
@@ -547,6 +564,173 @@ class RuntimePermissionsUpgradeControllerTest {
verifyGranted(TEST_PKG_NAME, READ_MEDIA_IMAGES)
}
+ @Test
+ fun userSelectedGrantedIfReadMediaVisualGrantedWhenVersionIs10() {
+ Assume.assumeTrue(SdkLevel.isAtLeastU())
+ whenever(packageManager.isDeviceUpgrading).thenReturn(true)
+ setInitialDatabaseVersion(10)
+ setPackages(
+ Package(
+ TEST_PKG_NAME,
+ Permission(READ_MEDIA_VIDEO, isGranted = true, flags = FLAG_PERMISSION_USER_SET),
+ Permission(READ_MEDIA_IMAGES, isGranted = true, flags = FLAG_PERMISSION_USER_SET),
+ Permission(READ_MEDIA_VISUAL_USER_SELECTED, isGranted = false),
+ targetSdkVersion = 33
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyGranted(TEST_PKG_NAME, READ_MEDIA_VISUAL_USER_SELECTED)
+ }
+
+ @Test
+ fun userSelectedNotGrantedIfDeviceNotUpgradingWhenVersionIs10() {
+ Assume.assumeTrue(SdkLevel.isAtLeastU())
+ whenever(packageManager.isDeviceUpgrading).thenReturn(false)
+ setInitialDatabaseVersion(10)
+ setPackages(
+ Package(
+ TEST_PKG_NAME,
+ Permission(READ_MEDIA_VIDEO, isGranted = true, flags = FLAG_PERMISSION_USER_SET),
+ Permission(READ_MEDIA_IMAGES, isGranted = true, flags = FLAG_PERMISSION_USER_SET),
+ Permission(READ_MEDIA_VISUAL_USER_SELECTED, isGranted = false),
+ targetSdkVersion = 33
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyNotGranted(TEST_PKG_NAME, READ_MEDIA_VISUAL_USER_SELECTED)
+ }
+
+ @Test
+ fun userSelectedNotGrantedIfReadMediaVisualNotGrantedWhenVersionIs10() {
+ Assume.assumeTrue(SdkLevel.isAtLeastU())
+ whenever(packageManager.isDeviceUpgrading).thenReturn(false)
+ setInitialDatabaseVersion(10)
+ setPackages(
+ Package(
+ TEST_PKG_NAME,
+ Permission(READ_MEDIA_VIDEO, isGranted = false, flags = FLAG_PERMISSION_USER_SET),
+ Permission(READ_MEDIA_IMAGES, isGranted = false, flags = FLAG_PERMISSION_USER_SET),
+ Permission(READ_MEDIA_VISUAL_USER_SELECTED, isGranted = false),
+ targetSdkVersion = 33
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyNotGranted(TEST_PKG_NAME, READ_MEDIA_VISUAL_USER_SELECTED)
+ }
+
+ @Test
+ fun ensureDatabaseResetToLatestIfAboveLatest() {
+ setInitialDatabaseVersion(Int.MAX_VALUE)
+ upgradeIfNeeded()
+ verify(permissionManager).runtimePermissionsVersion =
+ AdditionalMatchers.not(eq(Int.MAX_VALUE))
+ }
+
+ @Test
+ fun bodySensorsInheritToBodySensorsBackgroundWhenBodySensorsWasGrantedAndTargetingR() {
+ Assume.assumeTrue(DeviceUtils.isWear(application))
+ Assume.assumeTrue(SdkLevel.isAtLeastT())
+ whenever(packageManager.isDeviceUpgrading).thenReturn(true)
+ setInitialDatabaseVersion(9)
+ setPackages(
+ Package(
+ TEST_PKG_NAME,
+ Permission(BODY_SENSORS, isGranted = true, flags = FLAG_PERMISSION_USER_SET),
+ Permission(BODY_SENSORS_BACKGROUND, isGranted = false),
+ targetSdkVersion = 30
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyGranted(TEST_PKG_NAME, BODY_SENSORS_BACKGROUND)
+ }
+
+ @Test
+ fun bodySensorsNotInheritToBodySensorsBackgroundWhenBodySensorsWasNotGrantedAndTargetingR() {
+ Assume.assumeTrue(DeviceUtils.isWear(application))
+ Assume.assumeTrue(SdkLevel.isAtLeastT())
+ whenever(packageManager.isDeviceUpgrading).thenReturn(true)
+ setInitialDatabaseVersion(9)
+ setPackages(
+ Package(
+ TEST_PKG_NAME,
+ Permission(BODY_SENSORS, isGranted = false, flags = FLAG_PERMISSION_USER_SET),
+ Permission(BODY_SENSORS_BACKGROUND, isGranted = false),
+ targetSdkVersion = 30
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyNotGranted(TEST_PKG_NAME, BODY_SENSORS_BACKGROUND)
+ }
+
+ @Test
+ fun bodySensorsInheritToBodySensorsBackgroundWhenBodySensorsWasGrantedAndTargetingT() {
+ Assume.assumeTrue(DeviceUtils.isWear(application))
+ Assume.assumeTrue(SdkLevel.isAtLeastT())
+ whenever(packageManager.isDeviceUpgrading).thenReturn(true)
+ setInitialDatabaseVersion(9)
+ setPackages(
+ Package(
+ TEST_PKG_NAME,
+ Permission(BODY_SENSORS, isGranted = true, flags = FLAG_PERMISSION_USER_SET),
+ Permission(BODY_SENSORS_BACKGROUND, isGranted = false),
+ targetSdkVersion = 33
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyGranted(TEST_PKG_NAME, BODY_SENSORS_BACKGROUND)
+ }
+
+ @Test
+ fun bodySensorsNotInheritToBodySensorsBackgroundWhenBodySensorsWasNotGrantedAndTargetingT() {
+ Assume.assumeTrue(DeviceUtils.isWear(application))
+ Assume.assumeTrue(SdkLevel.isAtLeastT())
+ whenever(packageManager.isDeviceUpgrading).thenReturn(true)
+ setInitialDatabaseVersion(9)
+ setPackages(
+ Package(
+ TEST_PKG_NAME,
+ Permission(BODY_SENSORS, isGranted = false, flags = FLAG_PERMISSION_USER_SET),
+ Permission(BODY_SENSORS_BACKGROUND, isGranted = false),
+ targetSdkVersion = 33
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyNotGranted(TEST_PKG_NAME, BODY_SENSORS_BACKGROUND)
+ }
+
+ @Test
+ fun bodySensorsNotInheritToBodySensorsBackgroundWhenBackgroundNotDeclaredAndTargetingT() {
+ Assume.assumeTrue(DeviceUtils.isWear(application))
+ Assume.assumeTrue(SdkLevel.isAtLeastT())
+ whenever(packageManager.isDeviceUpgrading).thenReturn(true)
+ setInitialDatabaseVersion(9)
+ setPackages(
+ Package(
+ TEST_PKG_NAME,
+ Permission(BODY_SENSORS, isGranted = true, flags = FLAG_PERMISSION_USER_SET),
+ targetSdkVersion = 33
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyNotGranted(TEST_PKG_NAME, BODY_SENSORS_BACKGROUND)
+ }
+
@After
fun resetSystem() {
// Send low memory notifications for all data repositories which will clear cached data
@@ -575,12 +759,9 @@ class RuntimePermissionsUpgradeControllerTest {
) : this(name, permission.toList(), isPreinstalled, targetSdkVersion)
}
- private class PreinstalledPackage(
- name: String,
- permissions: List<Permission> = emptyList()
- ) : Package(name, permissions, true) {
- constructor(name: String, vararg permission: Permission) :
- this(name, permission.toList())
+ private class PreinstalledPackage(name: String, permissions: List<Permission> = emptyList()) :
+ Package(name, permissions, true) {
+ constructor(name: String, vararg permission: Permission) : this(name, permission.toList())
}
private fun <R> runWithShellPermissionIdentity(block: () -> R): R {
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionDecisionStorageImplTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionDecisionStorageImplTest.kt
index de8e3f5ef..fbbc07837 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionDecisionStorageImplTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionDecisionStorageImplTest.kt
@@ -27,6 +27,10 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.data.v33.PermissionDecision
import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.util.Date
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
@@ -37,10 +41,6 @@ import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.ByteArrayInputStream
-import java.io.ByteArrayOutputStream
-import java.io.File
-import java.util.Date
@RunWith(AndroidJUnit4::class)
class PermissionDecisionStorageImplTest {
@@ -53,13 +53,12 @@ class PermissionDecisionStorageImplTest {
private val jan12020 = Date(2020, 0, 1).time
- private val mapLocationGrant = PermissionDecision(
- MAP_PACKAGE_NAME, jan12020, "location", /* isGranted */ true)
- private val parkingLocationGrant = PermissionDecision(
- "package.test.parking", jan12020, "location", /* isGranted */ false)
+ private val mapLocationGrant =
+ PermissionDecision(MAP_PACKAGE_NAME, jan12020, "location", /* isGranted */ true)
+ private val parkingLocationGrant =
+ PermissionDecision("package.test.parking", jan12020, "location", /* isGranted */ false)
- @Mock
- lateinit var jobScheduler: JobScheduler
+ @Mock lateinit var jobScheduler: JobScheduler
private lateinit var context: Context
private lateinit var storage: PermissionDecisionStorageImpl
@@ -69,10 +68,12 @@ class PermissionDecisionStorageImplTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(DeviceConfig::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
Mockito.`when`(PermissionControllerApplication.get()).thenReturn(application)
context = ApplicationProvider.getApplicationContext()
filesDir = context.cacheDir
@@ -102,8 +103,8 @@ class PermissionDecisionStorageImplTest {
@Test
fun serialize_roundsTimeDownToDate() {
- val laterInTheDayGrant = mapLocationGrant.copy(
- eventTime = (mapLocationGrant.eventTime + FIVE_HOURS_MS))
+ val laterInTheDayGrant =
+ mapLocationGrant.copy(eventTime = (mapLocationGrant.eventTime + FIVE_HOURS_MS))
val outStream = ByteArrayOutputStream()
storage.serialize(outStream, listOf(laterInTheDayGrant))
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/handheld/v31/DashboardUtilsTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/handheld/v31/DashboardUtilsTest.kt
index 776e0719c..136162040 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/handheld/v31/DashboardUtilsTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/handheld/v31/DashboardUtilsTest.kt
@@ -21,189 +21,123 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.permissioncontroller.permission.ui.handheld.v31.getDurationUsedStr
import com.android.permissioncontroller.permission.ui.handheld.v31.getTimeDiffStr
import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.TimeUnit
import org.junit.Test
import org.junit.runner.RunWith
-import java.util.concurrent.TimeUnit
-/**
- * A suite of unit tests to test the permission dashboard utils.
- */
+/** A suite of unit tests to test the permission dashboard utils. */
@RunWith(AndroidJUnit4::class)
class DashboardUtilsTest {
@Test
fun getTimeDiffStr_durationSecondsOne() {
val duration: Long = TimeUnit.SECONDS.toMillis(1L)
- assertThat(
- getTimeDiffStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("1 second")
+ assertThat(getTimeDiffStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("1 second")
}
@Test
fun getTimeDiffStr_durationSecondsOther() {
val duration: Long = TimeUnit.SECONDS.toMillis(59L)
- assertThat(
- getTimeDiffStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("59 seconds")
+ assertThat(getTimeDiffStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("59 seconds")
}
@Test
fun getTimeDiffStr_durationMinutesOne() {
val duration: Long = TimeUnit.MINUTES.toMillis(1L)
- assertThat(
- getTimeDiffStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("1 minute")
+ assertThat(getTimeDiffStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("1 minute")
}
@Test
fun getTimeDiffStr_durationMinutesOther() {
val duration: Long = TimeUnit.MINUTES.toMillis(59L)
- assertThat(
- getTimeDiffStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("59 minutes")
+ assertThat(getTimeDiffStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("59 minutes")
}
@Test
fun getTimeDiffStr_durationHoursOne() {
val duration: Long = TimeUnit.HOURS.toMillis(1L)
- assertThat(
- getTimeDiffStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("1 hour")
+ assertThat(getTimeDiffStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("1 hour")
}
@Test
fun getTimeDiffStr_durationHoursOther() {
val duration: Long = TimeUnit.HOURS.toMillis(23L)
- assertThat(
- getTimeDiffStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("23 hours")
+ assertThat(getTimeDiffStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("23 hours")
}
@Test
fun getTimeDiffStr_durationDaysOne() {
val duration: Long = TimeUnit.DAYS.toMillis(1L)
- assertThat(
- getTimeDiffStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("1 day")
+ assertThat(getTimeDiffStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("1 day")
}
@Test
fun getTimeDiffStr_durationDaysOther() {
val duration: Long = TimeUnit.DAYS.toMillis(2L)
- assertThat(
- getTimeDiffStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("2 days")
+ assertThat(getTimeDiffStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("2 days")
}
@Test
fun getDurationUsedStr_durationSecondsOne() {
val duration: Long = TimeUnit.SECONDS.toMillis(1L)
- assertThat(
- getDurationUsedStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("1 sec")
+ assertThat(getDurationUsedStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("1 sec")
}
@Test
fun getDurationUsedStr_durationSecondsOther() {
val duration: Long = TimeUnit.SECONDS.toMillis(59L)
- assertThat(
- getDurationUsedStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("59 secs")
+ assertThat(getDurationUsedStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("59 secs")
}
@Test
fun getDurationUsedStr_durationMinutesOne() {
val duration: Long = TimeUnit.MINUTES.toMillis(1L)
- assertThat(
- getDurationUsedStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("1 min")
+ assertThat(getDurationUsedStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("1 min")
}
@Test
fun getDurationUsedStr_durationMinutesOther() {
val duration: Long = TimeUnit.MINUTES.toMillis(59L)
- assertThat(
- getDurationUsedStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("59 mins")
+ assertThat(getDurationUsedStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("59 mins")
}
@Test
fun getDurationUsedStr_durationHoursOne() {
val duration: Long = TimeUnit.HOURS.toMillis(1L)
- assertThat(
- getDurationUsedStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("1 hour")
+ assertThat(getDurationUsedStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("1 hour")
}
@Test
fun getDurationUsedStr_durationHoursOther() {
val duration: Long = TimeUnit.HOURS.toMillis(23L)
- assertThat(
- getDurationUsedStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("23 hours")
+ assertThat(getDurationUsedStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("23 hours")
}
@Test
fun getDurationUsedStr_durationDaysOne() {
val duration: Long = TimeUnit.DAYS.toMillis(1L)
- assertThat(
- getDurationUsedStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("1 day")
+ assertThat(getDurationUsedStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("1 day")
}
@Test
fun getDurationUsedStr_durationDaysOther() {
val duration: Long = TimeUnit.DAYS.toMillis(2L)
- assertThat(
- getDurationUsedStr(
- ApplicationProvider.getApplicationContext(),
- duration
- )
- ).isEqualTo("2 days")
- }
-} \ No newline at end of file
+ assertThat(getDurationUsedStr(ApplicationProvider.getApplicationContext(), duration))
+ .isEqualTo("2 days")
+ }
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt
index 0f4216066..899a026c4 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt
@@ -47,26 +47,18 @@ import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-/**
- * Unit tests for [ReviewPermissionsViewModel]
- */
+/** Unit tests for [ReviewPermissionsViewModel] */
@RunWith(AndroidJUnit4::class)
class ReviewPermissionsViewModelTest {
private val testPackageName = "test.package"
- @Mock
- private lateinit var application: PermissionControllerApplication
- @Mock
- private lateinit var permGroup: LightAppPermGroup
- @Mock
- private lateinit var foregroundSubGroup: LightAppPermGroup.AppPermSubGroup
- @Mock
- private lateinit var backgroundSubGroup: LightAppPermGroup.AppPermSubGroup
- @Mock
- private lateinit var admin: RestrictedLockUtils.EnforcedAdmin
- @Mock
- private lateinit var packageManager: PackageManager
+ @Mock private lateinit var application: PermissionControllerApplication
+ @Mock private lateinit var permGroup: LightAppPermGroup
+ @Mock private lateinit var foregroundSubGroup: LightAppPermGroup.AppPermSubGroup
+ @Mock private lateinit var backgroundSubGroup: LightAppPermGroup.AppPermSubGroup
+ @Mock private lateinit var admin: RestrictedLockUtils.EnforcedAdmin
+ @Mock private lateinit var packageManager: PackageManager
private lateinit var mockitoSession: MockitoSession
private lateinit var context: Context
@@ -76,10 +68,12 @@ class ReviewPermissionsViewModelTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(Utils::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(Utils::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
context = ApplicationProvider.getApplicationContext()
val userHandle: UserHandle = android.os.Process.myUserHandle()
@@ -114,9 +108,9 @@ class ReviewPermissionsViewModelTest {
val summary = model.getSummaryForIndividuallyControlledPermGroup(permGroup)
assertEquals(
- ReviewPermissionsViewModel.PermissionSummary(
- SummaryMessage.REVOKED_COUNT, false, 1
- ), summary)
+ ReviewPermissionsViewModel.PermissionSummary(SummaryMessage.REVOKED_COUNT, false, 1),
+ summary
+ )
}
@Test
@@ -124,48 +118,78 @@ class ReviewPermissionsViewModelTest {
whenever(permGroup.isGranted).thenReturn(true)
whenever(foregroundSubGroup.isPolicyFixed).thenReturn(true)
- val summary = model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_FOREGROUND,
- permGroup, context)
+ val summary =
+ model.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_FOREGROUND,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.ENABLED_BY_POLICY_FOREGROUND_ONLY.toPermSummary(), summary)
val spyViewModel = spy(model)
doReturn(admin).`when`(spyViewModel).getAdmin(context, permGroup)
- val summaryAdmin = spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
- PERMISSION_FOREGROUND, permGroup, context)
- assertEquals(SummaryMessage.ENABLED_BY_ADMIN_FOREGROUND_ONLY.toPermSummary(true),
- summaryAdmin)
+ val summaryAdmin =
+ spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_FOREGROUND,
+ permGroup,
+ context
+ )
+ assertEquals(
+ SummaryMessage.ENABLED_BY_ADMIN_FOREGROUND_ONLY.toPermSummary(true),
+ summaryAdmin
+ )
}
@Test
fun getSummary_backgroundFixedPolicy_foregroundRequested() {
whenever(backgroundSubGroup.isPolicyFixed).thenReturn(true)
- val summary = model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_FOREGROUND,
- permGroup, context)
+ val summary =
+ model.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_FOREGROUND,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.DISABLED_BY_POLICY_BACKGROUND_ONLY.toPermSummary(), summary)
val spyViewModel = spy(model)
doReturn(admin).`when`(spyViewModel).getAdmin(context, permGroup)
- val summaryAdmin = spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
- PERMISSION_FOREGROUND, permGroup, context)
- assertEquals(SummaryMessage.DISABLED_BY_ADMIN_BACKGROUND_ONLY.toPermSummary(true),
- summaryAdmin)
+ val summaryAdmin =
+ spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_FOREGROUND,
+ permGroup,
+ context
+ )
+ assertEquals(
+ SummaryMessage.DISABLED_BY_ADMIN_BACKGROUND_ONLY.toPermSummary(true),
+ summaryAdmin
+ )
}
@Test
fun getSummary_backgroundFixedPolicy() {
whenever(backgroundSubGroup.isPolicyFixed).thenReturn(true)
- val summary = model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BACKGROUND,
- permGroup, context)
+ val summary =
+ model.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_BACKGROUND,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.ENABLED_BY_POLICY_BACKGROUND_ONLY.toPermSummary(), summary)
val spyViewModel = spy(model)
doReturn(admin).`when`(spyViewModel).getAdmin(context, permGroup)
- val summaryAdmin = spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
- PERMISSION_BACKGROUND, permGroup, context)
- assertEquals(SummaryMessage.ENABLED_BY_ADMIN_BACKGROUND_ONLY.toPermSummary(true),
- summaryAdmin)
+ val summaryAdmin =
+ spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_BACKGROUND,
+ permGroup,
+ context
+ )
+ assertEquals(
+ SummaryMessage.ENABLED_BY_ADMIN_BACKGROUND_ONLY.toPermSummary(true),
+ summaryAdmin
+ )
}
@Test
@@ -173,14 +197,22 @@ class ReviewPermissionsViewModelTest {
whenever(permGroup.isPolicyFullyFixed).thenReturn(true)
whenever(permGroup.hasBackgroundGroup).thenReturn(true)
- val summary = model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_FOREGROUND,
- permGroup, context)
+ val summary =
+ model.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_FOREGROUND,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.ENABLED_BY_POLICY_BACKGROUND_ONLY.toPermSummary(), summary)
val spyViewModel = spy(model)
doReturn(admin).`when`(spyViewModel).getAdmin(context, permGroup)
- val summaryAdmin = spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
- PERMISSION_FOREGROUND, permGroup, context)
+ val summaryAdmin =
+ spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_FOREGROUND,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.ENABLED_BY_ADMIN_FOREGROUND_ONLY.toPermSummary(), summaryAdmin)
}
@@ -189,14 +221,22 @@ class ReviewPermissionsViewModelTest {
whenever(permGroup.isPolicyFullyFixed).thenReturn(true)
whenever(permGroup.hasBackgroundGroup).thenReturn(true)
- val summary = model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BACKGROUND,
- permGroup, context)
+ val summary =
+ model.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_BACKGROUND,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.ENFORCED_BY_POLICY.toPermSummary(), summary)
val spyViewModel = spy(model)
doReturn(admin).`when`(spyViewModel).getAdmin(context, permGroup)
- val summaryAdmin = spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
- PERMISSION_BACKGROUND, permGroup, context)
+ val summaryAdmin =
+ spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_BACKGROUND,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.ENABLED_BY_ADMIN.toPermSummary(), summaryAdmin)
}
@@ -204,14 +244,18 @@ class ReviewPermissionsViewModelTest {
fun getSummary_fullyFixedPolicy_hasNoBackgroundGroup() {
whenever(permGroup.isPolicyFullyFixed).thenReturn(true)
- val summary = model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BOTH,
- permGroup, context)
+ val summary =
+ model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BOTH, permGroup, context)
assertEquals(SummaryMessage.ENFORCED_BY_POLICY.toPermSummary(), summary)
val spyViewModel = spy(model)
doReturn(admin).`when`(spyViewModel).getAdmin(context, permGroup)
- val summaryAdmin = spyViewModel.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BOTH,
- permGroup, context)
+ val summaryAdmin =
+ spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_BOTH,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.ENABLED_BY_ADMIN.toPermSummary(), summaryAdmin)
}
@@ -220,14 +264,18 @@ class ReviewPermissionsViewModelTest {
whenever(foregroundSubGroup.isPolicyFixed).thenReturn(true)
whenever(permGroup.isGranted).thenReturn(false)
- val summary = model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BOTH,
- permGroup, context)
+ val summary =
+ model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BOTH, permGroup, context)
assertEquals(SummaryMessage.ENFORCED_BY_POLICY.toPermSummary(), summary)
val spyViewModel = spy(model)
doReturn(admin).`when`(spyViewModel).getAdmin(context, permGroup)
- val adminSummary = spyViewModel.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BOTH,
- permGroup, context)
+ val adminSummary =
+ spyViewModel.getSummaryForFixedByPolicyPermissionGroup(
+ PERMISSION_BOTH,
+ permGroup,
+ context
+ )
assertEquals(SummaryMessage.DISABLED_BY_ADMIN.toPermSummary(), adminSummary)
}
@@ -235,8 +283,8 @@ class ReviewPermissionsViewModelTest {
fun getSummary_systemFixedPolicy() {
whenever(permGroup.isSystemFixed).thenReturn(true)
- val summary = model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BOTH,
- permGroup, context)
+ val summary =
+ model.getSummaryForFixedByPolicyPermissionGroup(PERMISSION_BOTH, permGroup, context)
assertEquals(SummaryMessage.ENABLED_SYSTEM_FIXED.toPermSummary(), summary)
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt
index be6518b23..8bd61ebe6 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt
@@ -24,6 +24,7 @@ import android.app.AppOpsManager.MODE_FOREGROUND
import android.app.AppOpsManager.MODE_IGNORED
import android.app.AppOpsManager.permissionToOp
import android.app.Application
+import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED
import android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME
@@ -41,11 +42,13 @@ import android.os.Build
import android.os.UserHandle
import android.permission.PermissionManager
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermGroupInfo
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermInfo
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission
+import com.android.permissioncontroller.permission.utils.ContextCompat
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
@@ -64,7 +67,8 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
-private const val PERMISSION_CONTROLLER_CHANGED_FLAG_MASK = FLAG_PERMISSION_USER_SET or
+private const val PERMISSION_CONTROLLER_CHANGED_FLAG_MASK =
+ FLAG_PERMISSION_USER_SET or
FLAG_PERMISSION_USER_FIXED or
FLAG_PERMISSION_ONE_TIME or
FLAG_PERMISSION_REVOKED_COMPAT or
@@ -101,8 +105,9 @@ class GrantRevokeTests {
}
}
- @Mock
- val app: Application = mock(Application::class.java)
+ @Mock val app: Application = mock(Application::class.java)
+
+ @Mock val context: Context = mock(Context::class.java)
/**
* Create a mock Application object, with a mock packageManager, AppOpsManager, and
@@ -114,16 +119,24 @@ class GrantRevokeTests {
`when`(app.packageManager).thenReturn(mock(PackageManager::class.java))
val aom: AppOpsManager = mock(AppOpsManager::class.java)
+
+ if (SdkLevel.isAtLeastU()) {
+ `when`(context.deviceId).thenReturn(ContextCompat.DEVICE_ID_DEFAULT)
+ }
+ `when`(context.packageManager).thenReturn(mock(PackageManager::class.java))
+ `when`(context.getSystemService(PermissionManager::class.java))
+ .thenReturn(mock(PermissionManager::class.java))
// Return an invalid app op state, so setOpMode will always attempt to change the op state
`when`(aom.unsafeCheckOpRaw(anyString(), anyInt(), nullable(String::class.java)))
.thenReturn(-1)
`when`(app.getSystemService(AppOpsManager::class.java)).thenReturn(aom)
- `when`(app.getSystemService(ActivityManager::class.java)).thenReturn(
- mock(ActivityManager::class.java))
+ `when`(app.getSystemService(ActivityManager::class.java))
+ .thenReturn(mock(ActivityManager::class.java))
- `when`(app.getSystemService(PermissionManager::class.java)).thenReturn(
- mock(PermissionManager::class.java))
+ `when`(app.getSystemService(PermissionManager::class.java))
+ .thenReturn(mock(PermissionManager::class.java))
+ `when`(app.applicationContext).thenReturn(context)
}
/**
@@ -142,19 +155,35 @@ class GrantRevokeTests {
val permFlags = mutableListOf<Int>()
for ((permName, isGranted) in perms) {
permNames.add(permName)
- permFlags.add(if (isGranted) {
- PERMISSION_GRANTED
- } else {
- PERMISSION_DENIED
- })
+ permFlags.add(
+ if (isGranted) {
+ PERMISSION_GRANTED
+ } else {
+ PERMISSION_DENIED
+ }
+ )
}
- return LightPackageInfo(TEST_PACKAGE_NAME, listOf(), permNames, permFlags, TEST_UID,
- if (isPreMApp) {
- Build.VERSION_CODES.LOLLIPOP
- } else {
- Build.VERSION_CODES.R
- }, isInstantApp, isInstantApp, 0, 0L, 0L, false, emptyMap())
+ return LightPackageInfo(
+ TEST_PACKAGE_NAME,
+ listOf(),
+ permNames,
+ permFlags,
+ TEST_UID,
+ if (isPreMApp) {
+ Build.VERSION_CODES.LOLLIPOP
+ } else {
+ Build.VERSION_CODES.R
+ },
+ isInstantApp,
+ isInstantApp,
+ 0,
+ 0L,
+ 0L,
+ false,
+ emptyMap(),
+ ContextCompat.DEVICE_ID_DEFAULT
+ )
}
/**
@@ -163,13 +192,13 @@ class GrantRevokeTests {
* @param pkg Package requesting the permission
* @param permName The name of the permission
* @param granted Whether the permission is granted (should be false if the permission is compat
- * revoked)
+ * revoked)
* @param backgroundPerm The name of this permission's background permission, if there is one
* @param foregroundPerms The names of this permission's foreground permissions, if there are
- * any
+ * any
* @param flags The system permission flags of this permission
* @param permInfoProtectionFlags The flags that the PermissionInfo object has (accessed by
- * PermissionInfo.getProtectionFlags)
+ * PermissionInfo.getProtectionFlags)
*/
private fun createMockPerm(
pkgInfo: LightPackageInfo,
@@ -179,11 +208,24 @@ class GrantRevokeTests {
flags: Int = NO_FLAGS,
permInfoProtectionFlags: Int = 0
): LightPermission {
- val permInfo = LightPermInfo(permName, TEST_PACKAGE_NAME, PERM_GROUP_NAME, backgroundPerm,
- PermissionInfo.PROTECTION_DANGEROUS, permInfoProtectionFlags, 0)
- return LightPermission(pkgInfo, permInfo,
- pkgInfo.requestedPermissionsFlags[pkgInfo.requestedPermissions.indexOf(permName)]
- == PERMISSION_GRANTED, flags, foregroundPerms)
+ val permInfo =
+ LightPermInfo(
+ permName,
+ TEST_PACKAGE_NAME,
+ PERM_GROUP_NAME,
+ backgroundPerm,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ permInfoProtectionFlags,
+ 0
+ )
+ return LightPermission(
+ pkgInfo,
+ permInfo,
+ pkgInfo.requestedPermissionsFlags[pkgInfo.requestedPermissions.indexOf(permName)] ==
+ PERMISSION_GRANTED,
+ flags,
+ foregroundPerms
+ )
}
/**
@@ -201,12 +243,11 @@ class GrantRevokeTests {
}
/**
- * Create a list of strings which usefully states which flags are set in a group of flags.
- * Only checks for flags relevant to granting and revoking (so, for instance, policy fixed is
- * not checked).
+ * Create a list of strings which usefully states which flags are set in a group of flags. Only
+ * checks for flags relevant to granting and revoking (so, for instance, policy fixed is not
+ * checked).
*
* @param flags The flags to check
- *
* @return a list of strings, representing which flags have been set
*/
private fun flagsToString(flags: Int): List<String> {
@@ -251,28 +292,32 @@ class GrantRevokeTests {
val flags = state.second
assertWithMessage("permission $permName grant state incorrect")
- .that(perms[permName]?.isGrantedIncludingAppOp).isEqualTo(granted)
+ .that(perms[permName]?.isGrantedIncludingAppOp)
+ .isEqualTo(granted)
val actualFlags = perms[permName]!!.flags
- assertWithMessage("permission $permName flags incorrect, expected" +
- "${flagsToString(flags)}; got ${flagsToString(actualFlags)}")
- .that(perms[permName]?.flags).isEqualTo(flags)
+ assertWithMessage(
+ "permission $permName flags incorrect, expected" +
+ "${flagsToString(flags)}; got ${flagsToString(actualFlags)}"
+ )
+ .that(perms[permName]?.flags)
+ .isEqualTo(flags)
}
}
/**
- * Verify that permission state was propagated to the system. Verify that grant or revoke
- * were called, if applicable, or verify they weren't. Verify that we have set flags
- * correctly, if applicable, or verify flags were not set.
+ * Verify that permission state was propagated to the system. Verify that grant or revoke were
+ * called, if applicable, or verify they weren't. Verify that we have set flags correctly, if
+ * applicable, or verify flags were not set.
*
* @param permName The name of the permission to verify
* @param expectPermChange Whether or not a permission grant or revoke was expected. If false,
- * verify neither grant nor revoke were called
- * @param expectPermGranted If a permission change was expected, verify that the permission
- * was set to granted (if true) or revoked (if false)
+ * verify neither grant nor revoke were called
+ * @param expectPermGranted If a permission change was expected, verify that the permission was
+ * set to granted (if true) or revoked (if false)
* @param expectedFlags The flags that the system should have set the permission to have
- * @param originalFlags The flags the permission originally had. Used to ensure the correct
- * flag mask was used
+ * @param originalFlags The flags the permission originally had. Used to ensure the correct flag
+ * mask was used
*/
private fun verifyPermissionState(
permName: String,
@@ -281,7 +326,7 @@ class GrantRevokeTests {
expectedFlags: Int = NO_FLAGS,
originalFlags: Int = NO_FLAGS
) {
- val pm = app.packageManager
+ val pm = context.packageManager
if (expectPermChange) {
if (expectPermGranted) {
verify(pm).grantRuntimePermission(TEST_PACKAGE_NAME, permName, TEST_USER)
@@ -294,11 +339,23 @@ class GrantRevokeTests {
}
if (expectedFlags != originalFlags) {
- verify(pm).updatePermissionFlags(permName, TEST_PACKAGE_NAME,
- PERMISSION_CONTROLLER_CHANGED_FLAG_MASK, expectedFlags, TEST_USER)
+ verify(pm)
+ .updatePermissionFlags(
+ permName,
+ TEST_PACKAGE_NAME,
+ PERMISSION_CONTROLLER_CHANGED_FLAG_MASK,
+ expectedFlags,
+ TEST_USER
+ )
} else {
- verify(pm, never()).updatePermissionFlags(eq(permName), eq(TEST_PACKAGE_NAME), anyInt(),
- anyInt(), eq(TEST_USER))
+ verify(pm, never())
+ .updatePermissionFlags(
+ eq(permName),
+ eq(TEST_PACKAGE_NAME),
+ anyInt(),
+ anyInt(),
+ eq(TEST_USER)
+ )
}
}
@@ -308,7 +365,7 @@ class GrantRevokeTests {
*
* @param appOpName The name of the app op to check
* @param expectAppOpSet Whether an app op change was expected. If false, verify setUidMode was
- * not called
+ * not called
* @param expectedMode If a change was expected, the mode the app op should be set to
*/
private fun verifyAppOpState(
@@ -353,8 +410,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_ALLOWED)
verifyAppKillState(shouldBeKilled = false)
@@ -379,17 +440,28 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_ALLOWED)
- verifyPermissionState(permName = FG_PERM_2_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
- verifyAppOpState(appOpName = OP_2_NAME, expectAppOpSet = true,
- expectedMode = MODE_FOREGROUND)
+ verifyPermissionState(
+ permName = FG_PERM_2_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
+ verifyAppOpState(
+ appOpName = OP_2_NAME,
+ expectAppOpSet = true,
+ expectedMode = MODE_FOREGROUND
+ )
verifyAppKillState(shouldBeKilled = false)
- val expectedState = mutableMapOf(FG_PERM_NAME to (true to newFlags),
- FG_PERM_2_NAME to (true to newFlags))
+ val expectedState =
+ mutableMapOf(FG_PERM_NAME to (true to newFlags), FG_PERM_2_NAME to (true to newFlags))
assertGroupPermState(newGroup, expectedState)
}
@@ -408,8 +480,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME_NO_APP_OP, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME_NO_APP_OP,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = false)
verifyAppOpState(appOpName = OP_2_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
@@ -434,14 +510,18 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantBackgroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = BG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = BG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_ALLOWED)
verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = false)
verifyAppKillState(shouldBeKilled = false)
- val expectedState = mutableMapOf(FG_PERM_NAME to (true to NO_FLAGS),
- BG_PERM_NAME to (true to newFlags))
+ val expectedState =
+ mutableMapOf(FG_PERM_NAME to (true to NO_FLAGS), BG_PERM_NAME to (true to newFlags))
assertGroupPermState(newGroup, expectedState)
}
@@ -462,26 +542,34 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyPermissionState(permName = BG_PERM_NAME, expectPermChange = false)
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_FOREGROUND)
verifyAppKillState(shouldBeKilled = false)
- val expectedState = mutableMapOf(FG_PERM_NAME to (true to newFlags),
- BG_PERM_NAME to (false to NO_FLAGS))
+ val expectedState =
+ mutableMapOf(FG_PERM_NAME to (true to newFlags), BG_PERM_NAME to (false to NO_FLAGS))
assertGroupPermState(newGroup, expectedState)
resetMockAppState()
val newGroup2 = KotlinUtils.grantBackgroundRuntimePermissions(app, newGroup)
- verifyPermissionState(permName = BG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = BG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_ALLOWED)
verifyAppKillState(shouldBeKilled = false)
- val expectedState2 = mutableMapOf(FG_PERM_NAME to (true to newFlags),
- BG_PERM_NAME to (true to newFlags))
+ val expectedState2 =
+ mutableMapOf(FG_PERM_NAME to (true to newFlags), BG_PERM_NAME to (true to newFlags))
assertGroupPermState(newGroup2, expectedState2)
}
@@ -495,20 +583,28 @@ class GrantRevokeTests {
val pkg = createMockPackage(mapOf(FG_PERM_NAME to false, BG_PERM_NAME to false))
val perms = mutableMapOf<String, LightPermission>()
val origBgFlags = FLAG_PERMISSION_AUTO_REVOKED
- perms[FG_PERM_NAME] = createMockPerm(
- pkg, FG_PERM_NAME, BG_PERM_NAME, null, FLAG_PERMISSION_AUTO_REVOKED)
- perms[BG_PERM_NAME] = createMockPerm(
- pkg, BG_PERM_NAME, null, listOf(FG_PERM_NAME), origBgFlags)
+ perms[FG_PERM_NAME] =
+ createMockPerm(pkg, FG_PERM_NAME, BG_PERM_NAME, null, FLAG_PERMISSION_AUTO_REVOKED)
+ perms[BG_PERM_NAME] =
+ createMockPerm(pkg, BG_PERM_NAME, null, listOf(FG_PERM_NAME), origBgFlags)
val group = createMockGroup(pkg, perms)
resetMockAppState()
KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
- verifyPermissionState(permName = BG_PERM_NAME, expectPermChange = false,
- expectedFlags = NO_FLAGS, originalFlags = origBgFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
+ verifyPermissionState(
+ permName = BG_PERM_NAME,
+ expectPermChange = false,
+ expectedFlags = NO_FLAGS,
+ originalFlags = origBgFlags
+ )
}
/**
@@ -528,16 +624,24 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_ALLOWED)
- verifyPermissionState(permName = FG_PERM_2_NAME, expectPermChange = false,
- expectedFlags = permFlags, originalFlags = permFlags)
+ verifyPermissionState(
+ permName = FG_PERM_2_NAME,
+ expectPermChange = false,
+ expectedFlags = permFlags,
+ originalFlags = permFlags
+ )
verifyAppOpState(appOpName = OP_2_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
- val expectedState = mutableMapOf(FG_PERM_NAME to (true to newFlags),
- FG_PERM_2_NAME to (false to permFlags))
+ val expectedState =
+ mutableMapOf(FG_PERM_NAME to (true to newFlags), FG_PERM_2_NAME to (false to permFlags))
assertGroupPermState(newGroup, expectedState)
}
@@ -558,25 +662,33 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_FOREGROUND)
verifyAppKillState(shouldBeKilled = false)
- var expectedState = mutableMapOf(FG_PERM_NAME to (true to newFlags),
- BG_PERM_NAME to (false to permFlags))
+ var expectedState =
+ mutableMapOf(FG_PERM_NAME to (true to newFlags), BG_PERM_NAME to (false to permFlags))
assertGroupPermState(newGroup, expectedState)
resetMockAppState()
val newGroup2 = KotlinUtils.grantBackgroundRuntimePermissions(app, newGroup)
- verifyPermissionState(permName = BG_PERM_NAME, expectPermChange = false,
- expectedFlags = permFlags, originalFlags = permFlags)
+ verifyPermissionState(
+ permName = BG_PERM_NAME,
+ expectPermChange = false,
+ expectedFlags = permFlags,
+ originalFlags = permFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
- expectedState = mutableMapOf(FG_PERM_NAME to (true to newFlags),
- BG_PERM_NAME to (false to permFlags))
+ expectedState =
+ mutableMapOf(FG_PERM_NAME to (true to newFlags), BG_PERM_NAME to (false to permFlags))
assertGroupPermState(newGroup2, expectedState)
}
@@ -596,8 +708,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = false,
- expectedFlags = newFlags, originalFlags = oldFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = false,
+ expectedFlags = newFlags,
+ originalFlags = oldFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
@@ -620,8 +736,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = false,
- expectedFlags = newFlags, originalFlags = oldFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = false,
+ expectedFlags = newFlags,
+ originalFlags = oldFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_ALLOWED)
verifyAppKillState(shouldBeKilled = true)
@@ -643,8 +763,12 @@ class GrantRevokeTests {
resetMockAppState()
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = false,
- expectedFlags = flags, originalFlags = flags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = false,
+ expectedFlags = flags,
+ originalFlags = flags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
@@ -652,9 +776,7 @@ class GrantRevokeTests {
assertGroupPermState(newGroup, expectedState)
}
- /**
- * Test that an instant app cannot have regular (non-instant) permission granted.
- */
+ /** Test that an instant app cannot have regular (non-instant) permission granted. */
@Test
fun cantGrantInstantAppStandardPermTest() {
val pkg = createMockPackage(mapOf(FG_PERM_NAME to false), isInstantApp = true)
@@ -680,8 +802,12 @@ class GrantRevokeTests {
fun cantGrantPreRuntimeAppWithRuntimeOnlyPermTest() {
val pkg = createMockPackage(mapOf(FG_PERM_NAME to false), isPreMApp = true)
val perms = mutableMapOf<String, LightPermission>()
- perms[FG_PERM_NAME] = createMockPerm(pkg, FG_PERM_NAME,
- permInfoProtectionFlags = PROTECTION_FLAG_RUNTIME_ONLY)
+ perms[FG_PERM_NAME] =
+ createMockPerm(
+ pkg,
+ FG_PERM_NAME,
+ permInfoProtectionFlags = PROTECTION_FLAG_RUNTIME_ONLY
+ )
val group = createMockGroup(pkg, perms)
resetMockAppState()
@@ -695,23 +821,25 @@ class GrantRevokeTests {
assertGroupPermState(newGroup, expectedState)
}
- /**
- * Test that an instant package can have an instant permission granted.
- */
+ /** Test that an instant package can have an instant permission granted. */
@Test
fun grantInstantAppInstantPermTest() {
val pkg = createMockPackage(mapOf(FG_PERM_NAME to false), isInstantApp = true)
val perms = mutableMapOf<String, LightPermission>()
- perms[FG_PERM_NAME] = createMockPerm(pkg, FG_PERM_NAME,
- permInfoProtectionFlags = PROTECTION_FLAG_INSTANT)
+ perms[FG_PERM_NAME] =
+ createMockPerm(pkg, FG_PERM_NAME, permInfoProtectionFlags = PROTECTION_FLAG_INSTANT)
val group = createMockGroup(pkg, perms)
resetMockAppState()
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = true, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = true,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_ALLOWED)
verifyAppKillState(shouldBeKilled = false)
@@ -719,9 +847,7 @@ class GrantRevokeTests {
assertGroupPermState(newGroup, expectedState)
}
- /**
- * Test that granting a permission clears the user fixed and review required flags.
- */
+ /** Test that granting a permission clears the user fixed and review required flags. */
@Test
fun grantClearsUserFixedAndReviewRequired() {
val pkg = createMockPackage(mapOf(FG_PERM_NAME to true))
@@ -733,8 +859,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = false,
- expectedFlags = newFlags, originalFlags = oldFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = false,
+ expectedFlags = newFlags,
+ originalFlags = oldFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
@@ -742,9 +872,7 @@ class GrantRevokeTests {
assertGroupPermState(newGroup, expectedState)
}
- /**
- * Test revoking one foreground permission. The permission and app op should be revoked.
- */
+ /** Test revoking one foreground permission. The permission and app op should be revoked. */
@Test
fun revokeOnePermTest() {
val pkg = createMockPackage(mapOf(FG_PERM_NAME to true))
@@ -756,8 +884,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = false)
@@ -765,9 +897,7 @@ class GrantRevokeTests {
assertGroupPermState(newGroup, expectedState)
}
- /**
- * Test revoking two foreground permissions. Both permissions and app ops should be revoked.
- */
+ /** Test revoking two foreground permissions. Both permissions and app ops should be revoked. */
@Test
fun revokeTwoPermTest() {
val pkg = createMockPackage(mapOf(FG_PERM_NAME to true, FG_PERM_2_NAME to true))
@@ -780,16 +910,24 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
- verifyPermissionState(permName = FG_PERM_2_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_2_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_2_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = false)
- val expectedState = mutableMapOf(FG_PERM_NAME to (false to newFlags),
- FG_PERM_2_NAME to (false to newFlags))
+ val expectedState =
+ mutableMapOf(FG_PERM_NAME to (false to newFlags), FG_PERM_2_NAME to (false to newFlags))
assertGroupPermState(newGroup, expectedState)
}
@@ -807,8 +945,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME_NO_APP_OP, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME_NO_APP_OP,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = false)
verifyAppOpState(appOpName = OP_2_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
@@ -834,13 +976,17 @@ class GrantRevokeTests {
val newFlags = FLAG_PERMISSION_USER_SET
verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = false)
- verifyPermissionState(permName = BG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = BG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_FOREGROUND)
verifyAppKillState(shouldBeKilled = false)
- val expectedState = mutableMapOf(FG_PERM_NAME to (true to NO_FLAGS),
- BG_PERM_NAME to (false to newFlags))
+ val expectedState =
+ mutableMapOf(FG_PERM_NAME to (true to NO_FLAGS), BG_PERM_NAME to (false to newFlags))
assertGroupPermState(newGroup, expectedState)
}
@@ -861,24 +1007,32 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeBackgroundRuntimePermissions(app, group, true)
val newFlags = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED
- verifyPermissionState(permName = BG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = BG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_FOREGROUND)
verifyAppKillState(shouldBeKilled = false)
- val expectedState = mutableMapOf(FG_PERM_NAME to (true to NO_FLAGS),
- BG_PERM_NAME to (false to newFlags))
+ val expectedState =
+ mutableMapOf(FG_PERM_NAME to (true to NO_FLAGS), BG_PERM_NAME to (false to newFlags))
assertGroupPermState(newGroup, expectedState)
resetMockAppState()
val newGroup2 = KotlinUtils.revokeForegroundRuntimePermissions(app, newGroup, true)
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = false)
- val expectedState2 = mutableMapOf(FG_PERM_NAME to (false to newFlags),
- BG_PERM_NAME to (false to newFlags))
+ val expectedState2 =
+ mutableMapOf(FG_PERM_NAME to (false to newFlags), BG_PERM_NAME to (false to newFlags))
assertGroupPermState(newGroup2, expectedState2)
}
@@ -899,15 +1053,19 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyPermissionState(permName = FG_PERM_2_NAME, expectPermChange = false)
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppOpState(appOpName = OP_2_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
- val expectedState = mutableMapOf(FG_PERM_NAME to (false to newFlags),
- FG_PERM_2_NAME to (true to permFlags))
+ val expectedState =
+ mutableMapOf(FG_PERM_NAME to (false to newFlags), FG_PERM_2_NAME to (true to permFlags))
assertGroupPermState(newGroup, expectedState)
}
@@ -928,13 +1086,17 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = false)
- var expectedState = mutableMapOf(FG_PERM_NAME to (false to newFlags),
- BG_PERM_NAME to (true to permFlags))
+ var expectedState =
+ mutableMapOf(FG_PERM_NAME to (false to newFlags), BG_PERM_NAME to (true to permFlags))
assertGroupPermState(newGroup, expectedState)
resetMockAppState()
@@ -944,14 +1106,14 @@ class GrantRevokeTests {
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
- expectedState = mutableMapOf(FG_PERM_NAME to (false to newFlags),
- BG_PERM_NAME to (true to permFlags))
+ expectedState =
+ mutableMapOf(FG_PERM_NAME to (false to newFlags), BG_PERM_NAME to (true to permFlags))
assertGroupPermState(newGroup2, expectedState)
}
/**
- * Test revoking a one time granted permission. The permission should be revoked, but no
- * longer be one time.
+ * Test revoking a one time granted permission. The permission should be revoked, but no longer
+ * be one time.
*/
@Test
fun revokeOneTimeTest() {
@@ -965,8 +1127,13 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags, originalFlags = oldFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags,
+ originalFlags = oldFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = false)
@@ -975,8 +1142,8 @@ class GrantRevokeTests {
}
/**
- * Test compat revoking (permission granted, app op denied) permission. The app op
- * should be revoked, while the permission remains granted. The app should also be killed.
+ * Test compat revoking (permission granted, app op denied) permission. The app op should be
+ * revoked, while the permission remains granted. The app should also be killed.
*/
@Test
fun revokePreMAppTest() {
@@ -989,8 +1156,11 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_REVOKED_COMPAT
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = false,
- expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = true)
@@ -1036,8 +1206,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group, true)
val newFlags = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = false)
@@ -1062,8 +1236,13 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags, originalFlags = oldFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags,
+ originalFlags = oldFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = false)
@@ -1087,8 +1266,13 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group, true)
val newFlags = oldFlags or FLAG_PERMISSION_USER_FIXED
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = true,
- expectPermGranted = false, expectedFlags = newFlags, originalFlags = oldFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = true,
+ expectPermGranted = false,
+ expectedFlags = newFlags,
+ originalFlags = oldFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = true, expectedMode = MODE_IGNORED)
verifyAppKillState(shouldBeKilled = false)
@@ -1097,8 +1281,8 @@ class GrantRevokeTests {
}
/**
- * Test revoking an already revoked permission, while changing its user fixed state from true
- * to false. The user fixed should update, but the state should stay the same otherwise.
+ * Test revoking an already revoked permission, while changing its user fixed state from true to
+ * false. The user fixed should update, but the state should stay the same otherwise.
*/
@Test
fun changeUserFixedTest() {
@@ -1112,8 +1296,12 @@ class GrantRevokeTests {
val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group)
val newFlags = FLAG_PERMISSION_USER_SET
- verifyPermissionState(permName = FG_PERM_NAME, expectPermChange = false,
- expectedFlags = newFlags, originalFlags = oldFlags)
+ verifyPermissionState(
+ permName = FG_PERM_NAME,
+ expectPermChange = false,
+ expectedFlags = newFlags,
+ originalFlags = oldFlags
+ )
verifyAppOpState(appOpName = OP_NAME, expectAppOpSet = false)
verifyAppKillState(shouldBeKilled = false)
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/StringUtilsTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/StringUtilsTest.kt
index 178f5d56b..2af19480d 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/StringUtilsTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/StringUtilsTest.kt
@@ -16,62 +16,64 @@
package com.android.permissioncontroller.tests.mocking.permission.utils
-import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.utils.StringUtils
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.permissioncontroller.permission.utils.StringUtils
+import com.android.permissioncontroller.tests.mocking.R
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
-/**
- * A suite of unit tests to test the permission dashboard utils.
- */
+/** A suite of unit tests to test the permission dashboard utils. */
@RunWith(AndroidJUnit4::class)
class StringUtilsTest {
@Test
fun getIcuPluralsString_one_noArguments() {
assertThat(
- StringUtils.getIcuPluralsString(
- ApplicationProvider.getApplicationContext(),
- R.string.test_icu_plural,
- 1
+ StringUtils.getIcuPluralsString(
+ ApplicationProvider.getApplicationContext(),
+ R.string.test_icu_plural,
+ 1
+ )
)
- ).isEqualTo("1 test")
+ .isEqualTo("1 test")
}
@Test
fun getIcuPluralsString_other_noArguments() {
assertThat(
- StringUtils.getIcuPluralsString(
- ApplicationProvider.getApplicationContext(),
- R.string.test_icu_plural,
- 2
+ StringUtils.getIcuPluralsString(
+ ApplicationProvider.getApplicationContext(),
+ R.string.test_icu_plural,
+ 2
+ )
)
- ).isEqualTo("2 tests")
+ .isEqualTo("2 tests")
}
@Test
fun getIcuPluralsString_one_additionalArguments() {
assertThat(
- StringUtils.getIcuPluralsString(
- ApplicationProvider.getApplicationContext(),
- R.string.test_icu_plural_with_argument,
- 1,
- "with argument"
+ StringUtils.getIcuPluralsString(
+ ApplicationProvider.getApplicationContext(),
+ R.string.test_icu_plural_with_argument,
+ 1,
+ "with argument"
+ )
)
- ).isEqualTo("1 test with argument")
+ .isEqualTo("1 test with argument")
}
@Test
fun getIcuPluralsString_other_additionalArguments() {
assertThat(
- StringUtils.getIcuPluralsString(
- ApplicationProvider.getApplicationContext(),
- R.string.test_icu_plural_with_argument,
- 2,
- "with argument"
+ StringUtils.getIcuPluralsString(
+ ApplicationProvider.getApplicationContext(),
+ R.string.test_icu_plural_with_argument,
+ 2,
+ "with argument"
+ )
)
- ).isEqualTo("2 tests with argument")
+ .isEqualTo("2 tests with argument")
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AccessibilitySourceServiceTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AccessibilitySourceServiceTest.kt
index 2fcf4a24d..f794ab0d3 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AccessibilitySourceServiceTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AccessibilitySourceServiceTest.kt
@@ -33,8 +33,8 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
-import org.junit.runner.RunWith
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
@@ -53,8 +53,7 @@ import org.mockito.quality.Strictness
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
class AccessibilitySourceServiceTest {
- @Mock
- lateinit var jobService: AccessibilityJobService
+ @Mock lateinit var jobService: AccessibilityJobService
private lateinit var context: Context
private lateinit var mockitoSession: MockitoSession
private lateinit var accessibilitySourceService: AccessibilitySourceService
@@ -66,9 +65,11 @@ class AccessibilitySourceServiceTest {
MockitoAnnotations.initMocks(this)
context = ApplicationProvider.getApplicationContext()
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(DeviceConfig::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
accessibilitySourceService = runWithShellPermissionIdentity {
AccessibilitySourceService(context)
@@ -91,10 +92,9 @@ class AccessibilitySourceServiceTest {
runWithShellPermissionIdentity {
runBlocking {
- accessibilitySourceService.processAccessibilityJob(
- jobParameters,
- jobService
- ) { shouldCancel }
+ accessibilitySourceService.processAccessibilityJob(jobParameters, jobService) {
+ shouldCancel
+ }
}
}
verify(jobService).jobFinished(jobParameters, true)
@@ -103,9 +103,7 @@ class AccessibilitySourceServiceTest {
@Test
fun markServiceAsNotified() {
val a11yService = ComponentName("com.test.package", "AccessibilityService")
- runBlocking {
- accessibilitySourceService.markServiceAsNotified(a11yService)
- }
+ runBlocking { accessibilitySourceService.markServiceAsNotified(a11yService) }
val storedServices = getNotifiedServices()
assertThat(storedServices.size).isEqualTo(1)
@@ -143,9 +141,7 @@ class AccessibilitySourceServiceTest {
val allServices = listOf(a11yService, a11yService2, a11yService3)
val notifiedServices = runBlocking {
- allServices.forEach {
- accessibilitySourceService.markServiceAsNotified(it)
- }
+ allServices.forEach { accessibilitySourceService.markServiceAsNotified(it) }
accessibilitySourceService.removeFromNotifiedServices(a11yService2)
getNotifiedServices()
}
@@ -164,9 +160,7 @@ class AccessibilitySourceServiceTest {
val testComponents = listOf(testComponent, testComponent2, testComponent3)
val notifiedServices = runBlocking {
- testComponents.forEach {
- accessibilitySourceService.markServiceAsNotified(it)
- }
+ testComponents.forEach { accessibilitySourceService.markServiceAsNotified(it) }
accessibilitySourceService.removePackageState(testComponent.packageName)
getNotifiedServices()
}
@@ -182,9 +176,7 @@ class AccessibilitySourceServiceTest {
val testComponents = listOf(testComponent, testComponent2)
val notifiedServices = runBlocking {
- testComponents.forEach {
- accessibilitySourceService.markServiceAsNotified(it)
- }
+ testComponents.forEach { accessibilitySourceService.markServiceAsNotified(it) }
accessibilitySourceService.removePackageState(testComponent.packageName)
getNotifiedServices()
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AppDataSharingUpdatesPrivacySourceTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AppDataSharingUpdatesPrivacySourceTest.kt
index b1b5694ff..d09b5093f 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AppDataSharingUpdatesPrivacySourceTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AppDataSharingUpdatesPrivacySourceTest.kt
@@ -82,7 +82,10 @@ class AppDataSharingUpdatesPrivacySourceTest {
.startMocking()
whenever(
Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java), eq(SafetyCenterManager::class.java)))
+ any(ContextWrapper::class.java),
+ eq(SafetyCenterManager::class.java)
+ )
+ )
.thenReturn(mockSafetyCenterManager)
appDataSharingUpdatesPrivacySource = AppDataSharingUpdatesPrivacySource()
@@ -116,7 +119,10 @@ class AppDataSharingUpdatesPrivacySourceTest {
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_ID)
appDataSharingUpdatesPrivacySource.rescanAndPushSafetyCenterData(
- context, refreshIntent, EVENT_REFRESH_REQUESTED)
+ context,
+ refreshIntent,
+ EVENT_REFRESH_REQUESTED
+ )
val expectedSafetySourceData: SafetySourceData =
SafetySourceData.Builder()
@@ -124,14 +130,18 @@ class AppDataSharingUpdatesPrivacySourceTest {
SafetySourceStatus.Builder(
DATA_SHARING_UPDATES_TITLE,
DATA_SHARING_UPDATES_SUMMARY,
- SafetySourceData.SEVERITY_LEVEL_INFORMATION)
+ SafetySourceData.SEVERITY_LEVEL_INFORMATION
+ )
.setPendingIntent(
PendingIntent.getActivity(
context,
/* requestCode= */ 0,
Intent(ACTION_REVIEW_APP_DATA_SHARING_UPDATES),
- FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE))
- .build())
+ FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
+ )
+ )
+ .build()
+ )
.build()
val expectedSafetyEvent =
SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
@@ -139,7 +149,10 @@ class AppDataSharingUpdatesPrivacySourceTest {
.build()
verify(mockSafetyCenterManager)
.setSafetySourceData(
- APP_DATA_SHARING_UPDATES_SOURCE_ID, expectedSafetySourceData, expectedSafetyEvent)
+ APP_DATA_SHARING_UPDATES_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent
+ )
}
@Test
@@ -148,7 +161,10 @@ class AppDataSharingUpdatesPrivacySourceTest {
val bootCompleteIntent = Intent(ACTION_BOOT_COMPLETED)
appDataSharingUpdatesPrivacySource.rescanAndPushSafetyCenterData(
- context, bootCompleteIntent, EVENT_DEVICE_REBOOTED)
+ context,
+ bootCompleteIntent,
+ EVENT_DEVICE_REBOOTED
+ )
val expectedSafetyEvent = SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
verify(mockSafetyCenterManager)
@@ -163,7 +179,10 @@ class AppDataSharingUpdatesPrivacySourceTest {
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_ID)
appDataSharingUpdatesPrivacySource.rescanAndPushSafetyCenterData(
- context, refreshIntent, EVENT_REFRESH_REQUESTED)
+ context,
+ refreshIntent,
+ EVENT_REFRESH_REQUESTED
+ )
val expectedSafetyEvent =
SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
@@ -190,7 +209,9 @@ class AppDataSharingUpdatesPrivacySourceTest {
DeviceConfig.getBoolean(
eq(NAMESPACE_PRIVACY),
eq(SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED),
- anyBoolean()))
+ anyBoolean()
+ )
+ )
.thenReturn(enabled)
}
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerCheckInternalTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerCheckInternalTest.kt
index 6f1d2c5c9..bc00d3bc8 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerCheckInternalTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerCheckInternalTest.kt
@@ -95,7 +95,9 @@ class NotificationListenerCheckInternalTest {
// Setup Safety Center
doReturn(mockSafetyCenterManager).`when` {
Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java), eq(SafetyCenterManager::class.java))
+ any(ContextWrapper::class.java),
+ eq(SafetyCenterManager::class.java)
+ )
}
notificationListenerCheck = runWithShellPermissionIdentity {
@@ -121,7 +123,9 @@ class NotificationListenerCheckInternalTest {
runWithShellPermissionIdentity {
runBlocking {
notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded(
- jobParameters, mockNotificationListenerCheckJobService)
+ jobParameters,
+ mockNotificationListenerCheckJobService
+ )
}
}
@@ -135,7 +139,9 @@ class NotificationListenerCheckInternalTest {
runWithShellPermissionIdentity {
runBlocking {
notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded(
- jobParameters, mockNotificationListenerCheckJobService)
+ jobParameters,
+ mockNotificationListenerCheckJobService
+ )
}
}
@@ -149,7 +155,9 @@ class NotificationListenerCheckInternalTest {
runWithShellPermissionIdentity {
runBlocking {
notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded(
- jobParameters, mockNotificationListenerCheckJobService)
+ jobParameters,
+ mockNotificationListenerCheckJobService
+ )
}
}
@@ -157,7 +165,8 @@ class NotificationListenerCheckInternalTest {
.setSafetySourceData(
eq(SC_NLS_SOURCE_ID),
any(SafetySourceData::class.java),
- any(SafetyEvent::class.java))
+ any(SafetyEvent::class.java)
+ )
}
@Test
@@ -185,7 +194,8 @@ class NotificationListenerCheckInternalTest {
val updatedNlsComponents = runWithShellPermissionIdentity {
runBlocking {
notificationListenerCheck.removeDisabledComponentsFromNotifiedComponents(
- updatedEnabledComponents)
+ updatedEnabledComponents
+ )
getNotifiedComponents()
}
}
@@ -445,7 +455,9 @@ class NotificationListenerCheckInternalTest {
val testAppLabel = "TestApp Label"
doReturn(PackageInfo().apply { applicationInfo = ApplicationInfo() }).`when` {
Utils.getPackageInfoForComponentName(
- any(Context::class.java), any(ComponentName::class.java))
+ any(Context::class.java),
+ any(ComponentName::class.java)
+ )
}
doReturn(testAppLabel).`when` {
Utils.getApplicationLabel(any(Context::class.java), any(ApplicationInfo::class.java))
@@ -453,7 +465,8 @@ class NotificationListenerCheckInternalTest {
val safetySourceIssue =
Preconditions.checkNotNull(
- notificationListenerCheck.createSafetySourceIssue(testComponent, 0))
+ notificationListenerCheck.createSafetySourceIssue(testComponent, 0)
+ )
val expectedId = "notification_listener_${testComponent.flattenToString()}"
val expectedTitle =
@@ -470,21 +483,28 @@ class NotificationListenerCheckInternalTest {
}
val expectedDismissPendingIntent =
PendingIntent.getBroadcast(
- context, 0, expectedDismissIntent, PendingIntent.FLAG_IMMUTABLE)
+ context,
+ 0,
+ expectedDismissIntent,
+ PendingIntent.FLAG_IMMUTABLE
+ )
val expectedAction1 =
SafetySourceIssue.Action.Builder(
SC_NLS_DISABLE_ACTION_ID,
context.getString(R.string.notification_listener_remove_access_button_label),
- getDisableNlsPendingIntent(context, expectedId, testComponent))
+ getDisableNlsPendingIntent(context, expectedId, testComponent)
+ )
.setWillResolve(true)
.setSuccessMessage(
- context.getString(R.string.notification_listener_remove_access_success_label))
+ context.getString(R.string.notification_listener_remove_access_success_label)
+ )
.build()
val expectedAction2 =
SafetySourceIssue.Action.Builder(
NotificationListenerCheckInternal.SC_SHOW_NLS_SETTINGS_ACTION_ID,
context.getString(R.string.notification_listener_review_app_button_label),
- getNotificationListenerSettingsPendingIntent(context, testComponent))
+ getNotificationListenerSettingsPendingIntent(context, testComponent)
+ )
.build()
assertThat(safetySourceIssue.id).isEqualTo(expectedId)
@@ -501,9 +521,7 @@ class NotificationListenerCheckInternalTest {
@Test
fun exemptPackagesNotInitializedUntilUsed() {
assertThat(notificationListenerCheck.exemptPackagesDelegate.isInitialized()).isFalse()
- runWithShellPermissionIdentity {
- notificationListenerCheck.exemptPackages
- }
+ runWithShellPermissionIdentity { notificationListenerCheck.exemptPackages }
assertThat(notificationListenerCheck.exemptPackagesDelegate.isInitialized()).isTrue()
}
@@ -542,7 +560,8 @@ class NotificationListenerCheckInternalTest {
identifier = componentName.flattenToString()
putExtra(
Settings.EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME,
- componentName.flattenToString())
+ componentName.flattenToString()
+ )
}
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPregrantsTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPregrantsTest.kt
index d8d4b3866..55419ca3d 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPregrantsTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPregrantsTest.kt
@@ -47,9 +47,11 @@ class NotificationListenerPregrantsTest {
MockitoAnnotations.initMocks(this)
context = ApplicationProvider.getApplicationContext()
- mockitoSession = ExtendedMockito.mockitoSession()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
.mockStatic(Utils::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ .strictness(Strictness.LENIENT)
+ .startMocking()
notificationListenerPregrants = NotificationListenerPregrants(context)
}
@@ -71,4 +73,4 @@ class NotificationListenerPregrantsTest {
notificationListenerPregrants.pregrantedPackages
assertTrue(notificationListenerPregrants.pregrantedPackagesDelegate.isInitialized())
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPrivacySourceTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPrivacySourceTest.kt
index 9c1edb795..cc3b096a8 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPrivacySourceTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPrivacySourceTest.kt
@@ -37,10 +37,10 @@ import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.permissioncontroller.Constants.NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID
-import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.privacysources.NotificationListenerPrivacySource
+import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.privacysources.NotificationListenerCheckInternal
+import com.android.permissioncontroller.privacysources.NotificationListenerPrivacySource
import com.android.permissioncontroller.privacysources.PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED
import com.android.permissioncontroller.privacysources.SC_NLS_SOURCE_ID
import com.android.permissioncontroller.privacysources.SafetyCenterReceiver
@@ -53,27 +53,23 @@ import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-import org.mockito.MockitoSession
-import org.mockito.quality.Strictness
import org.mockito.Mockito.never
-import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
class NotificationListenerPrivacySourceTest {
private lateinit var mockitoSession: MockitoSession
- @Mock
- lateinit var mockSafetyCenterManager: SafetyCenterManager
- @Mock
- lateinit var mockNotificationManager: NotificationManager
- @Mock
- lateinit var mockRoleManager: RoleManager
- @Mock
- lateinit var mockUserManager: UserManager
+ @Mock lateinit var mockSafetyCenterManager: SafetyCenterManager
+ @Mock lateinit var mockNotificationManager: NotificationManager
+ @Mock lateinit var mockRoleManager: RoleManager
+ @Mock lateinit var mockUserManager: UserManager
private lateinit var context: Context
private lateinit var notificationListenerCheck: NotificationListenerCheckInternal
@@ -92,66 +88,89 @@ class NotificationListenerPrivacySourceTest {
MockitoAnnotations.initMocks(this)
context = ApplicationProvider.getApplicationContext()
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(DeviceConfig::class.java)
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(Utils::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(DeviceConfig::class.java)
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(Utils::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
// Setup default flagging
setNotificationListenerCheckEnabled(true)
// Setup contexts
- whenever(Utils.getParentUserContext(any(ContextWrapper::class.java)))
- .thenReturn(context)
+ whenever(Utils.getParentUserContext(any(ContextWrapper::class.java))).thenReturn(context)
// Setup package manager and mocked NLS packages
val packageInfo1 = getPackageInfo()
val packageInfo2 = getPackageInfo()
- whenever(Utils.getPackageInfoForComponentName(
- any(ContextWrapper::class.java),
- eq(testComponent1)))
+ whenever(
+ Utils.getPackageInfoForComponentName(
+ any(ContextWrapper::class.java),
+ eq(testComponent1)
+ )
+ )
.thenReturn(packageInfo1)
- whenever(Utils.getPackageInfoForComponentName(
- any(ContextWrapper::class.java),
- eq(testComponent2)))
+ whenever(
+ Utils.getPackageInfoForComponentName(
+ any(ContextWrapper::class.java),
+ eq(testComponent2)
+ )
+ )
.thenReturn(packageInfo2)
- whenever(Utils.getApplicationLabel(
- any(ContextWrapper::class.java),
- eq(packageInfo1.applicationInfo)))
+ whenever(
+ Utils.getApplicationLabel(
+ any(ContextWrapper::class.java),
+ eq(packageInfo1.applicationInfo!!)
+ )
+ )
.thenReturn(testComponent1.className)
- whenever(Utils.getApplicationLabel(
- any(ContextWrapper::class.java),
- eq(packageInfo2.applicationInfo)))
+ whenever(
+ Utils.getApplicationLabel(
+ any(ContextWrapper::class.java),
+ eq(packageInfo2.applicationInfo!!)
+ )
+ )
.thenReturn(testComponent2.className)
// Setup UserManager and User
- whenever(Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java),
- eq(UserManager::class.java)))
+ whenever(
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java),
+ eq(UserManager::class.java)
+ )
+ )
.thenReturn(mockUserManager)
- whenever(mockUserManager.getProfileParent(any(UserHandle::class.java)))
- .thenReturn(null)
+ whenever(mockUserManager.getProfileParent(any(UserHandle::class.java))).thenReturn(null)
// Setup Notification Manager
- whenever(Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java),
- eq(NotificationManager::class.java)))
+ whenever(
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java),
+ eq(NotificationManager::class.java)
+ )
+ )
.thenReturn(mockNotificationManager)
whenever(mockNotificationManager.enabledNotificationListeners)
.thenReturn(listOf(testComponent1, testComponent2))
- whenever(Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java),
- eq(RoleManager::class.java)))
+ whenever(
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java),
+ eq(RoleManager::class.java)
+ )
+ )
.thenReturn(mockRoleManager)
- whenever(mockRoleManager.getRoleHolders(anyString()))
- .thenReturn(emptyList())
+ whenever(mockRoleManager.getRoleHolders(anyString())).thenReturn(emptyList())
// Setup Safety Center
- whenever(Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java),
- eq(SafetyCenterManager::class.java)))
+ whenever(
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java),
+ eq(SafetyCenterManager::class.java)
+ )
+ )
.thenReturn(mockSafetyCenterManager)
// Init NotificationListenerCheckInternal, used to quickly create expected SafetySourceData
@@ -167,24 +186,21 @@ class NotificationListenerPrivacySourceTest {
@Test
fun safetyCenterEnabledChanged_removesNotifications() {
- runWithShellPermissionIdentity {
- privacySource.safetyCenterEnabledChanged(context, false)
- }
+ runWithShellPermissionIdentity { privacySource.safetyCenterEnabledChanged(context, false) }
verify(mockNotificationManager).cancel(NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID)
}
@Test
fun safetyCenterEnabledChanged_doesNotUpdateSafetyCenterData() {
- runWithShellPermissionIdentity {
- privacySource.safetyCenterEnabledChanged(context, false)
- }
+ runWithShellPermissionIdentity { privacySource.safetyCenterEnabledChanged(context, false) }
verify(mockSafetyCenterManager, never())
.setSafetySourceData(
eq(SC_NLS_SOURCE_ID),
any(SafetySourceData::class.java),
- any(SafetyEvent::class.java))
+ any(SafetyEvent::class.java)
+ )
}
@Test
@@ -209,18 +225,17 @@ class NotificationListenerPrivacySourceTest {
SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
verify(mockSafetyCenterManager)
- .setSafetySourceData(
- SC_NLS_SOURCE_ID,
- expectedSafetySourceData,
- expectedSafetyEvent
- )
+ .setSafetySourceData(SC_NLS_SOURCE_ID, expectedSafetySourceData, expectedSafetyEvent)
}
@Test
fun rescanAndPushSafetyCenterData_updatesSafetyCenterEventRefresh() {
- val intent = Intent(SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES)
- .putExtra(SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID,
- SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ val intent =
+ Intent(SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES)
+ .putExtra(
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID,
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
+ )
privacySource.rescanAndPushSafetyCenterData(
context,
intent,
@@ -237,11 +252,7 @@ class NotificationListenerPrivacySourceTest {
.build()
verify(mockSafetyCenterManager)
- .setSafetySourceData(
- SC_NLS_SOURCE_ID,
- expectedSafetySourceData,
- expectedSafetyEvent
- )
+ .setSafetySourceData(SC_NLS_SOURCE_ID, expectedSafetySourceData, expectedSafetyEvent)
}
@Test
@@ -257,16 +268,11 @@ class NotificationListenerPrivacySourceTest {
SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
verify(mockSafetyCenterManager)
- .setSafetySourceData(
- SC_NLS_SOURCE_ID,
- expectedSafetySourceData,
- expectedSafetyEvent
- )
+ .setSafetySourceData(SC_NLS_SOURCE_ID, expectedSafetySourceData, expectedSafetyEvent)
}
@Test
- fun rescanAndPushSafetyCenterData_notificationListenerCheckDisabled_noSafetyCenterInteractions
- () {
+ fun rescanAndPushSafetyCenterData_notificationListenerCheckDisabled_noSafetyCenterInteractions() {
setNotificationListenerCheckEnabled(false)
privacySource.rescanAndPushSafetyCenterData(
@@ -280,18 +286,17 @@ class NotificationListenerPrivacySourceTest {
private fun setNotificationListenerCheckEnabled(enabled: Boolean) {
whenever(
- DeviceConfig.getBoolean(
- eq(DeviceConfig.NAMESPACE_PRIVACY),
- eq(PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED),
- anyBoolean()
+ DeviceConfig.getBoolean(
+ eq(DeviceConfig.NAMESPACE_PRIVACY),
+ eq(PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED),
+ anyBoolean()
+ )
)
- ).thenReturn(enabled)
+ .thenReturn(enabled)
}
private fun getPackageInfo(): PackageInfo {
- return PackageInfo().apply {
- applicationInfo = ApplicationInfo()
- }
+ return PackageInfo().apply { applicationInfo = ApplicationInfo() }
}
private fun createExpectedSafetyCenterData(): SafetySourceData {
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/SafetyCenterReceiverTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/SafetyCenterReceiverTest.kt
index b4b1abd96..6a45ac7c4 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/SafetyCenterReceiverTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/SafetyCenterReceiverTest.kt
@@ -38,7 +38,6 @@ import com.android.permissioncontroller.privacysources.PrivacySource
import com.android.permissioncontroller.privacysources.SafetyCenterReceiver
import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_DEVICE_REBOOTED
import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_REFRESH_REQUESTED
-import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
@@ -48,7 +47,6 @@ import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
@@ -56,16 +54,14 @@ import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-/**
- * Unit tests for [SafetyCenterReceiver]
- */
+/** Unit tests for [SafetyCenterReceiver] */
@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
@@ -80,48 +76,50 @@ class SafetyCenterReceiverTest {
private val testCoroutineDispatcher = TestCoroutineDispatcher()
- @Mock
- lateinit var mockSafetyCenterManager: SafetyCenterManager
- @Mock
- lateinit var mockPackageManager: PackageManager
- @Mock
- lateinit var mockPrivacySource: PrivacySource
- @Mock
- lateinit var mockPrivacySource2: PrivacySource
- @Mock
- lateinit var mockUserManager: UserManager
+ @Mock lateinit var mockSafetyCenterManager: SafetyCenterManager
+ @Mock lateinit var mockPackageManager: PackageManager
+ @Mock lateinit var mockPrivacySource: PrivacySource
+ @Mock lateinit var mockPrivacySource2: PrivacySource
+ @Mock lateinit var mockUserManager: UserManager
private lateinit var mockitoSession: MockitoSession
private lateinit var safetyCenterReceiver: SafetyCenterReceiver
- private fun privacySourceMap(context: Context) = mapOf(
- TEST_PRIVACY_SOURCE_ID to mockPrivacySource,
- TEST_PRIVACY_SOURCE_ID_2 to mockPrivacySource2
- )
+ private fun privacySourceMap(context: Context) =
+ mapOf(
+ TEST_PRIVACY_SOURCE_ID to mockPrivacySource,
+ TEST_PRIVACY_SOURCE_ID_2 to mockPrivacySource2
+ )
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(DeviceConfig::class.java)
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(Utils::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(DeviceConfig::class.java)
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(Utils::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
whenever(PermissionControllerApplication.get()).thenReturn(application)
whenever(application.applicationContext).thenReturn(application)
whenever(application.packageManager).thenReturn(mockPackageManager)
whenever(mockSafetyCenterManager.isSafetyCenterEnabled).thenReturn(true)
whenever(
- Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java), eq(UserManager::class.java)
- ))
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java),
+ eq(UserManager::class.java)
+ )
+ )
.thenReturn(mockUserManager)
whenever(
- Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java), eq(SafetyCenterManager::class.java)
- ))
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java),
+ eq(SafetyCenterManager::class.java)
+ )
+ )
.thenReturn(mockSafetyCenterManager)
whenever(mockUserManager.isProfile).thenReturn(false)
@@ -140,12 +138,13 @@ class SafetyCenterReceiverTest {
private fun mockQSTileSettingsFlag() {
whenever(
- DeviceConfig.getInt(
- eq(DeviceConfig.NAMESPACE_PRIVACY),
- eq(SafetyCenterQsTileService.QS_TILE_COMPONENT_SETTING_FLAGS),
- ArgumentMatchers.anyInt()
+ DeviceConfig.getInt(
+ eq(DeviceConfig.NAMESPACE_PRIVACY),
+ eq(SafetyCenterQsTileService.QS_TILE_COMPONENT_SETTING_FLAGS),
+ ArgumentMatchers.anyInt()
+ )
)
- ).thenReturn(PackageManager.DONT_KILL_APP)
+ .thenReturn(PackageManager.DONT_KILL_APP)
}
@Test
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/TextStorageRepositoryTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/TextStorageRepositoryTest.kt
index 15b9168ad..6c824122c 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/TextStorageRepositoryTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/TextStorageRepositoryTest.kt
@@ -25,6 +25,9 @@ import androidx.test.filters.SdkSuppress
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.permissioncontroller.privacysources.PrivacySourceData
import com.android.permissioncontroller.privacysources.TextStorageRepository
+import java.io.BufferedWriter
+import java.io.File
+import java.io.FileWriter
import org.junit.After
import org.junit.Assert
import org.junit.Before
@@ -33,9 +36,6 @@ import org.junit.runner.RunWith
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.BufferedWriter
-import java.io.File
-import java.io.FileWriter
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
@@ -50,9 +50,11 @@ class TextStorageRepositoryTest {
MockitoAnnotations.initMocks(this)
context = ApplicationProvider.getApplicationContext()
- mockitoSession = ExtendedMockito.mockitoSession()
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
.mockStatic(DeviceConfig::class.java)
- .strictness(Strictness.LENIENT).startMocking()
+ .strictness(Strictness.LENIENT)
+ .startMocking()
dataFile = context.getFileStreamPath("testFile")
}
@@ -83,10 +85,12 @@ class TextStorageRepositoryTest {
@Test
fun testWrite_MultipleEntries() {
val storageRepository = TextStorageRepository(dataFile)
- val components = listOf(TestPrivacySourceComponent("a", 100),
+ val components =
+ listOf(
+ TestPrivacySourceComponent("a", 100),
TestPrivacySourceComponent("b", 200),
TestPrivacySourceComponent("c", 300)
- )
+ )
storageRepository.persistData(components)
val dataList = storageRepository.readData(creator)
Assert.assertEquals(3, dataList.size)
@@ -95,10 +99,12 @@ class TextStorageRepositoryTest {
@Test
fun testRead_Ignore_CorruptedEntries() {
val storageRepository = TextStorageRepository(dataFile)
- val components = listOf(TestPrivacySourceComponent("a", 100),
- TestPrivacySourceComponent("b", 200),
- TestPrivacySourceComponent("c", 300)
- )
+ val components =
+ listOf(
+ TestPrivacySourceComponent("a", 100),
+ TestPrivacySourceComponent("b", 200),
+ TestPrivacySourceComponent("c", 300)
+ )
storageRepository.persistData(components)
appendCorruptedData(dataFile, "not_enough_parts")
appendCorruptedData(dataFile, "not_enough_parts")
@@ -110,9 +116,8 @@ class TextStorageRepositoryTest {
@Test
fun testRead_Ignore_NumberFormatError() {
val storageRepository = TextStorageRepository(dataFile)
- val components = listOf(TestPrivacySourceComponent("a", 100),
- TestPrivacySourceComponent("b", 200)
- )
+ val components =
+ listOf(TestPrivacySourceComponent("a", 100), TestPrivacySourceComponent("b", 200))
storageRepository.persistData(components)
appendCorruptedData(dataFile, "com.example.TestService hundred")
appendCorruptedData(dataFile, "com.example.TestService1 abc")
@@ -128,19 +133,18 @@ class TextStorageRepositoryTest {
}
}
- private val creator = object : PrivacySourceData.Creator<TestPrivacySourceComponent> {
- override fun fromStorageData(data: String): TestPrivacySourceComponent {
- val lineComponents = data.split(" ")
- return TestPrivacySourceComponent(lineComponents[0], lineComponents[1].toInt())
+ private val creator =
+ object : PrivacySourceData.Creator<TestPrivacySourceComponent> {
+ override fun fromStorageData(data: String): TestPrivacySourceComponent {
+ val lineComponents = data.split(" ")
+ return TestPrivacySourceComponent(lineComponents[0], lineComponents[1].toInt())
+ }
}
- }
}
-class TestPrivacySourceComponent(
- private val name: String,
- private val timestamp: Int
-) : PrivacySourceData {
+class TestPrivacySourceComponent(private val name: String, private val timestamp: Int) :
+ PrivacySourceData {
override fun toStorageData(): String {
return "$name $timestamp"
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/WorkPolicyInfoTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/WorkPolicyInfoTest.kt
index 3e86d58b0..bbbf0e86a 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/WorkPolicyInfoTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/WorkPolicyInfoTest.kt
@@ -85,24 +85,34 @@ class WorkPolicyInfoTest {
val application = Mockito.mock(PermissionControllerApplication::class.java)
whenever(
Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java), eq(UserManager::class.java)))
+ any(ContextWrapper::class.java),
+ eq(UserManager::class.java)
+ )
+ )
.thenReturn(mockUserManager)
whenever(
Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java), eq(SafetyCenterManager::class.java)))
+ any(ContextWrapper::class.java),
+ eq(SafetyCenterManager::class.java)
+ )
+ )
.thenReturn(mockSafetyCenterManager)
whenever(mockUserManager.isProfile).thenReturn(false)
whenever(
Utils.getEnterpriseString(
any(ContextWrapper::class.java),
eq(WorkPolicyInfo.WORK_POLICY_TITLE),
- anyInt()))
+ anyInt()
+ )
+ )
.thenReturn(WORK_POLICY_TITLE)
whenever(
Utils.getEnterpriseString(
any(ContextWrapper::class.java),
eq(WorkPolicyInfo.WORK_POLICY_SUMMARY),
- anyInt()))
+ anyInt()
+ )
+ )
.thenReturn(WORK_POLICY_SUMMARY)
whenever(PermissionControllerApplication.get()).thenReturn(application)
@@ -121,7 +131,8 @@ class WorkPolicyInfoTest {
Intent(Intent.ACTION_BOOT_COMPLETED)
.putExtra(
SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID,
- SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
+ )
whenever(mockWorkPolicyUtils.workPolicyInfoIntentDO).thenReturn(intent)
whenever(mockWorkPolicyUtils.workPolicyInfoIntentPO).thenReturn(null)
@@ -134,7 +145,8 @@ class WorkPolicyInfoTest {
SafetySourceStatus.Builder(
WORK_POLICY_TITLE,
WORK_POLICY_SUMMARY,
- SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
+ )
.setPendingIntent(pendingIntent)
.build()
val expectedSafetySourceData: SafetySourceData =
@@ -146,7 +158,8 @@ class WorkPolicyInfoTest {
.setSafetySourceData(
WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
expectedSafetySourceData,
- expectedSafetyEvent)
+ expectedSafetyEvent
+ )
}
@Test
@@ -170,7 +183,8 @@ class WorkPolicyInfoTest {
.setSafetySourceData(
WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
expectedSafetySourceData,
- expectedSafetyEvent)
+ expectedSafetyEvent
+ )
}
@Test
@@ -189,7 +203,10 @@ class WorkPolicyInfoTest {
whenever(mockWorkPolicyUtils.workPolicyInfoIntentPO).thenReturn(null)
workPolicyInfo.rescanAndPushSafetyCenterData(
- context, intent, RefreshEvent.EVENT_DEVICE_REBOOTED)
+ context,
+ intent,
+ RefreshEvent.EVENT_DEVICE_REBOOTED
+ )
val pendingIntent =
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
@@ -197,7 +214,8 @@ class WorkPolicyInfoTest {
SafetySourceStatus.Builder(
WORK_POLICY_TITLE,
WORK_POLICY_SUMMARY,
- SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
+ )
.setPendingIntent(pendingIntent)
.build()
@@ -210,7 +228,8 @@ class WorkPolicyInfoTest {
.setSafetySourceData(
WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
expectedSafetySourceData,
- expectedSafetyEvent)
+ expectedSafetyEvent
+ )
}
@Test
@@ -219,13 +238,17 @@ class WorkPolicyInfoTest {
Intent(Intent.ACTION_BOOT_COMPLETED)
.putExtra(
SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID,
- SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
+ )
whenever(mockWorkPolicyUtils.workPolicyInfoIntentDO).thenReturn(intent)
whenever(mockWorkPolicyUtils.workPolicyInfoIntentPO).thenReturn(null)
workPolicyInfo.rescanAndPushSafetyCenterData(
- context, intent, RefreshEvent.EVENT_REFRESH_REQUESTED)
+ context,
+ intent,
+ RefreshEvent.EVENT_REFRESH_REQUESTED
+ )
val pendingIntent =
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
@@ -233,7 +256,8 @@ class WorkPolicyInfoTest {
SafetySourceStatus.Builder(
WORK_POLICY_TITLE,
WORK_POLICY_SUMMARY,
- SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
+ )
.setPendingIntent(pendingIntent)
.build()
@@ -251,7 +275,8 @@ class WorkPolicyInfoTest {
.setSafetySourceData(
WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
expectedSafetySourceData,
- expectedSafetyEvent)
+ expectedSafetyEvent
+ )
}
@Test
@@ -270,7 +295,8 @@ class WorkPolicyInfoTest {
SafetySourceStatus.Builder(
WORK_POLICY_TITLE,
WORK_POLICY_SUMMARY,
- SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
+ )
.setPendingIntent(pendingIntent)
.build()
@@ -283,7 +309,8 @@ class WorkPolicyInfoTest {
.setSafetySourceData(
WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
expectedSafetySourceData,
- expectedSafetyEvent)
+ expectedSafetyEvent
+ )
}
@Test
@@ -302,6 +329,7 @@ class WorkPolicyInfoTest {
.setSafetySourceData(
WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
expectedSafetySourceData,
- expectedSafetyEvent)
+ expectedSafetyEvent
+ )
}
}
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 34ea6fcf0..ca0392716 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
@@ -22,6 +22,9 @@ import android.safetycenter.SafetyCenterData
import android.safetycenter.SafetyCenterEntryGroup
import android.safetycenter.SafetyCenterEntryOrGroup
import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK
+import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION
import android.safetycenter.SafetyCenterStatus
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
@@ -209,6 +212,44 @@ class SafetyCenterUiDataTest {
assertThat(result).isEmpty()
}
+ @Test
+ fun getMatchingDismissedIssues_doesntReturnGreenIssues() {
+ val greenDismissedIssue =
+ createSafetyCenterIssue(
+ "id1",
+ MATCHING_GROUP_ID,
+ severityLevel = ISSUE_SEVERITY_LEVEL_OK
+ )
+ val yellowDismissedIssue =
+ createSafetyCenterIssue(
+ "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)
+ val safetyCenterData =
+ createSafetyCenterData(
+ dismissedIssues =
+ listOf(
+ redDismissedIssue,
+ yellowDismissedIssue,
+ greenDismissedIssue,
+ nonMatchingDismissedIssue
+ ),
+ )
+
+ val result =
+ SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).containsExactly(redDismissedIssue, yellowDismissedIssue).inOrder()
+ }
+
private companion object {
const val MATCHING_GROUP_ID = "matching_group_id"
const val NON_MATCHING_GROUP_ID = "non_matching_group_id"
@@ -238,8 +279,13 @@ class SafetyCenterUiDataTest {
fun createSafetyCenterEntryGroup(groupId: String) =
SafetyCenterEntryGroup.Builder(groupId, "group title").build()
- fun createSafetyCenterIssue(issueId: String, groupId: String) =
+ fun createSafetyCenterIssue(
+ issueId: String,
+ groupId: String,
+ severityLevel: Int = ISSUE_SEVERITY_LEVEL_RECOMMENDATION
+ ) =
SafetyCenterIssue.Builder(issueId, "issue title", "issue summary")
+ .setSeverityLevel(severityLevel)
.setGroupId(groupId)
.build()
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/StatusUiDataTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/StatusUiDataTest.kt
index d963fd535..2b9f6b8d2 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/StatusUiDataTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/StatusUiDataTest.kt
@@ -72,8 +72,8 @@ class StatusUiDataTest {
assertThat(StatusUiData(STATUS).originalSummary).isEqualTo(STATUS.summary)
assertThat(StatusUiData(ANOTHER_STATUS).originalSummary).isEqualTo(ANOTHER_STATUS.summary)
assertThat(
- StatusUiData(SafetyCenterData(STATUS, listOf(), listOf(), listOf()))
- .originalSummary)
+ StatusUiData(SafetyCenterData(STATUS, listOf(), listOf(), listOf())).originalSummary
+ )
.isEqualTo(STATUS.summary)
}
@@ -83,7 +83,8 @@ class StatusUiDataTest {
assertThat(StatusUiData(ANOTHER_STATUS).severityLevel)
.isEqualTo(ANOTHER_STATUS.severityLevel)
assertThat(
- StatusUiData(SafetyCenterData(STATUS, listOf(), listOf(), listOf())).severityLevel)
+ StatusUiData(SafetyCenterData(STATUS, listOf(), listOf(), listOf())).severityLevel
+ )
.isEqualTo(STATUS.severityLevel)
}
@@ -114,7 +115,9 @@ class StatusUiDataTest {
mockContext.getString(
R.string.safety_status_preference_title_and_summary_content_description,
STATUS.title,
- STATUS.summary))
+ STATUS.summary
+ )
+ )
.thenReturn(expectedContentDescription)
val actualContentDescription = StatusUiData(STATUS).getContentDescription(mockContext)
@@ -163,14 +166,16 @@ class StatusUiDataTest {
@Test
fun isRefreshInProgress_dataFetch_isTrue() {
assertThat(
- uiDataForRefreshStatus(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS).isRefreshInProgress)
+ uiDataForRefreshStatus(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS).isRefreshInProgress
+ )
.isTrue()
}
@Test
fun isRefreshInProgress_fullRescan_isTrue() {
assertThat(
- uiDataForRefreshStatus(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS).isRefreshInProgress)
+ uiDataForRefreshStatus(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS).isRefreshInProgress
+ )
.isTrue()
}
@@ -185,8 +190,10 @@ class StatusUiDataTest {
StatusUiData(
statusForSeverity(OVERALL_SEVERITY_LEVEL_OK),
hasIssues = false,
- hasPendingActions = false)
- .shouldShowRescanButton())
+ hasPendingActions = false
+ )
+ .shouldShowRescanButton()
+ )
.isTrue()
}
@@ -196,8 +203,10 @@ class StatusUiDataTest {
StatusUiData(
statusForSeverity(OVERALL_SEVERITY_LEVEL_UNKNOWN),
hasIssues = false,
- hasPendingActions = false)
- .shouldShowRescanButton())
+ hasPendingActions = false
+ )
+ .shouldShowRescanButton()
+ )
.isTrue()
}
@@ -207,8 +216,10 @@ class StatusUiDataTest {
StatusUiData(
statusForSeverity(OVERALL_SEVERITY_LEVEL_OK),
hasIssues = true,
- hasPendingActions = false)
- .shouldShowRescanButton())
+ hasPendingActions = false
+ )
+ .shouldShowRescanButton()
+ )
.isFalse()
}
@@ -218,8 +229,10 @@ class StatusUiDataTest {
StatusUiData(
statusForSeverity(OVERALL_SEVERITY_LEVEL_OK),
hasIssues = false,
- hasPendingActions = true)
- .shouldShowRescanButton())
+ hasPendingActions = true
+ )
+ .shouldShowRescanButton()
+ )
.isFalse()
}
@@ -227,13 +240,17 @@ class StatusUiDataTest {
fun shouldShowRescanButton_severityNotOkOrUnknown_isFalse() {
for (severity in
listOf(
- OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING, OVERALL_SEVERITY_LEVEL_RECOMMENDATION)) {
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING,
+ OVERALL_SEVERITY_LEVEL_RECOMMENDATION
+ )) {
assertThat(
StatusUiData(
statusForSeverity(severity),
hasIssues = false,
- hasPendingActions = false)
- .shouldShowRescanButton())
+ hasPendingActions = false
+ )
+ .shouldShowRescanButton()
+ )
.isFalse()
}
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryPersistenceTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryPersistenceTest.kt
index 10221f6fa..ff91677b8 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryPersistenceTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryPersistenceTest.kt
@@ -113,7 +113,9 @@ class AppsSafetyLabelHistoryPersistenceTest {
val appsSafetyLabelHistory =
AppsSafetyLabelHistory(
listOf(
- AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))))
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
@@ -128,7 +130,10 @@ class AppsSafetyLabelHistoryPersistenceTest {
AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
@@ -145,7 +150,9 @@ class AppsSafetyLabelHistoryPersistenceTest {
val appsSafetyLabelHistory =
AppsSafetyLabelHistory(
listOf(
- AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))))
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).version).isEqualTo(0)
@@ -156,9 +163,13 @@ class AppsSafetyLabelHistoryPersistenceTest {
val appsSafetyLabelHistory =
AppsSafetyLabelHistory(
listOf(
- AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))))
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(
- dataFile, AppsSafetyLabelHistoryFileContent(appsSafetyLabelHistory, 5))
+ dataFile,
+ AppsSafetyLabelHistoryFileContent(appsSafetyLabelHistory, 5)
+ )
assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).version).isEqualTo(5)
}
@@ -174,7 +185,12 @@ class AppsSafetyLabelHistoryPersistenceTest {
AppsSafetyLabelHistory(
listOf(
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)))))
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1)
+ )
+ )
+ )
+ )
}
@Test
@@ -182,7 +198,9 @@ class AppsSafetyLabelHistoryPersistenceTest {
val appsSafetyLabelHistory =
AppsSafetyLabelHistory(
listOf(
- AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1))))
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1))
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_2_V1, dataFile)
@@ -192,9 +210,16 @@ class AppsSafetyLabelHistoryPersistenceTest {
AppsSafetyLabelHistory(
listOf(
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)),
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1)
+ ),
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V1)))))
+ AppInfo(PACKAGE_NAME_2),
+ listOf(SAFETY_LABEL_PKG_2_V1)
+ )
+ )
+ )
+ )
}
@Test
@@ -205,7 +230,10 @@ class AppsSafetyLabelHistoryPersistenceTest {
AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_2_V3, dataFile)
@@ -215,13 +243,20 @@ class AppsSafetyLabelHistoryPersistenceTest {
AppsSafetyLabelHistory(
listOf(
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)),
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1)
+ ),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
listOf(
SAFETY_LABEL_PKG_2_V1,
SAFETY_LABEL_PKG_2_V2,
- SAFETY_LABEL_PKG_2_V3)))))
+ SAFETY_LABEL_PKG_2_V3
+ )
+ )
+ )
+ )
+ )
}
@Test
@@ -238,7 +273,11 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3)))))
+ listOf(SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3)
+ )
+ )
+ )
+ )
}
@Test
@@ -249,7 +288,10 @@ class AppsSafetyLabelHistoryPersistenceTest {
AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V2)),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_1_V3, dataFile)
@@ -264,7 +306,9 @@ class AppsSafetyLabelHistoryPersistenceTest {
AppsSafetyLabelHistory(
listOf(
AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)),
- AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V1))))
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V1))
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
AppsSafetyLabelHistoryPersistence.recordSafetyLabels(
@@ -272,8 +316,10 @@ class AppsSafetyLabelHistoryPersistenceTest {
SAFETY_LABEL_PKG_1_V2,
SAFETY_LABEL_PKG_2_V2,
SAFETY_LABEL_PKG_2_V3,
- SAFETY_LABEL_PKG_3_V1),
- dataFile)
+ SAFETY_LABEL_PKG_3_V1
+ ),
+ dataFile
+ )
assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
.isEqualTo(
@@ -281,16 +327,23 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)
+ ),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
listOf(
SAFETY_LABEL_PKG_2_V1,
SAFETY_LABEL_PKG_2_V2,
- SAFETY_LABEL_PKG_2_V3)),
+ SAFETY_LABEL_PKG_2_V3
+ )
+ ),
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_3), listOf(SAFETY_LABEL_PKG_3_V1)),
- )))
+ AppInfo(PACKAGE_NAME_3),
+ listOf(SAFETY_LABEL_PKG_3_V1)
+ ),
+ )
+ )
+ )
}
@Test
@@ -308,7 +361,9 @@ class AppsSafetyLabelHistoryPersistenceTest {
val appsSafetyLabelHistory =
AppsSafetyLabelHistory(
listOf(
- AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1))))
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1))
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
val safetyLabelDiffs: List<AppSafetyLabelDiff> =
@@ -324,7 +379,10 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2))))
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
val safetyLabelDiffs: List<AppSafetyLabelDiff> =
@@ -340,7 +398,10 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3))))
+ listOf(SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
val safetyLabelDiffs: List<AppSafetyLabelDiff> =
@@ -357,11 +418,14 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)
+ ),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(
- SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
val safetyLabelDiffs =
@@ -371,7 +435,9 @@ class AppsSafetyLabelHistoryPersistenceTest {
.isEqualTo(
listOf(
AppSafetyLabelDiff(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2),
- AppSafetyLabelDiff(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V3)))
+ AppSafetyLabelDiff(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V3)
+ )
+ )
}
@Test
@@ -389,11 +455,14 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)
+ ),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(
- SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
val lastUpdatedTimes =
@@ -403,7 +472,9 @@ class AppsSafetyLabelHistoryPersistenceTest {
.isEqualTo(
mapOf(
AppInfo(PACKAGE_NAME_1) to DATE_2022_10_14,
- AppInfo(PACKAGE_NAME_2) to DATE_2022_12_30))
+ AppInfo(PACKAGE_NAME_2) to DATE_2022_12_30
+ )
+ )
}
@Test
@@ -413,14 +484,20 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)
+ ),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
AppsSafetyLabelHistoryPersistence.deleteSafetyLabelsForApps(
- setOf(AppInfo(PACKAGE_NAME_2)), dataFile)
+ setOf(AppInfo(PACKAGE_NAME_2)),
+ dataFile
+ )
assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
.isEqualTo(
@@ -428,7 +505,11 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)))))
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)
+ )
+ )
+ )
+ )
}
@Test
@@ -438,11 +519,14 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(
- SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)
+ ),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
AppsSafetyLabelHistoryPersistence.deleteSafetyLabelsOlderThan(DATE_2022_12_30, dataFile)
@@ -452,9 +536,16 @@ class AppsSafetyLabelHistoryPersistenceTest {
AppsSafetyLabelHistory(
listOf(
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V3)),
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V3)
+ ),
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2)))))
+ AppInfo(PACKAGE_NAME_2),
+ listOf(SAFETY_LABEL_PKG_2_V2)
+ )
+ )
+ )
+ )
}
@Test
@@ -464,11 +555,14 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(
- SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)
+ ),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2)
+ )
+ )
+ )
AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
AppsSafetyLabelHistoryPersistence.deleteSafetyLabelsOlderThan(DATE_2022_10_14, dataFile)
@@ -479,10 +573,15 @@ class AppsSafetyLabelHistoryPersistenceTest {
listOf(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)),
+ listOf(SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)
+ ),
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_2),
- listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2)))))
+ listOf(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V2)
+ )
+ )
+ )
+ )
}
@Test
@@ -531,7 +630,9 @@ class AppsSafetyLabelHistoryPersistenceTest {
DeviceConfig.getInt(
eq(NAMESPACE_PRIVACY),
eq(PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP),
- anyInt()))
+ anyInt()
+ )
+ )
.thenReturn(max)
}
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryTest.kt
index dedb0b1cd..74eba4e4c 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryTest.kt
@@ -49,7 +49,9 @@ class AppsSafetyLabelHistoryTest {
fun createAppSafetyLabelHistory_requiresAllSafetyLabelsHaveSameApp() {
Assert.assertThrows(IllegalArgumentException::class.java) {
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_2_V1))
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_2_V1)
+ )
}
}
@@ -57,7 +59,9 @@ class AppsSafetyLabelHistoryTest {
fun createAppSafetyLabelHistory_requiresOrderedByReceivedAt() {
Assert.assertThrows(IllegalArgumentException::class.java) {
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V1))
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V1)
+ )
}
}
@@ -65,7 +69,9 @@ class AppsSafetyLabelHistoryTest {
fun withSafetyLabel_forDifferentApp_throwsIllegalArgumentException() {
val appSafetyLabelHistory =
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V3))
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V3)
+ )
Assert.assertThrows(IllegalArgumentException::class.java) {
appSafetyLabelHistory.withSafetyLabel(SAFETY_LABEL_PKG_2_V1, 20)
@@ -76,25 +82,34 @@ class AppsSafetyLabelHistoryTest {
fun withSafetyLabel_returnsOrderdSafetyLabels() {
val appSafetyLabelHistory =
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V3))
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V3)
+ )
assertThat(appSafetyLabelHistory.withSafetyLabel(SAFETY_LABEL_PKG_1_V2, 20))
.isEqualTo(
AppSafetyLabelHistory(
AppInfo(PACKAGE_NAME_1),
- listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)))
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)
+ )
+ )
}
@Test
fun withSafetyLabel_dropsOldLabelsWhenMaxPersisted() {
val appSafetyLabelHistory =
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V3))
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V3)
+ )
assertThat(appSafetyLabelHistory.withSafetyLabel(SAFETY_LABEL_PKG_1_V2, 2))
.isEqualTo(
AppSafetyLabelHistory(
- AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)))
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V3)
+ )
+ )
}
@Test
@@ -105,7 +120,10 @@ class AppsSafetyLabelHistoryTest {
val safetyLabelForPersistence =
SafetyLabel.extractLocationSharingSafetyLabel(
- PACKAGE_NAME_1, DATE_2022_09_01, appMetadataSafetyLabel)
+ PACKAGE_NAME_1,
+ DATE_2022_09_01,
+ appMetadataSafetyLabel
+ )
assertThat(safetyLabelForPersistence)
.isEqualTo(SafetyLabel(AppInfo(PACKAGE_NAME_1), DATE_2022_09_01, DataLabel(mapOf())))
@@ -119,14 +137,19 @@ class AppsSafetyLabelHistoryTest {
val safetyLabelForPersistence =
SafetyLabel.extractLocationSharingSafetyLabel(
- PACKAGE_NAME_1, DATE_2022_10_10, appMetadataSafetyLabel)
+ PACKAGE_NAME_1,
+ DATE_2022_10_10,
+ appMetadataSafetyLabel
+ )
assertThat(safetyLabelForPersistence)
.isEqualTo(
SafetyLabel(
AppInfo(PACKAGE_NAME_1),
DATE_2022_10_10,
- DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(false)))))
+ DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(false)))
+ )
+ )
}
@Test
@@ -137,14 +160,19 @@ class AppsSafetyLabelHistoryTest {
val safetyLabelForPersistence =
SafetyLabel.extractLocationSharingSafetyLabel(
- PACKAGE_NAME_2, DATE_2022_10_10, appMetadataSafetyLabel)
+ PACKAGE_NAME_2,
+ DATE_2022_10_10,
+ appMetadataSafetyLabel
+ )
assertThat(safetyLabelForPersistence)
.isEqualTo(
SafetyLabel(
AppInfo(PACKAGE_NAME_2),
DATE_2022_10_10,
- DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(true)))))
+ DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(true)))
+ )
+ )
}
@Test
@@ -155,7 +183,10 @@ class AppsSafetyLabelHistoryTest {
val safetyLabelForPersistence =
SafetyLabel.extractLocationSharingSafetyLabel(
- PACKAGE_NAME_2, DATE_2022_10_10, appMetadataSafetyLabel)
+ PACKAGE_NAME_2,
+ DATE_2022_10_10,
+ appMetadataSafetyLabel
+ )
assertThat(safetyLabelForPersistence)
.isEqualTo(SafetyLabel(AppInfo(PACKAGE_NAME_2), DATE_2022_10_10, DataLabel(mapOf())))
@@ -170,14 +201,19 @@ class AppsSafetyLabelHistoryTest {
val safetyLabelForPersistence =
SafetyLabel.extractLocationSharingSafetyLabel(
- PACKAGE_NAME_2, DATE_2022_10_10, appMetadataSafetyLabel)
+ PACKAGE_NAME_2,
+ DATE_2022_10_10,
+ appMetadataSafetyLabel
+ )
assertThat(safetyLabelForPersistence)
.isEqualTo(
SafetyLabel(
AppInfo(PACKAGE_NAME_2),
DATE_2022_10_10,
- DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(true)))))
+ DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(true)))
+ )
+ )
}
/** Companion object for [AppsSafetyLabelHistoryTest]. */
@@ -211,8 +247,10 @@ class AppsSafetyLabelHistoryTest {
PersistableBundle().apply {
putIntArray(
PURPOSES_KEY,
- listOf(PURPOSE_FRAUD_PREVENTION_SECURITY).toIntArray())
- })
+ listOf(PURPOSE_FRAUD_PREVENTION_SECURITY).toIntArray()
+ )
+ }
+ )
}
return PersistableBundle().apply {
@@ -227,7 +265,8 @@ class AppsSafetyLabelHistoryTest {
APPROX_LOCATION,
PersistableBundle().apply {
putIntArray(PURPOSES_KEY, listOf(PURPOSE_ADVERTISING).toIntArray())
- })
+ }
+ )
}
return PersistableBundle().apply {
@@ -242,7 +281,8 @@ class AppsSafetyLabelHistoryTest {
FINANCIAL_PURCHASE_HISTORY,
PersistableBundle().apply {
putIntArray(PURPOSES_KEY, listOf(PURPOSE_ADVERTISING).toIntArray())
- })
+ }
+ )
}
return PersistableBundle().apply {
@@ -257,7 +297,8 @@ class AppsSafetyLabelHistoryTest {
APPROX_LOCATION,
PersistableBundle().apply {
putIntArray(PURPOSES_KEY, listOf(PURPOSE_ADVERTISING).toIntArray())
- })
+ }
+ )
}
val financeBundle =
PersistableBundle().apply {
@@ -265,7 +306,8 @@ class AppsSafetyLabelHistoryTest {
FINANCIAL_PURCHASE_HISTORY,
PersistableBundle().apply {
putIntArray(PURPOSES_KEY, listOf(PURPOSE_ADVERTISING).toIntArray())
- })
+ }
+ )
}
return PersistableBundle().apply {
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/SafetyLabelChangesJobServiceTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/SafetyLabelChangesJobServiceTest.kt
index f6395f8ea..4d206a2f4 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/SafetyLabelChangesJobServiceTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/SafetyLabelChangesJobServiceTest.kt
@@ -138,8 +138,8 @@ class SafetyLabelChangesJobServiceTest {
val captor = ArgumentCaptor.forClass(JobInfo::class.java)
verify(mockJobScheduler, times(2)).schedule(captor.capture())
val capturedJobIds = captor.getAllValues()
- assertThat(capturedJobIds[0].id).isEqualTo(
- Constants.SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID)
+ assertThat(capturedJobIds[0].id)
+ .isEqualTo(Constants.SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID)
assertThat(capturedJobIds[1].id)
.isEqualTo(Constants.SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID)
}
@@ -155,7 +155,9 @@ class SafetyLabelChangesJobServiceTest {
DeviceConfig.getBoolean(
eq(DeviceConfig.NAMESPACE_PRIVACY),
eq(SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED),
- anyBoolean()))
+ anyBoolean()
+ )
+ )
.thenReturn(flagValue)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TestSafetyLabels.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TestSafetyLabels.kt
index 19c5adddd..45b57662d 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TestSafetyLabels.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TestSafetyLabels.kt
@@ -42,21 +42,24 @@ object TestSafetyLabels {
SafetyLabel(
AppInfo(PACKAGE_NAME_1),
DATE_2022_09_01,
- DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(true))))
+ DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(true)))
+ )
/** A Safety label for [PACKAGE_NAME_1]. */
val SAFETY_LABEL_PKG_1_V2: SafetyLabel =
SafetyLabel(
AppInfo(PACKAGE_NAME_1),
DATE_2022_10_14,
- DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(false))))
+ DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(false)))
+ )
/** A Safety label for [PACKAGE_NAME_1]. */
val SAFETY_LABEL_PKG_1_V3: SafetyLabel =
SafetyLabel(
AppInfo(PACKAGE_NAME_1),
DATE_2022_12_10,
- DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(false))))
+ DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(false)))
+ )
/** A Safety label for [PACKAGE_NAME_2]. */
val SAFETY_LABEL_PKG_2_V1: SafetyLabel =
@@ -66,7 +69,10 @@ object TestSafetyLabels {
DataLabel(
mapOf(
LOCATION_CATEGORY to DataCategory(true),
- FINANCIAL_CATEGORY to DataCategory(false))))
+ FINANCIAL_CATEGORY to DataCategory(false)
+ )
+ )
+ )
/** A Safety label for [PACKAGE_NAME_2]. */
val SAFETY_LABEL_PKG_2_V2: SafetyLabel =
@@ -77,12 +83,14 @@ object TestSafetyLabels {
SafetyLabel(
AppInfo(PACKAGE_NAME_2),
DATE_2022_12_30,
- DataLabel(mapOf(FINANCIAL_CATEGORY to DataCategory(true))))
+ DataLabel(mapOf(FINANCIAL_CATEGORY to DataCategory(true)))
+ )
/** A Safety label for [PACKAGE_NAME_3]. */
val SAFETY_LABEL_PKG_3_V1: SafetyLabel =
SafetyLabel(
AppInfo(PACKAGE_NAME_3),
DATE_2022_10_10,
- DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(true))))
+ DataLabel(mapOf(LOCATION_CATEGORY to DataCategory(true)))
+ )
}
diff --git a/PermissionController/tests/outofprocess/Android.bp b/PermissionController/tests/outofprocess/Android.bp
index e646def28..acb4ab5bd 100644
--- a/PermissionController/tests/outofprocess/Android.bp
+++ b/PermissionController/tests/outofprocess/Android.bp
@@ -33,7 +33,6 @@ android_test {
srcs: [
"src/**/*.kt",
- ":permissioncontroller-protos",
],
libs: [
@@ -42,11 +41,11 @@ android_test {
],
static_libs: [
+ "permissioncontroller-protos",
"androidx.test.rules",
"androidx.test.ext.truth",
"androidx.test.ext.junit",
"compatibility-device-util-axt",
- "libprotobuf-java-lite",
],
proto: {
diff --git a/PermissionController/tests/outofprocess/src/com/android/permissioncontroller/tests/outofprocess/DumpTest.kt b/PermissionController/tests/outofprocess/src/com/android/permissioncontroller/tests/outofprocess/DumpTest.kt
index 4963a4683..667a307ae 100644
--- a/PermissionController/tests/outofprocess/src/com/android/permissioncontroller/tests/outofprocess/DumpTest.kt
+++ b/PermissionController/tests/outofprocess/src/com/android/permissioncontroller/tests/outofprocess/DumpTest.kt
@@ -20,14 +20,17 @@ import android.os.ParcelFileDescriptor.AutoCloseInputStream
import android.os.UserHandle.myUserId
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.PermissionControllerProto.PermissionControllerDumpProto
import com.google.common.truth.Truth.assertThat
import com.google.protobuf.InvalidProtocolBufferException
+import java.nio.charset.StandardCharsets.UTF_8
import org.junit.Assert.fail
+import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import java.nio.charset.StandardCharsets.UTF_8
@RunWith(AndroidJUnit4::class)
class DumpTest {
@@ -36,8 +39,8 @@ class DumpTest {
private val instrumentation = InstrumentationRegistry.getInstrumentation()
private fun getDump(): PermissionControllerDumpProto {
- val dumpFile = instrumentation.getUiAutomation()
- .executeShellCommand("dumpsys permissionmgr --proto")
+ val dumpFile =
+ instrumentation.getUiAutomation().executeShellCommand("dumpsys permissionmgr --proto")
val dump = AutoCloseInputStream(dumpFile).readBytes()
try {
@@ -48,6 +51,12 @@ class DumpTest {
}
}
+ @Before
+ fun setUp() {
+ // We no longer dump auto revoke data since T.
+ assumeFalse(SdkLevel.isAtLeastT())
+ }
+
@Test
fun autoRevokeDumpHasCurrentUser() {
val dump = getDump()
@@ -66,6 +75,6 @@ class DumpTest {
assumeTrue(dump.autoRevoke.usersList.isNotEmpty())
assertThat(dump.autoRevoke.usersList[myUserId()].packagesList.map { it.packageName })
- .contains(OS_PKG)
+ .contains(OS_PKG)
}
}
diff --git a/PermissionController/tests/permissionui/Android.bp b/PermissionController/tests/permissionui/Android.bp
index 704307c1f..41b5f88ed 100644
--- a/PermissionController/tests/permissionui/Android.bp
+++ b/PermissionController/tests/permissionui/Android.bp
@@ -60,9 +60,12 @@ android_test {
":CtsAppThatRequestsLocationPermission29",
":PermissionUiUseStoragePermissionApp",
":PermissionUiUseCameraPermissionApp",
+ ":PermissionUiUseHealthConnectPermissionApp",
+ ":PermissionUiInvalidUseHealthConnectPermissionApp",
":PermissionUiDefineAdditionalPermissionApp",
":PermissionUiUseAdditionalPermissionApp",
":PermissionUiUseTwoAdditionalPermissionsApp",
+ ":PermissionUiReadCalendarPermissionApp",
],
per_testcase_directory: true,
}
diff --git a/PermissionController/tests/permissionui/AndroidTest.xml b/PermissionController/tests/permissionui/AndroidTest.xml
index 62fc6ed3f..566410777 100644
--- a/PermissionController/tests/permissionui/AndroidTest.xml
+++ b/PermissionController/tests/permissionui/AndroidTest.xml
@@ -31,24 +31,30 @@
<!-- Create place to store apks -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="mkdir -p /data/local/tmp/permissioncontroller/tests/permissionui" />
- <option name="teardown-command" value="rm -rf /data/local/tmp/permissioncontroller/"/>
+ <option name="run-command" value="mkdir -p /data/local/tmp/pc-permissionui" />
+ <option name="teardown-command" value="rm -fr /data/local/tmp/pc-permissionui"/>
</target_preparer>
<!-- Load additional APKs onto device -->
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="push-file" key="CtsAppThatRequestsLocationPermission29.apk"
- value="/data/local/tmp/permissioncontroller/tests/permissionui/AppThatRequestsLocation.apk" />
+ value="/data/local/tmp/pc-permissionui/AppThatRequestsLocation.apk" />
<option name="push-file" key="PermissionUiUseStoragePermissionApp.apk"
- value="/data/local/tmp/permissioncontroller/tests/permissionui/PermissionUiUseStoragePermissionApp.apk" />
+ value="/data/local/tmp/pc-permissionui/PermissionUiUseStoragePermissionApp.apk" />
<option name="push-file" key="PermissionUiUseCameraPermissionApp.apk"
- value="/data/local/tmp/permissioncontroller/tests/permissionui/PermissionUiUseCameraPermissionApp.apk" />
+ value="/data/local/tmp/pc-permissionui/PermissionUiUseCameraPermissionApp.apk" />
+ <option name="push-file" key="PermissionUiUseHealthConnectPermissionApp.apk"
+ value="/data/local/tmp/pc-permissionui/PermissionUiUseHealthConnectPermissionApp.apk" />
+ <option name="push-file" key="PermissionUiInvalidUseHealthConnectPermissionApp.apk"
+ value="/data/local/tmp/pc-permissionui/PermissionUiInvalidUseHealthConnectPermissionApp.apk" />
<option name="push-file" key="PermissionUiDefineAdditionalPermissionApp.apk"
- value="/data/local/tmp/permissioncontroller/tests/permissionui/PermissionUiDefineAdditionalPermissionApp.apk" />
+ value="/data/local/tmp/pc-permissionui/PermissionUiDefineAdditionalPermissionApp.apk" />
<option name="push-file" key="PermissionUiUseAdditionalPermissionApp.apk"
- value="/data/local/tmp/permissioncontroller/tests/permissionui/PermissionUiUseAdditionalPermissionApp.apk" />
+ value="/data/local/tmp/pc-permissionui/PermissionUiUseAdditionalPermissionApp.apk" />
<option name="push-file" key="PermissionUiUseTwoAdditionalPermissionsApp.apk"
- value="/data/local/tmp/permissioncontroller/tests/permissionui/PermissionUiUseTwoAdditionalPermissionsApp.apk" />
+ value="/data/local/tmp/pc-permissionui/PermissionUiUseTwoAdditionalPermissionsApp.apk" />
+ <option name="push-file" key="PermissionUiReadCalendarPermissionApp.apk"
+ value="/data/local/tmp/pc-permissionui/PermissionUiReadCalendarPermissionApp.apk" />
</target_preparer>
<!-- Uninstall test-apps -->
diff --git a/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/Android.bp b/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/Android.bp
new file mode 100644
index 000000000..c366f9a0c
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_modules_Permission_PermissionController_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: [
+ "packages_modules_Permission_PermissionController_license",
+ ],
+}
+
+android_test_helper_app {
+ name: "PermissionUiInvalidUseHealthConnectPermissionApp",
+
+ srcs: ["src/**/*.kt"],
+
+ sdk_version: "34",
+}
diff --git a/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/AndroidManifest.xml b/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/AndroidManifest.xml
new file mode 100644
index 000000000..c5e0f4906
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.permissioncontroller.tests.appthatrequestpermission">
+
+ <uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
+ <uses-permission android:name="android.permission.health.READ_STEPS" />
+
+ <application android:label="HealthConnectRequestApp" />
+</manifest>
+
diff --git a/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt b/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt
new file mode 100644
index 000000000..98089208a
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiInvalidUseHealthConnectPermissionApp/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 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.tests.appthatrequestpermission
+
+import android.app.Activity
+
+class DummyActivity : Activity()
diff --git a/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/Android.bp b/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/Android.bp
new file mode 100644
index 000000000..edb0da6fc
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_modules_Permission_PermissionController_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: [
+ "packages_modules_Permission_PermissionController_license",
+ ],
+}
+
+android_test_helper_app {
+ name: "PermissionUiReadCalendarPermissionApp",
+
+ srcs: ["src/**/*.kt"],
+
+ sdk_version: "30",
+}
diff --git a/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/AndroidManifest.xml b/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/AndroidManifest.xml
new file mode 100644
index 000000000..8ebb502e8
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.permissioncontroller.tests.appthatrequestpermission">
+ <uses-permission android:name="android.permission.READ_CALENDAR"/>
+
+ <attribution android:tag="testTag" android:label="@string/test_attribution_label" />
+
+ <application android:label="CalendarRequestApp" />
+</manifest>
+
diff --git a/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/res/values/strings.xml b/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/res/values/strings.xml
new file mode 100644
index 000000000..91cb8c1fd
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiReadCalendarPermissionApp/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Placeholder attribution label for testing [CHAR LIMIT=32] -->
+ <string name="test_attribution_label">Test Attribution Label</string>
+</resources>
diff --git a/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/Android.bp b/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/Android.bp
new file mode 100644
index 000000000..10788a116
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_modules_Permission_PermissionController_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: [
+ "packages_modules_Permission_PermissionController_license",
+ ],
+}
+
+android_test_helper_app {
+ name: "PermissionUiUseHealthConnectPermissionApp",
+
+ srcs: ["src/**/*.kt"],
+
+ sdk_version: "34",
+}
diff --git a/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/AndroidManifest.xml b/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/AndroidManifest.xml
new file mode 100644
index 000000000..d5903a543
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.permissioncontroller.tests.appthatrequestpermission">
+
+ <uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
+ <uses-permission android:name="android.permission.health.READ_STEPS" />
+
+ <application android:label="HealthConnectRequestApp">
+ <activity android:name=".DummyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW_PERMISSION_USAGE" />
+ <category android:name="android.intent.category.HEALTH_PERMISSIONS" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
+
diff --git a/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt b/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt
new file mode 100644
index 000000000..98089208a
--- /dev/null
+++ b/PermissionController/tests/permissionui/PermissionUiUseHealthConnectPermissionApp/src/com/android/permissioncontroller/tests/appthatrequestpermission/DummyActivity.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 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.tests.appthatrequestpermission
+
+import android.app.Activity
+
+class DummyActivity : Activity()
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionGroupPreferenceUtils.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionGroupPreferenceUtils.kt
index 175b7a701..8e1d6a831 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionGroupPreferenceUtils.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionGroupPreferenceUtils.kt
@@ -26,31 +26,33 @@ private const val SUMMARY_TEXT = "apps allowed"
* Read the {@link UsageCount} of the group of the permission from the Ui.
*
* @param groupLabel label fo the group the count should be read for
- *
* @return usage counts for the group of the permission
*/
fun getUsageCountsFromUi(groupLabel: CharSequence): UsageCount {
waitFindObject(By.text(groupLabel.toString()))
return getEventually {
- val summaryText = waitFindObject(By.hasChild(By.text(groupLabel.toString()))
- .hasChild(By.textContains(SUMMARY_TEXT))).findObject(By.textContains(SUMMARY_TEXT)).text
+ val summaryText =
+ waitFindObject(
+ By.hasChild(By.text(groupLabel.toString()))
+ .hasChild(By.textContains(SUMMARY_TEXT))
+ )
+ .findObject(By.textContains(SUMMARY_TEXT))
+ .text
// Matches two numbers out of the summary line, i.e. "...3...12..." -> "3", "12"
- val groups = Regex("^[^\\d]*(\\d+)[^\\d]*(\\d+)[^\\d]*\$")
- .find(summaryText)?.groupValues
- ?: throw Exception("No usage counts found")
+ val groups =
+ Regex("^[^\\d]*(\\d+)[^\\d]*(\\d+)[^\\d]*\$").find(summaryText)?.groupValues
+ ?: throw Exception("No usage counts found")
UsageCount(groups[1].toInt(), groups[2].toInt())
}
}
-/**
- * Usage counts as read via {@link #getUsageCountsFromUi}.
- */
+/** Usage counts as read via {@link #getUsageCountsFromUi}. */
data class UsageCount(
/** Number of apps with permission granted */
val granted: Int,
/** Number of apps that request permissions */
val total: Int
-) \ No newline at end of file
+)
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionHub2Test.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionHub2Test.kt
index 6f143d2db..ec846d778 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionHub2Test.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionHub2Test.kt
@@ -25,78 +25,49 @@ import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
import android.os.Process.myUserHandle
-import android.provider.DeviceConfig
-import android.provider.DeviceConfig.NAMESPACE_PRIVACY
import androidx.test.platform.app.InstrumentationRegistry
import com.android.compatibility.common.util.SystemUtil.eventually
-import com.android.compatibility.common.util.SystemUtil.runShellCommand
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.google.common.truth.Truth.assertThat
-import org.junit.AfterClass
-import org.junit.BeforeClass
-/**
- * Super class with utilities for testing permission hub 2 code
- */
+/** Super class with utilities for testing permission hub 2 code */
open class PermissionHub2Test {
private val APP = "com.android.permissioncontroller.tests.appthatrequestpermission"
private val instrumentation = InstrumentationRegistry.getInstrumentation()
protected val context = instrumentation.targetContext
- companion object {
- private const val PROPERTY_PERMISSIONS_HUB_2_ENABLED = "permissions_hub_2_enabled"
-
- private var wasPermissionHubEnabled = false
-
- @JvmStatic
- @BeforeClass
- fun enablePermissionHub2() {
-
- runWithShellPermissionIdentity {
- wasPermissionHubEnabled = DeviceConfig.getBoolean(NAMESPACE_PRIVACY,
- PROPERTY_PERMISSIONS_HUB_2_ENABLED, false)
- }
-
- if (!wasPermissionHubEnabled) {
- runShellCommand(
- "device_config put privacy $PROPERTY_PERMISSIONS_HUB_2_ENABLED true")
- }
- }
-
- @JvmStatic
- @AfterClass
- fun disablePermissionHub2() {
- if (!wasPermissionHubEnabled) {
- runShellCommand(
- "device_config put privacy $PROPERTY_PERMISSIONS_HUB_2_ENABLED false")
- }
- }
- }
-
- /**
- * Make {@value #APP} access the camera
- */
+ /** Make {@value #APP} access the camera */
protected fun accessCamera() {
// App needs to be in foreground to be able to access camera
context.startActivity(
- Intent().setComponent(ComponentName.createRelative(APP, ".DummyActivity"))
- .setFlags(FLAG_ACTIVITY_NEW_TASK))
+ Intent()
+ .setComponent(ComponentName.createRelative(APP, ".DummyActivity"))
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ )
runWithShellPermissionIdentity {
eventually {
assertThat(
- context.packageManager.getPermissionFlags(CAMERA, APP, myUserHandle()) and
- FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
- ).isNotEqualTo(0)
+ context.packageManager.getPermissionFlags(CAMERA, APP, myUserHandle()) and
+ FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
+ )
+ .isNotEqualTo(0)
}
eventually {
assertThat(
- context.getSystemService(AppOpsManager::class.java).startOp(
- OPSTR_CAMERA, context.packageManager.getPackageUid(APP, 0), APP, null, null
+ context
+ .getSystemService(AppOpsManager::class.java)
+ .startOp(
+ OPSTR_CAMERA,
+ context.packageManager.getPackageUid(APP, 0),
+ APP,
+ null,
+ null
+ )
)
- ).isEqualTo(MODE_ALLOWED)
+ .isEqualTo(MODE_ALLOWED)
}
}
}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/UiUtils.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/UiUtils.kt
index 25aa79632..fa741d3eb 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/UiUtils.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/UiUtils.kt
@@ -16,12 +16,10 @@
package com.android.permissioncontroller.permissionui
-import androidx.test.uiautomator.UiDevice
import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
-/**
- * Wake up screen
- */
+/** Wake up screen */
fun wakeUpScreen() {
val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@@ -29,9 +27,7 @@ fun wakeUpScreen() {
uiDevice.executeShellCommand("wm dismiss-keyguard")
}
-/**
- * Press the home button
- */
+/** Press the home button */
fun pressHome() {
val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
uiDevice.pressHome()
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AllAppPermissionsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AllAppPermissionsFragmentTest.kt
index d5f574327..6234f6e17 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AllAppPermissionsFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AllAppPermissionsFragmentTest.kt
@@ -19,8 +19,8 @@ package com.android.permissioncontroller.permissionui.ui
import android.content.Intent
import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.uninstallApp
-import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.uiautomator.By
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
@@ -37,23 +37,18 @@ private const val MORE_OPTIONS = "More options"
private const val ALL_PERMISSIONS = "All permissions"
/**
- * Simple tests for {@link AllAppPermissionsFragment}
- * Currently, does NOT run on TV.
- * TODO(b/178576541): Adapt and run on TV.
- * Run with:
- * atest AllAppPermissionsFragmentTest
+ * Simple tests for {@link AllAppPermissionsFragment} Currently, does NOT run on TV.
+ *
+ * TODO(b/178576541): Adapt and run on TV. Run with: atest AllAppPermissionsFragmentTest
*/
@RunWith(AndroidJUnit4::class)
class AllAppPermissionsFragmentTest : BasePermissionUiTest() {
private val ONE_PERMISSION_DEFINER_APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui/" +
- "PermissionUiDefineAdditionalPermissionApp.apk"
+ "/data/local/tmp/pc-permissionui/" + "PermissionUiDefineAdditionalPermissionApp.apk"
private val PERMISSION_USER_APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui/" +
- "PermissionUiUseAdditionalPermissionApp.apk"
+ "/data/local/tmp/pc-permissionui/" + "PermissionUiUseAdditionalPermissionApp.apk"
private val TWO_PERMISSION_USER_APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui/" +
- "PermissionUiUseTwoAdditionalPermissionsApp.apk"
+ "/data/local/tmp/pc-permissionui/" + "PermissionUiUseTwoAdditionalPermissionsApp.apk"
private val DEFINER_PKG = "com.android.permissioncontroller.tests.appthatdefinespermission"
private val USER_PKG = "com.android.permissioncontroller.tests.appthatrequestpermission"
@@ -62,8 +57,7 @@ class AllAppPermissionsFragmentTest : BasePermissionUiTest() {
private val TIMEOUT_SHORT = 500L
- @Before
- fun assumeNotTelevision() = assumeFalse(isTelevision)
+ @Before fun assumeNotTelevision() = assumeFalse(isTelevision)
@Before
fun wakeScreenUp() {
@@ -76,12 +70,13 @@ class AllAppPermissionsFragmentTest : BasePermissionUiTest() {
install(PERMISSION_USER_APK)
runWithShellPermissionIdentity {
- instrumentationContext.startActivity(Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS)
- .apply {
+ instrumentationContext.startActivity(
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
putExtra(Intent.EXTRA_PACKAGE_NAME, USER_PKG)
- })
+ }
+ )
}
waitFindObject(By.descContains(MORE_OPTIONS)).click()
@@ -98,30 +93,22 @@ class AllAppPermissionsFragmentTest : BasePermissionUiTest() {
waitFindObject(By.text(PERM_LABEL))
install(TWO_PERMISSION_USER_APK)
- eventually {
- waitFindObject(By.text(SECOND_PERM_LABEL))
- }
+ eventually { waitFindObject(By.text(SECOND_PERM_LABEL)) }
}
@Test
fun permissionsAreRemovedWhenAppIsUpdated() {
install(TWO_PERMISSION_USER_APK)
- eventually {
- waitFindObject(By.text(SECOND_PERM_LABEL))
- }
+ eventually { waitFindObject(By.text(SECOND_PERM_LABEL)) }
install(PERMISSION_USER_APK)
- eventually {
- assertNull(waitFindObjectOrNull(By.text(SECOND_PERM_LABEL), TIMEOUT_SHORT))
- }
+ eventually { assertNull(waitFindObjectOrNull(By.text(SECOND_PERM_LABEL), TIMEOUT_SHORT)) }
}
@Test
fun activityIsClosedWhenUserIsUninstalled() {
uninstallApp(USER_PKG)
- eventually {
- assertNull(waitFindObjectOrNull(By.text(ALL_PERMISSIONS), TIMEOUT_SHORT))
- }
+ eventually { assertNull(waitFindObjectOrNull(By.text(ALL_PERMISSIONS), TIMEOUT_SHORT)) }
}
@After
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AppPermissionFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AppPermissionFragmentTest.kt
index 7b058d004..06fb4beda 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AppPermissionFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AppPermissionFragmentTest.kt
@@ -21,8 +21,8 @@ import android.os.UserHandle
import android.os.UserHandle.myUserId
import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.uninstallApp
-import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.uiautomator.By
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
@@ -31,17 +31,16 @@ import org.junit.After
import org.junit.Assert.assertNull
import org.junit.Assume.assumeFalse
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
private const val APP_PERMISSIONS = "App permissions"
/**
- * Simple tests for {@link AppPermissionFragment}
- * Currently, does NOT run on TV.
- * TODO(b/178576541): Adapt and run on TV.
- * Run with:
- * atest AppPermissionFragmentTest
+ * Simple tests for {@link AppPermissionFragment} Currently, does NOT run on TV.
+ *
+ * TODO(b/178576541): Adapt and run on TV. Run with: atest AppPermissionFragmentTest
*/
@RunWith(AndroidJUnit4::class)
class AppPermissionFragmentTest : BasePermissionUiTest() {
@@ -56,8 +55,7 @@ class AppPermissionFragmentTest : BasePermissionUiTest() {
private val PERM = "com.android.permissioncontroller.tests.A"
- @Before
- fun assumeNotTelevision() = assumeFalse(isTelevision)
+ @Before fun assumeNotTelevision() = assumeFalse(isTelevision)
@Before
fun wakeScreenUp() {
@@ -73,31 +71,31 @@ class AppPermissionFragmentTest : BasePermissionUiTest() {
@Before
fun startManagePermissionAppsActivity() {
runWithShellPermissionIdentity {
- instrumentationContext.startActivity(Intent(Intent.ACTION_MANAGE_APP_PERMISSION).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- putExtra(Intent.EXTRA_PACKAGE_NAME, USER_PKG)
- putExtra(Intent.EXTRA_PERMISSION_NAME, PERM)
- putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, PERM)
- putExtra(Intent.EXTRA_USER, UserHandle.of(myUserId()))
- putExtra("com.android.permissioncontroller.extra.CALLER_NAME", "")
- })
+ instrumentationContext.startActivity(
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSION).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ putExtra(Intent.EXTRA_PACKAGE_NAME, USER_PKG)
+ putExtra(Intent.EXTRA_PERMISSION_NAME, PERM)
+ putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, PERM)
+ putExtra(Intent.EXTRA_USER, UserHandle.of(myUserId()))
+ putExtra("com.android.permissioncontroller.extra.CALLER_NAME", "")
+ }
+ )
}
}
@Test
+ @Ignore("b/301001789")
fun activityIsClosedWhenUserIsUninstalled() {
uninstallApp(USER_PKG)
- eventually {
- assertNull(waitFindObjectOrNull(By.text(APP_PERMISSIONS)))
- }
+ eventually { assertNull(waitFindObjectOrNull(By.text(APP_PERMISSIONS))) }
}
@Test
+ @Ignore("b/301001789")
fun activityIsClosedWhenDefinerIsUninstalled() {
uninstallApp(DEFINER_PKG)
- eventually {
- assertNull(waitFindObjectOrNull(By.text(APP_PERMISSIONS)))
- }
+ eventually { assertNull(waitFindObjectOrNull(By.text(APP_PERMISSIONS))) }
}
@After
@@ -105,4 +103,4 @@ class AppPermissionFragmentTest : BasePermissionUiTest() {
uninstallApp(DEFINER_PKG)
uninstallApp(USER_PKG)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/BasePermissionUiTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/BasePermissionUiTest.kt
index 7d2c644c5..2cb7e7a5c 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/BasePermissionUiTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/BasePermissionUiTest.kt
@@ -29,11 +29,11 @@ abstract class BasePermissionUiTest {
protected val instrumentationContext = instrumentation.context!!
protected val targetContext = instrumentation.targetContext!!
private val packageManager = instrumentationContext.packageManager!!
- protected val isTelevision = packageManager.run {
- hasSystemFeature(PackageManager.FEATURE_LEANBACK) ||
- hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)
- }
+ protected val isTelevision =
+ packageManager.run {
+ hasSystemFeature(PackageManager.FEATURE_LEANBACK) ||
+ hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)
+ }
- @Rule
- fun disableAnimationsRule() = DisableAnimationRule()
-} \ No newline at end of file
+ @Rule fun disableAnimationsRule() = DisableAnimationRule()
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/CustomPermissionAppsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/CustomPermissionAppsFragmentTest.kt
index 988cbca73..ff3631ea9 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/CustomPermissionAppsFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/CustomPermissionAppsFragmentTest.kt
@@ -17,8 +17,8 @@
package com.android.permissioncontroller.permissionui.ui
import android.permission.cts.PermissionUtils.uninstallApp
-import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.uiautomator.By
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
import org.junit.Assert.assertNull
@@ -32,24 +32,22 @@ private const val PERMISSION_APPS_DESCRIPTION = "Apps with this permission"
* Simple tests for {@link PermissionAppsFragment} when showing custom permission
*
* Currently, does NOT run on TV (same as the other tests that extend [PermissionAppsFragmentTest]).
+ *
* TODO(b/178576541): Adapt and run on TV.
*/
@RunWith(AndroidJUnit4::class)
-class CustomPermissionAppsFragmentTest : PermissionAppsFragmentTest(
- "/data/local/tmp/permissioncontroller/tests/permissionui" +
- "/PermissionUiUseAdditionalPermissionApp.apk",
- "com.android.permissioncontroller.tests.appthatrequestpermission",
- "com.android.permissioncontroller.tests.A",
- "/data/local/tmp/permissioncontroller/tests/permissionui" +
- "/PermissionUiDefineAdditionalPermissionApp.apk",
- "com.android.permissioncontroller.tests.appthatdefinespermission"
-) {
+class CustomPermissionAppsFragmentTest :
+ PermissionAppsFragmentTest(
+ "/data/local/tmp/pc-permissionui" + "/PermissionUiUseAdditionalPermissionApp.apk",
+ "com.android.permissioncontroller.tests.appthatrequestpermission",
+ "com.android.permissioncontroller.tests.A",
+ "/data/local/tmp/pc-permissionui" + "/PermissionUiDefineAdditionalPermissionApp.apk",
+ "com.android.permissioncontroller.tests.appthatdefinespermission"
+ ) {
@Ignore("b/155112992")
@Test
fun fragmentIsClosedWhenPermissionIsRemoved() {
uninstallApp(definerApk!!)
- eventually {
- assertNull(waitFindObjectOrNull(By.text(PERMISSION_APPS_DESCRIPTION)))
- }
+ eventually { assertNull(waitFindObjectOrNull(By.text(PERMISSION_APPS_DESCRIPTION))) }
}
}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/HealthConnectAllAppPermissionFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/HealthConnectAllAppPermissionFragmentTest.kt
new file mode 100644
index 000000000..0f4f3841a
--- /dev/null
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/HealthConnectAllAppPermissionFragmentTest.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2023 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.permissionui.ui
+
+import android.content.Intent
+import android.os.Build
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
+import com.android.permissioncontroller.permissionui.wakeUpScreen
+import org.junit.After
+import org.junit.Assert.assertNull
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Simple tests for {@link AllAppPermissionsFragment} for Health Connect behaviors Currently, does
+ * NOT run on TV.
+ *
+ * TODO(b/178576541): Adapt and run on TV. Run with: atest HealthConnectAllAppPermissionFragmentTest
+ */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class HealthConnectAllAppPermissionFragmentTest : BasePermissionUiTest() {
+ @Before fun assumeNotTelevision() = assumeFalse(isTelevision)
+
+ @Before
+ fun wakeScreenUp() {
+ wakeUpScreen()
+ }
+
+ @After
+ fun uninstallTestApp() {
+ uninstallTestApps()
+ }
+ @Test
+ fun usedHealthConnectPermissionsAreListed() {
+ installTestAppThatUsesHealthConnectPermission()
+
+ startManageAppPermissionsActivity()
+
+ eventually {
+ waitFindObject(By.text(HEALTH_CONNECT_LABEL))
+ waitFindObject(By.text(HEALTH_CONNECT_PERMISSION_READ_FLOORS_CLIMBED_LABEL))
+ waitFindObject(By.text(HEALTH_CONNECT_PERMISSION_READ_STEPS_LABEL))
+ }
+ }
+
+ @Test
+ fun invalidUngrantedUsedHealthConnectPermissionsAreNotListed() {
+ installInvalidTestAppThatUsesHealthConnectPermission()
+
+ startManageAppPermissionsActivity()
+
+ eventually {
+ assertNull(waitFindObjectOrNull(By.text(HEALTH_CONNECT_LABEL), TIMEOUT_SHORT))
+ assertNull(
+ waitFindObjectOrNull(
+ By.text(HEALTH_CONNECT_PERMISSION_READ_FLOORS_CLIMBED_LABEL),
+ TIMEOUT_SHORT
+ )
+ )
+ assertNull(
+ waitFindObjectOrNull(
+ By.text(HEALTH_CONNECT_PERMISSION_READ_STEPS_LABEL),
+ TIMEOUT_SHORT
+ )
+ )
+ }
+ }
+
+ @Test
+ fun invalidGrantedUsedHealthConnectPermissionsAreListed() {
+ installInvalidTestAppThatUsesHealthConnectPermission()
+ grantTestAppPermission(HEALTH_CONNECT_PERMISSION_READ_FLOORS_CLIMBED)
+
+ startManageAppPermissionsActivity()
+
+ // Ensure that Health Connect permission group permissions are present if a single one is
+ // already granted, regardless of whether the intent filters are incorrectly or not setup
+ // for the app
+ eventually {
+ waitFindObject(By.text(HEALTH_CONNECT_LABEL))
+ waitFindObject(By.text(HEALTH_CONNECT_PERMISSION_READ_FLOORS_CLIMBED_LABEL))
+
+ // READ_STEPS is not granted, but should still be present due to READ_FLOORS_CLIMBED
+ // being granted
+ waitFindObject(By.text(HEALTH_CONNECT_PERMISSION_READ_STEPS_LABEL))
+ }
+ }
+
+ private fun startManageAppPermissionsActivity() {
+ uiDevice.performActionAndWait(
+ {
+ runWithShellPermissionIdentity {
+ instrumentationContext.startActivity(
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ putExtra(Intent.EXTRA_PACKAGE_NAME, PERM_USER_PACKAGE)
+ }
+ )
+ }
+ },
+ Until.newWindow(),
+ TIMEOUT_SHORT
+ )
+
+ waitFindObject(By.descContains(MORE_OPTIONS)).click()
+ waitFindObject(By.text(ALL_PERMISSIONS)).click()
+ }
+
+ companion object {
+ // Health connect label uses a non breaking space
+ private const val HEALTH_CONNECT_LABEL = "Health\u00A0Connect"
+ private const val HEALTH_CONNECT_PERMISSION_READ_FLOORS_CLIMBED =
+ "android.permission.health.READ_FLOORS_CLIMBED"
+ private const val HEALTH_CONNECT_PERMISSION_READ_FLOORS_CLIMBED_LABEL =
+ "Read floors climbed"
+ private const val HEALTH_CONNECT_PERMISSION_READ_STEPS_LABEL = "Read steps"
+
+ private const val MORE_OPTIONS = "More options"
+ private const val ALL_PERMISSIONS = "All permissions"
+
+ private val TIMEOUT_SHORT = 500L
+ }
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/HealthConnectAppPermissionFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/HealthConnectAppPermissionFragmentTest.kt
new file mode 100644
index 000000000..04dbac39f
--- /dev/null
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/HealthConnectAppPermissionFragmentTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 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.permissionui.ui
+
+import android.content.Intent
+import android.os.Build
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitUntilObjectGone
+import com.android.permissioncontroller.permissionui.wakeUpScreen
+import org.junit.After
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Simple tests for {@link AppPermissionsFragment} for Health Connect behaviors Currently, does NOT
+ * run on TV.
+ *
+ * TODO(b/178576541): Adapt and run on TV. Run with: atest HealthConnectAppPermissionFragmentTest
+ */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class HealthConnectAppPermissionFragmentTest : BasePermissionUiTest() {
+ @Before fun assumeNotTelevision() = assumeFalse(isTelevision)
+
+ @Before
+ fun wakeScreenUp() {
+ wakeUpScreen()
+ }
+
+ @After
+ fun uninstallTestApp() {
+ uninstallTestApps()
+ }
+ @Test
+ fun usedHealthConnectPermissionsAreListed() {
+ installTestAppThatUsesHealthConnectPermission()
+
+ startManageAppPermissionsActivity()
+
+ eventually { waitFindObject(By.text(HEALTH_CONNECT_LABEL)) }
+ }
+
+ @Test
+ fun invalidUngrantedUsedHealthConnectPermissionsAreNotListed() {
+ installInvalidTestAppThatUsesHealthConnectPermission()
+
+ startManageAppPermissionsActivity()
+
+ waitUntilObjectGone(By.text(HEALTH_CONNECT_LABEL), TIMEOUT_SHORT)
+ }
+
+ @Test
+ fun invalidGrantedUsedHealthConnectPermissionsAreListed() {
+ installInvalidTestAppThatUsesHealthConnectPermission()
+ grantTestAppPermission(HEALTH_CONNECT_PERMISSION_READ_FLOORS_CLIMBED)
+
+ startManageAppPermissionsActivity()
+
+ eventually { waitFindObject(By.text(HEALTH_CONNECT_LABEL)) }
+ }
+
+ private fun startManageAppPermissionsActivity() {
+ runWithShellPermissionIdentity {
+ instrumentationContext.startActivity(
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ putExtra(Intent.EXTRA_PACKAGE_NAME, PERM_USER_PACKAGE)
+ }
+ )
+ }
+ }
+
+ companion object {
+ // Health connect label uses a non breaking space
+ private const val HEALTH_CONNECT_LABEL = "Health\u00A0Connect"
+ private const val HEALTH_CONNECT_PERMISSION_READ_FLOORS_CLIMBED =
+ "android.permission.health.READ_FLOORS_CLIMBED"
+
+ private val TIMEOUT_SHORT = 500L
+ }
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/LocationPermissionAppsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/LocationPermissionAppsFragmentTest.kt
index 3b48d7235..fb13c99ed 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/LocationPermissionAppsFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/LocationPermissionAppsFragmentTest.kt
@@ -17,18 +17,24 @@
package com.android.permissioncontroller.permissionui.ui
import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
import org.junit.runner.RunWith
/**
* Simple tests for {@link PermissionAppsFragment} when showing location permission
*
* Currently, does NOT run on TV (same as the other tests that extend [PermissionAppsFragmentTest]).
+ *
* TODO(b/178576541): Adapt and run on TV.
+ * TODO(b/304152870): On Android R, the package name never disappears from screen after uninstall
*/
@RunWith(AndroidJUnit4::class)
-class LocationPermissionAppsFragmentTest : PermissionAppsFragmentTest(
- "/data/local/tmp/permissioncontroller/tests/permissionui/AppThatRequestsLocation.apk",
- "android.permission.cts.appthatrequestpermission",
- ACCESS_COARSE_LOCATION
-)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+class LocationPermissionAppsFragmentTest :
+ PermissionAppsFragmentTest(
+ "/data/local/tmp/pc-permissionui/AppThatRequestsLocation.apk",
+ "android.permission.cts.appthatrequestpermission",
+ ACCESS_COARSE_LOCATION
+ )
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/PermissionAppsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/PermissionAppsFragmentTest.kt
index a5453d9e7..276494ab3 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/PermissionAppsFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/PermissionAppsFragmentTest.kt
@@ -19,14 +19,17 @@ package com.android.permissioncontroller.permissionui.ui
import android.content.Intent
import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.uninstallApp
+import android.util.Log
import androidx.test.uiautomator.By
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.Direction
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
-import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
import com.android.permissioncontroller.permissionui.wakeUpScreen
+import com.google.common.truth.Truth.assertWithMessage
import org.junit.After
-import org.junit.Assert.assertNull
import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.Test
@@ -37,6 +40,7 @@ import org.junit.Test
* <p>Leave abstract to prevent the test runner from trying to run it
*
* Currently, none of the tests that extend [PermissionAppsFragmentTest] run on TV.
+ *
* TODO(b/178576541): Adapt and run on TV.
*/
abstract class PermissionAppsFragmentTest(
@@ -46,61 +50,98 @@ abstract class PermissionAppsFragmentTest(
val definerApk: String? = null,
val definerPkg: String? = null
) : BasePermissionUiTest() {
+ val pkgSelector = By.text(userPkg)
+ var startTimeMillis: Long = 0
- @Before
- fun assumeNotTelevision() = assumeFalse(isTelevision)
-
- @Before
- fun wakeScreenUp() {
- wakeUpScreen()
+ private fun scrollFindFromTop(selector: BySelector): UiObject2? {
+ val scrollable = uiDevice.findObject(By.scrollable(true))
+ if (scrollable != null) {
+ logCheckPoint("found scrollable, so proceeding to scroll")
+ logCheckPoint("starting scroll up")
+ scrollable.scrollUntil(Direction.UP, Until.scrollFinished(Direction.UP))
+ logCheckPoint("finished scroll up")
+ logCheckPoint("starting scroll down")
+ var uiObject = scrollable.scrollUntil(Direction.DOWN, Until.findObject(selector))
+ logCheckPoint("finished scroll down")
+ return uiObject
+ }
+ logCheckPoint("no scrollable on screen, so finding object directly")
+ return uiDevice.findObject(selector)
}
@Before
- fun installDefinerApk() {
+ fun setUp() {
+ startTimeMillis = System.currentTimeMillis()
+ logCheckPoint("setUp: started")
+ assumeFalse(isTelevision)
+ wakeUpScreen()
if (definerApk != null) {
install(definerApk)
}
- }
-
- @Before
- fun startManagePermissionAppsActivity() {
- runWithShellPermissionIdentity {
- instrumentationContext.startActivity(Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
- .apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- putExtra(Intent.EXTRA_PERMISSION_NAME, perm)
- })
- }
+ uninstallApp(userPkg)
+ uiDevice.performActionAndWait(
+ {
+ runWithShellPermissionIdentity {
+ instrumentationContext.startActivity(
+ Intent(Intent.ACTION_MANAGE_PERMISSION_APPS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ putExtra(Intent.EXTRA_PERMISSION_NAME, perm)
+ }
+ )
+ }
+ },
+ Until.newWindow(),
+ NEW_WINDOW_TIMEOUT_MILLIS
+ )
+ logCheckPoint("setUp: finished")
}
@Test
- fun appAppearsWhenInstalled() {
- assertNull(waitFindObjectOrNull(By.text(userPkg)))
+ fun testAppAppearanceReflectsInstallation() {
+ logCheckPoint("testAppAppearanceReflectsInstallation: started")
+ // Install package
install(userApk)
- eventually {
- waitFindObject(By.text(userPkg))
- }
- }
-
- // TODO(b/280652042) Slow tests aren't good
- @Test(timeout = 120000)
- fun appDisappearsWhenUninstalled() {
- assertNull(waitFindObjectOrNull(By.text(userPkg)))
+ logCheckPoint("installed app")
- install(userApk)
- eventually {
- waitFindObject(By.text(userPkg))
- }
+ // Expect *to* find package listed on screen
+ eventually(
+ {
+ val pkg = scrollFindFromTop(pkgSelector)
+ assertWithMessage(
+ "Package '$userPkg' was NOT visible after installing, but should be"
+ )
+ .that(pkg)
+ .isNotNull()
+ },
+ Companion.SCROLL_TIMEOUT_MILLIS
+ )
+ // Uninstall app
uninstallApp(userPkg)
- eventually {
- assertNull(waitFindObjectOrNull(By.text(userPkg)))
- }
+ logCheckPoint("uninstalled app")
+
+ // Expect *not to* find package listed on screen
+ eventually(
+ {
+ val pkg = scrollFindFromTop(pkgSelector)
+ assertWithMessage(
+ "Package '$userPkg' was visible after uninstalling, but should NOT be"
+ )
+ .that(pkg)
+ .isNull()
+ },
+ Companion.SCROLL_TIMEOUT_MILLIS
+ )
+
+ logCheckPoint("confirmed installed app shown on screen")
+ logCheckPoint("testAppAppearanceReflectsInstallation: finished")
}
@After
fun tearDown() {
+ logCheckPoint("tearDown: started")
if (definerPkg != null) {
uninstallApp(definerPkg)
}
@@ -108,5 +149,17 @@ abstract class PermissionAppsFragmentTest(
uiDevice.pressBack()
uiDevice.pressHome()
+ logCheckPoint("tearDown: finished")
+ }
+
+ fun logCheckPoint(logMessage: String) {
+ val elapsedSeconds = (System.currentTimeMillis() - startTimeMillis) / 1000
+ Log.v(TAG, "(${elapsedSeconds}s): $logMessage")
+ }
+
+ companion object {
+ const val NEW_WINDOW_TIMEOUT_MILLIS = 25_000L
+ const val SCROLL_TIMEOUT_MILLIS = 25_000L
+ val TAG = PermissionAppsFragmentTest::class.java.simpleName
}
}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/StoragePermissionAppsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/StoragePermissionAppsFragmentTest.kt
index ada143613..3994a3ae6 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/StoragePermissionAppsFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/StoragePermissionAppsFragmentTest.kt
@@ -17,19 +17,24 @@
package com.android.permissioncontroller.permissionui.ui
import android.Manifest.permission.READ_EXTERNAL_STORAGE
+import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
import org.junit.runner.RunWith
/**
* Simple tests for {@link PermissionAppsFragment} when showing location permission
*
* Currently, does NOT run on TV (same as the other tests that extend [PermissionAppsFragmentTest]).
+ *
* TODO(b/178576541): Adapt and run on TV.
+ * TODO(b/304152870): On Android R, the package name never disappears from screen after uninstall
*/
@RunWith(AndroidJUnit4::class)
-class StoragePermissionAppsFragmentTest : PermissionAppsFragmentTest(
- "/data/local/tmp/permissioncontroller/tests/permissionui" +
- "/PermissionUiUseStoragePermissionApp.apk",
- "com.android.permissioncontroller.tests.appthatrequestpermission",
- READ_EXTERNAL_STORAGE
-)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+class StoragePermissionAppsFragmentTest :
+ PermissionAppsFragmentTest(
+ "/data/local/tmp/pc-permissionui" + "/PermissionUiUseStoragePermissionApp.apk",
+ "com.android.permissioncontroller.tests.appthatrequestpermission",
+ READ_EXTERNAL_STORAGE
+ )
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/TestAppUtils.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/TestAppUtils.kt
index 06e25485e..09f59de30 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/TestAppUtils.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/TestAppUtils.kt
@@ -21,9 +21,13 @@ import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.uninstallApp
// Test Apps' APK files
-private const val APK_DIRECTORY = "/data/local/tmp/permissioncontroller/tests/permissionui/"
+private const val APK_DIRECTORY = "/data/local/tmp/pc-permissionui/"
private const val LOCATION_PERM_USER_APK = "$APK_DIRECTORY/AppThatRequestsLocation.apk"
private const val CAMERA_PERM_USER_APK = "$APK_DIRECTORY/PermissionUiUseCameraPermissionApp.apk"
+private const val HEALTH_CONNECT_PERMISSION_USER_APK =
+ "$APK_DIRECTORY/PermissionUiUseHealthConnectPermissionApp.apk"
+private const val INVALID_HEALTH_CONNECT_PERMISSION_USER_APK =
+ "$APK_DIRECTORY/PermissionUiInvalidUseHealthConnectPermissionApp.apk"
private const val ADDITIONAL_PERM_USER_APK =
"$APK_DIRECTORY/PermissionUiUseAdditionalPermissionApp.apk"
private const val TWO_ADDITIONAL_PERM_USER_APK =
@@ -32,10 +36,9 @@ private const val ADDITIONAL_PERM_DEFINER_APK =
"$APK_DIRECTORY/PermissionUiDefineAdditionalPermissionApp.apk"
// All 4 of the AppThatUses_X_Permission(s) applications share the same package name.
-private const val PERM_USER_PACKAGE =
- "com.android.permissioncontroller.tests.appthatrequestpermission"
private const val PERM_DEFINER_PACKAGE =
"com.android.permissioncontroller.tests.appthatdefinespermission"
+const val PERM_USER_PACKAGE = "com.android.permissioncontroller.tests.appthatrequestpermission"
const val CAMERA_TEST_APP_LABEL = "CameraRequestApp"
@@ -48,9 +51,18 @@ const val TEST_APP_DEFINED_PERMISSION_B_LABEL = "Permission B"
const val TEST_APP_DEFINED_PERMISSION_C_LABEL = "Permission C"
fun installTestAppThatRequestsLocation() = install(LOCATION_PERM_USER_APK)
+
fun installTestAppThatUsesCameraPermission() = install(CAMERA_PERM_USER_APK)
+
+fun installTestAppThatUsesHealthConnectPermission() = install(HEALTH_CONNECT_PERMISSION_USER_APK)
+
+fun installInvalidTestAppThatUsesHealthConnectPermission() =
+ install(INVALID_HEALTH_CONNECT_PERMISSION_USER_APK)
+
fun installTestAppThatUsesAdditionalPermission() = install(ADDITIONAL_PERM_USER_APK)
+
fun installTestAppThatUsesTwoAdditionalPermissions() = install(TWO_ADDITIONAL_PERM_USER_APK)
+
fun installTestAppThatDefinesAdditionalPermissions() = install(ADDITIONAL_PERM_DEFINER_APK)
fun uninstallTestApps() {
@@ -58,4 +70,4 @@ fun uninstallTestApps() {
uninstallApp(PERM_DEFINER_PACKAGE)
}
-fun grantTestAppPermission(permission: String) = grantPermission(PERM_USER_PACKAGE, permission) \ No newline at end of file
+fun grantTestAppPermission(permission: String) = grantPermission(PERM_USER_PACKAGE, permission)
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/BaseHandheldPermissionUiTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/BaseHandheldPermissionUiTest.kt
index 66e254155..7f005e489 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/BaseHandheldPermissionUiTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/BaseHandheldPermissionUiTest.kt
@@ -21,6 +21,5 @@ import org.junit.Assume.assumeFalse
import org.junit.Before
abstract class BaseHandheldPermissionUiTest : BasePermissionUiTest() {
- @Before
- fun assumeNotTelevision() = assumeFalse(isTelevision)
-} \ No newline at end of file
+ @Before fun assumeNotTelevision() = assumeFalse(isTelevision)
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt
index c41dacc96..eb7be564b 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt
@@ -21,8 +21,8 @@ import android.permission.cts.PermissionUtils.grantPermission
import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.revokePermission
import android.permission.cts.PermissionUtils.uninstallApp
-import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.uiautomator.By
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
@@ -34,17 +34,13 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-/**
- * Simple tests for {@link ManageCustomPermissionsFragment}
- */
+/** Simple tests for {@link ManageCustomPermissionsFragment} */
@RunWith(AndroidJUnit4::class)
class ManageCustomPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
private val ONE_PERMISSION_DEFINER_APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui/" +
- "PermissionUiDefineAdditionalPermissionApp.apk"
+ "/data/local/tmp/pc-permissionui/" + "PermissionUiDefineAdditionalPermissionApp.apk"
private val PERMISSION_USER_APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui/" +
- "PermissionUiUseAdditionalPermissionApp.apk"
+ "/data/local/tmp/pc-permissionui/" + "PermissionUiUseAdditionalPermissionApp.apk"
private val DEFINER_PKG = "com.android.permissioncontroller.tests.appthatdefinespermission"
private val USER_PKG = "com.android.permissioncontroller.tests.appthatrequestpermission"
@@ -57,9 +53,11 @@ class ManageCustomPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
wakeUpScreen()
runWithShellPermissionIdentity {
- instrumentationContext.startActivity(Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- })
+ instrumentationContext.startActivity(
+ Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
}
}
@@ -88,14 +86,10 @@ class ManageCustomPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
val original = getUsageCountsFromUi(PERM_LABEL)
grantPermission(USER_PKG, PERM)
- eventually {
- assertThat(getUsageCountsFromUi(PERM_LABEL)).isNotEqualTo(original)
- }
+ eventually { assertThat(getUsageCountsFromUi(PERM_LABEL)).isNotEqualTo(original) }
revokePermission(USER_PKG, PERM)
- eventually {
- assertThat(getUsageCountsFromUi(PERM_LABEL)).isEqualTo(original)
- }
+ eventually { assertThat(getUsageCountsFromUi(PERM_LABEL)).isEqualTo(original) }
}
@After
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt
index 5d0fae9a1..1ad876245 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt
@@ -18,12 +18,14 @@ package com.android.permissioncontroller.permissionui.ui.handheld
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.content.Intent
+import android.content.pm.PackageManager
import android.permission.cts.PermissionUtils.grantPermission
import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.revokePermission
import android.permission.cts.PermissionUtils.uninstallApp
-import androidx.test.uiautomator.By
+import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.uiautomator.By
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.getEventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
@@ -36,28 +38,51 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-/**
- * Simple tests for {@link ManageStandardPermissionsFragment}
- */
+/** Simple tests for {@link ManageStandardPermissionsFragment} */
@RunWith(AndroidJUnit4::class)
class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
- private val LOCATION_USER_APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui/AppThatRequestsLocation.apk"
- private val ADDITIONAL_DEFINER_APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui/" +
- "PermissionUiDefineAdditionalPermissionApp.apk"
- private val ADDITIONAL_USER_APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui/" +
- "PermissionUiUseAdditionalPermissionApp.apk"
- private val LOCATION_USER_PKG = "android.permission.cts.appthatrequestpermission"
- private val ADDITIONAL_DEFINER_PKG =
- "com.android.permissioncontroller.tests.appthatdefinespermission"
- private val ADDITIONAL_USER_PKG =
- "com.android.permissioncontroller.tests.appthatrequestpermission"
- private val ADDITIONAL_PERMISSIONS_LABEL = "Additional permissions"
- private val ADDITIONAL_PERMISSIONS_SUMMARY = "more"
-
- private val locationGroupLabel = "Location"
+ @Before
+ fun setup() {
+ wakeUpScreen()
+
+ runWithShellPermissionIdentity {
+ removePackageIfInstalled()
+ instrumentationContext.startActivity(
+ Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ }
+ )
+ }
+ }
+
+ @After
+ fun tearDown() {
+ uninstallApp(LOCATION_USER_PKG)
+ uninstallApp(ADDITIONAL_DEFINER_PKG)
+ uninstallApp(ADDITIONAL_USER_PKG)
+ uiDevice.pressBack()
+ }
+
+ /**
+ * The test packages are not expected to be installed already, remove them if they are already
+ * installed (i.e. leftover from another test) when a test starts.
+ */
+ private fun removePackageIfInstalled() {
+ val packageNames = listOf(LOCATION_USER_PKG, ADDITIONAL_DEFINER_PKG, ADDITIONAL_USER_PKG)
+ for (packageName in packageNames) {
+ try {
+ val packageInfo =
+ instrumentationContext.packageManager.getPackageInfo(packageName, 0)
+ if (packageInfo != null) {
+ Log.w(LOG_TAG, "package $packageName not expected to be installed.")
+ uninstallApp(packageName)
+ Thread.sleep(1000)
+ }
+ } catch (e: PackageManager.NameNotFoundException) {
+ // ignore
+ }
+ }
+ }
/**
* Read the number of additional permissions from the Ui.
@@ -68,96 +93,89 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
waitFindObjectOrNull(By.textContains(ADDITIONAL_PERMISSIONS_LABEL)) ?: return 0
// Sometimes the entire preference disappears while it's searching for the app count
// (during uninstalling). Hence also return the count as 0 if count doesn't exist
- val additionalPermissionsSummary = waitFindObjectOrNull(
- By.textContains(ADDITIONAL_PERMISSIONS_SUMMARY)) ?: return 0
+ val additionalPermissionsSummary =
+ waitFindObjectOrNull(By.textContains(ADDITIONAL_PERMISSIONS_SUMMARY)) ?: return 0
val additionalPermissionsSummaryText = additionalPermissionsSummary.getText()
// Matches a single number out of the summary line, i.e. "...3..." -> "3"
return getEventually {
Regex("^[^\\d]*(\\d+)[^\\d]*\$")
- .find(additionalPermissionsSummaryText)!!.groupValues[1]
+ .find(additionalPermissionsSummaryText)!!
+ .groupValues[1]
.toInt()
}
}
- @Before
- fun setup() {
- wakeUpScreen()
-
- runWithShellPermissionIdentity {
- instrumentationContext.startActivity(Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- })
- }
-
- reuninstallApp(LOCATION_USER_APK, LOCATION_USER_PKG)
-
- // Sleep before each test for 1 second for getUsageCountsFromUi to get the correct counts
- Thread.sleep(1000)
- }
-
@Test
fun groupSummaryGetsUpdatedWhenAppGetsInstalled() {
- val original = getUsageCountsFromUi(locationGroupLabel)
+ val original = getUsageCountsFromUi(LOCATION_GROUP_LABEL)
install(LOCATION_USER_APK)
- eventually {
- val afterInstall = getUsageCountsFromUi(locationGroupLabel)
- assertThat(afterInstall.granted).isEqualTo(original.granted)
- assertThat(afterInstall.total).isEqualTo(original.total + 1)
- }
+ eventually(
+ {
+ val afterInstall = getUsageCountsFromUi(LOCATION_GROUP_LABEL)
+ assertThat(afterInstall.granted).isEqualTo(original.granted)
+ assertThat(afterInstall.total).isEqualTo(original.total + 1)
+ },
+ TIMEOUT
+ )
}
@Test
fun groupSummaryGetsUpdatedWhenAppGetsUninstalled() {
- reuninstallApp(LOCATION_USER_APK, LOCATION_USER_PKG)
- val original = getUsageCountsFromUi(locationGroupLabel)
-
+ val original = getUsageCountsFromUi(LOCATION_GROUP_LABEL)
install(LOCATION_USER_APK)
- eventually {
- assertThat(getUsageCountsFromUi(locationGroupLabel)).isNotEqualTo(original)
- }
+ eventually(
+ { assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL)).isNotEqualTo(original) },
+ TIMEOUT
+ )
uninstallApp(LOCATION_USER_PKG)
- reuninstallApp(LOCATION_USER_APK, LOCATION_USER_PKG)
- eventually {
- assertThat(getUsageCountsFromUi(locationGroupLabel)).isEqualTo(original)
- }
+ eventually(
+ { assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL)).isEqualTo(original) },
+ TIMEOUT
+ )
}
@Test
fun groupSummaryGetsUpdatedWhenPermissionGetsGranted() {
- val original = getUsageCountsFromUi(locationGroupLabel)
+ val original = getUsageCountsFromUi(LOCATION_GROUP_LABEL)
install(LOCATION_USER_APK)
- eventually {
- assertThat(getUsageCountsFromUi(locationGroupLabel).total)
- .isEqualTo(original.total + 1)
- }
+ eventually(
+ {
+ assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).total)
+ .isEqualTo(original.total + 1)
+ },
+ TIMEOUT
+ )
grantPermission(LOCATION_USER_PKG, ACCESS_COARSE_LOCATION)
eventually {
- assertThat(getUsageCountsFromUi(locationGroupLabel).granted)
+ assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).granted)
.isEqualTo(original.granted + 1)
}
}
@Test
fun groupSummaryGetsUpdatedWhenPermissionGetsRevoked() {
- val original = getUsageCountsFromUi(locationGroupLabel)
+ val original = getUsageCountsFromUi(LOCATION_GROUP_LABEL)
install(LOCATION_USER_APK)
grantPermission(LOCATION_USER_PKG, ACCESS_COARSE_LOCATION)
- eventually {
- assertThat(getUsageCountsFromUi(locationGroupLabel).total)
- .isNotEqualTo(original.total)
- assertThat(getUsageCountsFromUi(locationGroupLabel).granted)
- .isNotEqualTo(original.granted)
- }
+ eventually(
+ {
+ assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).total)
+ .isNotEqualTo(original.total)
+ assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).granted)
+ .isNotEqualTo(original.granted)
+ },
+ TIMEOUT
+ )
revokePermission(LOCATION_USER_PKG, ACCESS_COARSE_LOCATION)
eventually {
- assertThat(getUsageCountsFromUi(locationGroupLabel).granted)
+ assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).granted)
.isEqualTo(original.granted)
}
}
@@ -168,10 +186,12 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
install(ADDITIONAL_DEFINER_APK)
install(ADDITIONAL_USER_APK)
- eventually {
- assertThat(getAdditionalPermissionCount())
- .isEqualTo(additionalPermissionBefore + 1)
- }
+ eventually(
+ {
+ assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore + 1)
+ },
+ TIMEOUT
+ )
}
@Test
@@ -180,15 +200,16 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
install(ADDITIONAL_DEFINER_APK)
install(ADDITIONAL_USER_APK)
- eventually {
- assertThat(getAdditionalPermissionCount())
- .isNotEqualTo(additionalPermissionBefore)
- }
+ eventually(
+ { assertThat(getAdditionalPermissionCount()).isNotEqualTo(additionalPermissionBefore) },
+ TIMEOUT
+ )
uninstallApp(ADDITIONAL_USER_PKG)
- eventually {
- assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore)
- }
+ eventually(
+ { assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore) },
+ TIMEOUT
+ )
}
@Test
@@ -197,32 +218,38 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
install(ADDITIONAL_DEFINER_APK)
install(ADDITIONAL_USER_APK)
- eventually {
- assertThat(getAdditionalPermissionCount())
- .isNotEqualTo(additionalPermissionBefore)
- }
+ eventually(
+ { assertThat(getAdditionalPermissionCount()).isNotEqualTo(additionalPermissionBefore) },
+ TIMEOUT
+ )
uninstallApp(ADDITIONAL_DEFINER_PKG)
- eventually {
- assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore)
- }
- }
-
- fun reuninstallApp(apk: String, pkg: String) {
- // b/275752754: sometimes this test is flaky because inside @After it didn't uninstall the
- // packages correctly. This caused the permission manager screen to still show the package
- // as requesting the permission and caused the original usage count to be incorrect.
- // Installing/uninstalling the packages again to ensure the package is correctly uninstalled
- install(apk)
- uninstallApp(pkg)
+ eventually(
+ { assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore) },
+ TIMEOUT
+ )
}
- @After
- fun tearDown() {
- uninstallApp(LOCATION_USER_PKG)
- uninstallApp(ADDITIONAL_DEFINER_PKG)
- uninstallApp(ADDITIONAL_USER_PKG)
-
- uiDevice.pressBack()
+ companion object {
+ private val LOG_TAG = ManageStandardPermissionsFragmentTest::class.java.simpleName
+
+ private const val LOCATION_USER_APK =
+ "/data/local/tmp/pc-permissionui/AppThatRequestsLocation.apk"
+ private const val ADDITIONAL_DEFINER_APK =
+ "/data/local/tmp/pc-permissionui/" + "PermissionUiDefineAdditionalPermissionApp.apk"
+ private const val ADDITIONAL_USER_APK =
+ "/data/local/tmp/pc-permissionui/" + "PermissionUiUseAdditionalPermissionApp.apk"
+ private const val LOCATION_USER_PKG = "android.permission.cts.appthatrequestpermission"
+ private const val ADDITIONAL_DEFINER_PKG =
+ "com.android.permissioncontroller.tests.appthatdefinespermission"
+ private const val ADDITIONAL_USER_PKG =
+ "com.android.permissioncontroller.tests.appthatrequestpermission"
+ private const val ADDITIONAL_PERMISSIONS_LABEL = "Additional permissions"
+ private const val ADDITIONAL_PERMISSIONS_SUMMARY = "more"
+ private const val LOCATION_GROUP_LABEL = "Location"
+
+ // Package Added/Removed broadcast are pretty slow on cf devices, we may want to increase
+ // this in future if the test still fails.
+ private const val TIMEOUT = 30000L
}
}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ReviewOngoingUsageFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ReviewOngoingUsageFragmentTest.kt
index ec9971cb4..dc654047d 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ReviewOngoingUsageFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ReviewOngoingUsageFragmentTest.kt
@@ -30,9 +30,7 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
-/**
- * Simple tests for {@link ReviewOngoingUsageFragment}
- */
+/** Simple tests for {@link ReviewOngoingUsageFragment} */
class ReviewOngoingUsageFragmentTest : PermissionHub2Test() {
@Before
@@ -46,14 +44,15 @@ class ReviewOngoingUsageFragmentTest : PermissionHub2Test() {
@Test
fun cameraAccessShouldBeShown() {
runWithShellPermissionIdentity {
- context.startActivity(Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- })
+ context.startActivity(
+ Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
}
waitFindObject(By.textContains(CAMERA_TEST_APP_LABEL)).click()
}
- @After
- fun cleanUp() = uninstallTestApps()
-} \ No newline at end of file
+ @After fun cleanUp() = uninstallTestApps()
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageFragmentTest.kt
index 2869e1863..c7292f3e7 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageFragmentTest.kt
@@ -29,8 +29,8 @@ import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
import com.android.permissioncontroller.permissionui.PermissionHub2Test
-import com.android.permissioncontroller.permissionui.wakeUpScreen
import com.android.permissioncontroller.permissionui.pressHome
+import com.android.permissioncontroller.permissionui.wakeUpScreen
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -40,9 +40,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
class PermissionUsageFragmentTest : PermissionHub2Test() {
- private val APK =
- "/data/local/tmp/permissioncontroller/tests/permissionui" +
- "/PermissionUiUseCameraPermissionApp.apk"
+ private val APK = "/data/local/tmp/pc-permissionui" + "/PermissionUiUseCameraPermissionApp.apk"
private val APP = "com.android.permissioncontroller.tests.appthatrequestpermission"
private val APP_LABEL = "CameraRequestApp"
private val CAMERA_PREF_LABEL = "Camera"
@@ -62,8 +60,10 @@ class PermissionUsageFragmentTest : PermissionHub2Test() {
runWithShellPermissionIdentity {
context.startActivity(
Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- })
+ }
+ )
}
eventually {
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsFragmentTest.kt
index f3171c7d5..9794d787d 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsFragmentTest.kt
@@ -27,42 +27,49 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-/**
- * Run with:
- * atest ManagePermissionsFragmentTest
- */
+/** Run with: atest ManagePermissionsFragmentTest */
@RunWith(AndroidJUnit4::class)
class ManagePermissionsFragmentTest : TelevisionUiBaseTest() {
- @Before
- fun launch() = launchPermissionController()
+ @Before fun launch() = launchPermissionController()
@Test
fun test_bodySensors_permissionGroup_isNotShown() {
- assertFalse("Found \"Body sensors\" permission",
- uiDevice.hasElementWithTitle(bodySensorsPermissionLabel))
+ assertFalse(
+ "Found \"Body sensors\" permission",
+ uiDevice.hasElementWithTitle(bodySensorsPermissionLabel)
+ )
}
@Test
fun test_camera_permissionGroup_isShown_whenUsed() {
// Make sure Camera permission group is not shown at first.
- assertFalse("Found \"Camera\" permission",
- uiDevice.hasElementWithTitle(cameraPermissionLabel))
+ assertFalse(
+ "Found \"Camera\" permission",
+ uiDevice.hasElementWithTitle(cameraPermissionLabel)
+ )
// Install app that uses Camera permission...
installTestAppThatUsesCameraPermission()
// ... grant the permission ...
grantTestAppPermission(CAMERA)
// ... make sure now the Camera permission is shown.
- assertTrue("Could not find \"Camera\" permission",
- uiDevice.focusOnElementWithTitle(cameraPermissionLabel))
+ assertTrue(
+ "Could not find \"Camera\" permission",
+ uiDevice.focusOnElementWithTitle(cameraPermissionLabel)
+ )
}
@Test
fun test_otherPermissions_Button_isShown() {
uiDevice.navigateToTheBottom()
- assertEquals("The last item should be the \"Other permissions\" button",
- otherPermissionsLabel, uiDevice.focusedElementTitle)
- assertTrue("\"Other permissions\" button should be clickable",
- uiDevice.focusedElement.isClickable)
+ assertEquals(
+ "The last item should be the \"Other permissions\" button",
+ otherPermissionsLabel,
+ uiDevice.focusedElementTitle
+ )
+ assertTrue(
+ "\"Other permissions\" button should be clickable",
+ uiDevice.focusedElement.isClickable
+ )
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsOtherFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsOtherFragmentTest.kt
index f7cf27c72..2d338906b 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsOtherFragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/ManagePermissionsOtherFragmentTest.kt
@@ -29,10 +29,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-/**
- * Run with:
- * atest ManagePermissionsOtherFragmentTest
- */
+/** Run with: atest ManagePermissionsOtherFragmentTest */
@RunWith(AndroidJUnit4::class)
class ManagePermissionsOtherFragmentTest : TelevisionUiBaseTest() {
@@ -45,20 +42,27 @@ class ManagePermissionsOtherFragmentTest : TelevisionUiBaseTest() {
uiDevice.waitForIdle()
// Making sure are on the "Other permission" page now.
// For this we can check the Fragment's title.
- assertEquals("\"Other permissions\" didn't open",
- otherPermissionsLabel, uiDevice.fragmentDecorTitle)
+ assertEquals(
+ "\"Other permissions\" didn't open",
+ otherPermissionsLabel,
+ uiDevice.fragmentDecorTitle
+ )
}
@Test
fun bodySensors_permissionGroup_isNotShown() {
- assertFalse("Found \"Body sensors\" permission",
- uiDevice.focusOnElementWithTitle(bodySensorsPermissionLabel))
+ assertFalse(
+ "Found \"Body sensors\" permission",
+ uiDevice.focusOnElementWithTitle(bodySensorsPermissionLabel)
+ )
}
@Test
fun additionalPermissions_section_isNotShown_ifAllUnused() {
- assertFalse("\"Additional permissions\" section is shown",
- uiDevice.hasElementWithTitle(additionalPermissionsLabel))
+ assertFalse(
+ "\"Additional permissions\" section is shown",
+ uiDevice.hasElementWithTitle(additionalPermissionsLabel)
+ )
}
@Test
@@ -72,10 +76,14 @@ class ManagePermissionsOtherFragmentTest : TelevisionUiBaseTest() {
grantTestAppPermission(TEST_APP_DEFINED_PERMISSION_A)
// Make sure the "Additional permissions" section is now shown...
- assertTrue("\"Additional permissions\" section should be shown",
- uiDevice.hasElementWithTitle(additionalPermissionsLabel))
+ assertTrue(
+ "\"Additional permissions\" section should be shown",
+ uiDevice.hasElementWithTitle(additionalPermissionsLabel)
+ )
// ... and that we now have "Permission A" row.
- assertTrue("Could not find \"Permission A\" row",
- uiDevice.focusOnElementWithTitle(TEST_APP_DEFINED_PERMISSION_A_LABEL))
+ assertTrue(
+ "Could not find \"Permission A\" row",
+ uiDevice.focusOnElementWithTitle(TEST_APP_DEFINED_PERMISSION_A_LABEL)
+ )
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUiBaseTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUiBaseTest.kt
index c289afa6e..f56544660 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUiBaseTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUiBaseTest.kt
@@ -30,8 +30,7 @@ abstract class TelevisionUiBaseTest : BasePermissionUiTest() {
val otherPermissionsLabel = "Other permissions"
val additionalPermissionsLabel = "Additional permissions"
- @Before
- fun assumeTelevision() = assumeTrue(isTelevision)
+ @Before fun assumeTelevision() = assumeTrue(isTelevision)
@Before
fun wakeUpAndGoToHomeScreen() {
@@ -39,16 +38,17 @@ abstract class TelevisionUiBaseTest : BasePermissionUiTest() {
uiDevice.pressHome()
}
- @After
- fun cleanUp() = uninstallTestApps()
+ @After fun cleanUp() = uninstallTestApps()
protected fun launchPermissionController() {
SystemUtil.runWithShellPermissionIdentity {
- instrumentationContext.startActivity(Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- })
+ instrumentationContext.startActivity(
+ Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
}
uiDevice.waitForIdle()
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUtils.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUtils.kt
index b221eae70..8caac313e 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUtils.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/television/TelevisionUtils.kt
@@ -34,17 +34,20 @@ val UiDevice.fragmentDecorTitle: String?
get() = wait(Until.findObject(SELECTOR_RES_ID_PC_DECOR_TITLE), WAIT_DELAY)?.text
val UiDevice.focusedElement: UiObject2
- get() = wait(Until.findObject(SELECTOR_FOCUSED), WAIT_DELAY)
- ?: error("Focused item is not found")
+ get() =
+ wait(Until.findObject(SELECTOR_FOCUSED), WAIT_DELAY) ?: error("Focused item is not found")
private val UiObject2.titleElement: UiObject2
- get() = wait(Until.findObject(SELECTOR_RES_ID_ANDROID_TITLE), WAIT_DELAY)
- ?: error("Could not retrieve title")
+ get() =
+ wait(Until.findObject(SELECTOR_RES_ID_ANDROID_TITLE), WAIT_DELAY)
+ ?: error("Could not retrieve title")
val UiDevice.focusedElementTitle: String?
get() {
repeat(RETRIES) {
- try { return focusedElement.titleElement.text } catch (e: StaleObjectException) {}
+ try {
+ return focusedElement.titleElement.text
+ } catch (e: StaleObjectException) {}
}
error("Could not get title text")
}
@@ -63,13 +66,13 @@ fun UiDevice.navigateToTheTop() {
while (navigateUp()) {}
}
-fun UiDevice.focusOnElementWithTitle(title: CharSequence): Boolean =
- checkAllItemsIfNeeded { focusedElementTitle == title }
+fun UiDevice.focusOnElementWithTitle(title: CharSequence): Boolean = checkAllItemsIfNeeded {
+ focusedElementTitle == title
+}
-fun UiDevice.hasElementWithTitle(title: CharSequence): Boolean =
- checkAllItemsIfNeeded {
- hasObject(By.copy(SELECTOR_RES_ID_ANDROID_TITLE).text(title.toString()))
- }
+fun UiDevice.hasElementWithTitle(title: CharSequence): Boolean = checkAllItemsIfNeeded {
+ hasObject(By.copy(SELECTOR_RES_ID_ANDROID_TITLE).text(title.toString()))
+}
private fun UiDevice.checkAllItemsIfNeeded(predicate: () -> Boolean): Boolean {
// Let's do one quick check first, right where we are. If it does not work - we'll do the walk.
@@ -93,4 +96,4 @@ private fun UiDevice.navigate(action: () -> Unit): Boolean {
waitForIdle()
return prevFocusedTitle != focusedElementTitle
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearPermissionUsageDetailsFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearPermissionUsageDetailsFragmentTest.kt
new file mode 100644
index 000000000..999c89fc7
--- /dev/null
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearPermissionUsageDetailsFragmentTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 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.permissionui.ui.wear
+
+import android.Manifest.permission.CAMERA
+import android.content.Intent
+import android.os.Build
+import android.permission.cts.PermissionUtils.grantPermission
+import android.permission.cts.PermissionUtils.install
+import android.permission.cts.PermissionUtils.uninstallApp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
+import com.android.permissioncontroller.permissionui.PermissionHub2Test
+import com.android.permissioncontroller.permissionui.pressHome
+import com.android.permissioncontroller.permissionui.wakeUpScreen
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for [WearPermissionUsageDetailsFragment] */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+class WearPermissionUsageDetailsFragmentTest : PermissionHub2Test() {
+ private val CAMERA_APK =
+ "/data/local/tmp/pc-permissionui/PermissionUiUseCameraPermissionApp.apk"
+ private val CAMERA_APP = "com.android.permissioncontroller.tests.appthatrequestpermission"
+ private val CAMERA_APP_LABEL = "CameraRequestApp"
+ private val CAMERA_PREF_LABEL = "Camera"
+ private val MANAGE_PERMISSION_LABEL = "Manage permission"
+ private val APP_PERMISSIONS_TITLE = "App permissions"
+ private val TIMEOUT = 30_000L
+
+ @Before
+ fun setup() {
+ assumeTrue(isWear())
+ wakeUpScreen()
+ install(CAMERA_APK)
+ grantPermission(CAMERA_APP, CAMERA)
+ accessCamera()
+ goToPermissionUsageDetails()
+ }
+
+ private fun goToPermissionUsageDetails() {
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
+ }
+
+ clickObject(CAMERA_PREF_LABEL)
+ }
+
+ @Test
+ fun testClickAppThenTransitToAppPermissionGroups() {
+ clickObject(CAMERA_APP_LABEL)
+
+ // Find the title of AppPermissionGroups.
+ waitFindObject(By.textContains(APP_PERMISSIONS_TITLE), TIMEOUT)
+ // Find the permission in the list.
+ waitFindObject(By.textContains(CAMERA_PREF_LABEL), TIMEOUT)
+ }
+
+ @Test
+ fun testClickManagePermissionThenTransitToPermissionApps() {
+ clickObject(MANAGE_PERMISSION_LABEL)
+
+ // Find the title of PermissionApps.
+ waitFindObject(By.textContains(CAMERA_PREF_LABEL), TIMEOUT)
+ // Find the test app is in the app list.
+ waitFindObject(By.textContains(CAMERA_APP_LABEL), TIMEOUT)
+ }
+
+ @After
+ fun tearDown() {
+ uninstallApp(CAMERA_APP)
+ pressHome()
+ }
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearPermissionUsageFragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearPermissionUsageFragmentTest.kt
new file mode 100644
index 000000000..e37b97874
--- /dev/null
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearPermissionUsageFragmentTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2023 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.permissionui.ui.wear
+
+import android.Manifest.permission.CAMERA
+import android.Manifest.permission.READ_CALENDAR
+import android.app.AppOpsManager
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Process
+import android.permission.cts.PermissionUtils.grantPermission
+import android.permission.cts.PermissionUtils.install
+import android.permission.cts.PermissionUtils.uninstallApp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
+import com.android.permissioncontroller.permissionui.PermissionHub2Test
+import com.android.permissioncontroller.permissionui.pressHome
+import com.android.permissioncontroller.permissionui.wakeUpScreen
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for [WearPermissionUsageFragment] */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+class WearPermissionUsageFragmentTest : PermissionHub2Test() {
+ private val CAMERA_APK =
+ "/data/local/tmp/pc-permissionui/PermissionUiUseCameraPermissionApp.apk"
+ private val CAMERA_APP_LABEL = "CameraRequestApp"
+ private val CAMERA_PREF_LABEL = "Camera"
+
+ private val CALENDAR_APK =
+ "/data/local/tmp/pc-permissionui/PermissionUiReadCalendarPermissionApp.apk"
+ private val CALENDAR_APP_LABEL = "CalendarRequestApp"
+ private val CALENDAR_PREF_LABEL = "Calendar"
+
+ private val TEST_PACKAGE_NAME =
+ "com.android.permissioncontroller.tests.appthatrequestpermission"
+
+ private val SHOW_SYSTEM_LABEL = "Show system"
+ private val HIDE_SYSTEM_LABEL = "Hide system"
+ private val TIMEOUT = 30_000L
+
+ @Before
+ fun setup() {
+ assumeTrue(isWear())
+ wakeUpScreen()
+ }
+
+ @Test
+ fun testShowSystem() {
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
+ }
+
+ clickObject(SHOW_SYSTEM_LABEL)
+ waitFindObject(By.textContains(HIDE_SYSTEM_LABEL), TIMEOUT)
+
+ clickObject(HIDE_SYSTEM_LABEL)
+ waitFindObject(By.textContains(SHOW_SYSTEM_LABEL), TIMEOUT)
+ }
+
+ @Test
+ fun testTransitToPermissionUsageDetails() {
+ install(CAMERA_APK)
+ grantPermission(TEST_PACKAGE_NAME, CAMERA)
+ accessCamera()
+
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
+ }
+
+ clickObject(CAMERA_PREF_LABEL)
+
+ waitFindObject(By.textContains(CAMERA_APP_LABEL), TIMEOUT)
+ }
+
+ @Test
+ fun testTransitToPermissionApps() {
+ install(CALENDAR_APK)
+ grantPermission(TEST_PACKAGE_NAME, READ_CALENDAR)
+
+ accessCalendar()
+
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
+ }
+
+ clickObject(CALENDAR_PREF_LABEL)
+
+ waitFindObject(By.textContains(CALENDAR_PREF_LABEL), TIMEOUT)
+ waitFindObject(By.textContains(CALENDAR_APP_LABEL), TIMEOUT)
+ }
+
+ private fun accessCalendar() {
+ runWithShellPermissionIdentity {
+ eventually {
+ assertThat(
+ context.packageManager.getPermissionFlags(
+ READ_CALENDAR,
+ TEST_PACKAGE_NAME,
+ Process.myUserHandle()
+ ) and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
+ )
+ .isNotEqualTo(0)
+ }
+
+ eventually {
+ assertThat(
+ context
+ .getSystemService(AppOpsManager::class.java)
+ .startOp(
+ AppOpsManager.OPSTR_READ_CALENDAR,
+ context.packageManager.getPackageUid(TEST_PACKAGE_NAME, 0),
+ TEST_PACKAGE_NAME,
+ null,
+ null
+ )
+ )
+ .isEqualTo(AppOpsManager.MODE_ALLOWED)
+ }
+ }
+ }
+
+ @After
+ fun tearDown() {
+ uninstallApp(TEST_PACKAGE_NAME)
+ pressHome()
+ }
+}
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearUtils.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearUtils.kt
new file mode 100644
index 000000000..cf8098f01
--- /dev/null
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/wear/WearUtils.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 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.permissionui.ui.wear
+
+import android.content.pm.PackageManager
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
+import org.junit.Assert.assertNotNull
+
+private const val TIMEOUT = 30_000L
+
+fun isWear() =
+ InstrumentationRegistry.getInstrumentation()
+ .targetContext
+ .packageManager
+ .hasSystemFeature(PackageManager.FEATURE_WATCH)
+
+fun clickObject(text: String) {
+ eventually {
+ val obj = waitFindObject(By.textContains(text), TIMEOUT)
+ assertNotNull(obj)
+ obj.click()
+ }
+}
diff --git a/SafetyCenter/Annotations/Android.bp b/SafetyCenter/Annotations/Android.bp
index 852d734b0..c04f40333 100644
--- a/SafetyCenter/Annotations/Android.bp
+++ b/SafetyCenter/Annotations/Android.bp
@@ -32,7 +32,6 @@ java_library {
":safetycenter-annotations-sources",
],
libs: [
- "androidx.annotation_annotation",
"jsr305",
],
apex_available: [
diff --git a/SafetyCenter/Config/TEST_MAPPING b/SafetyCenter/Config/TEST_MAPPING
index c35d3d777..d8a356636 100644
--- a/SafetyCenter/Config/TEST_MAPPING
+++ b/SafetyCenter/Config/TEST_MAPPING
@@ -9,7 +9,7 @@
"name": "SafetyCenterConfigTests[com.google.android.permission.apex]",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/SafetyCenter/ConfigLintChecker/java/android/os/Build.java b/SafetyCenter/ConfigLintChecker/java/android/os/Build.java
index 531b6e481..4a58e04fc 100644
--- a/SafetyCenter/ConfigLintChecker/java/android/os/Build.java
+++ b/SafetyCenter/ConfigLintChecker/java/android/os/Build.java
@@ -24,7 +24,11 @@ public final class Build {
public static final class VERSION_CODES {
/** Constant used in the Safety Center config code. */
public static final int TIRAMISU = 33;
+
/** Constant used in the Safety Center config code. */
public static final int UPSIDE_DOWN_CAKE = 34;
+
+ /** Constant used in the Safety Center config code. */
+ public static final int VANILLA_ICE_CREAM = 35;
}
}
diff --git a/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java b/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java
index dbfaa56b1..cfe99071c 100644
--- a/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java
+++ b/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java
@@ -18,6 +18,7 @@ package com.android.modules.utils.build;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM;
/** Stub class to compile the linter for host execution. */
public final class SdkLevel {
@@ -42,4 +43,9 @@ public final class SdkLevel {
public static boolean isAtLeastU() {
return sSdkInt >= UPSIDE_DOWN_CAKE;
}
+
+ /** Method used in the Safety Center config code. */
+ public static boolean isAtLeastV() {
+ return sSdkInt >= VANILLA_ICE_CREAM;
+ }
}
diff --git a/SafetyCenter/Resources/res/raw-v35/safety_center_config.xml b/SafetyCenter/Resources/res/raw-v35/safety_center_config.xml
new file mode 100644
index 000000000..5d626757c
--- /dev/null
+++ b/SafetyCenter/Resources/res/raw-v35/safety_center_config.xml
@@ -0,0 +1,147 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="AndroidLockScreenSources"
+ title="@com.android.safetycenter.resources:string/lock_screen_sources_title"
+ summary="@com.android.safetycenter.resources:string/lock_screen_sources_summary">
+ <dynamic-safety-source
+ id="AndroidLockScreen"
+ packageName="com.android.settings"
+ profile="primary_profile_only"
+ title="@com.android.safetycenter.resources:string/lock_screen_title"
+ summary="@com.android.safetycenter.resources:string/lock_screen_summary_disabled"
+ searchTerms="@com.android.safetycenter.resources:string/lock_screen_search_terms"
+ initialDisplayState="disabled"
+ notificationsAllowed="true"/>
+ <dynamic-safety-source
+ id="AndroidBiometrics"
+ packageName="com.android.settings"
+ profile="all_profiles"
+ title="@com.android.safetycenter.resources:string/biometrics_title"
+ titleForWork="@com.android.safetycenter.resources:string/biometrics_title_for_work"
+ searchTerms="@com.android.safetycenter.resources:string/biometrics_search_terms"
+ initialDisplayState="hidden"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="AndroidCellularNetworkSecuritySources"
+ title="@com.android.safetycenter.resources:string/cellular_network_security_title"
+ summary="@com.android.safetycenter.resources:string/cellular_network_security_summary">
+ <dynamic-safety-source
+ id="AndroidCellularNetworkSecurity"
+ packageName="com.android.phone"
+ profile="primary_profile_only"
+ notificationsAllowed="true"
+ initialDisplayState="hidden"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="AndroidPrivacySources"
+ title="@com.android.safetycenter.resources:string/privacy_sources_title"
+ summary="@com.android.safetycenter.resources:string/privacy_sources_summary"
+ statelessIconType="privacy">
+ <static-safety-source
+ id="AndroidPermissionManager"
+ profile="primary_profile_only"
+ intentAction="android.intent.action.MANAGE_PERMISSIONS"
+ title="@com.android.safetycenter.resources:string/permission_manager_title"
+ summary="@com.android.safetycenter.resources:string/permission_manager_summary"
+ searchTerms="@com.android.safetycenter.resources:string/permission_manager_search_terms"/>
+ <static-safety-source
+ id="AndroidPermissionUsage"
+ profile="primary_profile_only"
+ intentAction="android.intent.action.REVIEW_PERMISSION_USAGE"
+ title="@com.android.safetycenter.resources:string/permission_usage_title"
+ summary="@com.android.safetycenter.resources:string/permission_usage_summary"
+ searchTerms="@com.android.safetycenter.resources:string/permission_usage_search_terms"/>
+ <dynamic-safety-source
+ id="AndroidHealthConnect"
+ profile="primary_profile_only"
+ packageName="com.android.healthconnect.controller"
+ initialDisplayState="hidden"
+ refreshOnPageOpenAllowed="false"
+ title="@com.android.safetycenter.resources:string/health_connect_title"
+ searchTerms="@com.android.safetycenter.resources:string/health_connect_search_terms"/>
+ <dynamic-safety-source
+ id="AndroidPrivacyAppDataSharingUpdates"
+ packageName="com.android.permissioncontroller"
+ profile="primary_profile_only"
+ initialDisplayState="hidden"
+ refreshOnPageOpenAllowed="true"
+ title="@com.android.safetycenter.resources:string/app_data_sharing_updates_title"
+ searchTerms="@com.android.safetycenter.resources:string/app_data_sharing_updates_search_terms"/>
+ <static-safety-source
+ id="AndroidPrivacyControls"
+ profile="primary_profile_only"
+ intentAction="android.settings.PRIVACY_CONTROLS"
+ title="@com.android.safetycenter.resources:string/privacy_controls_title"
+ summary="@com.android.safetycenter.resources:string/privacy_controls_summary"
+ searchTerms="@com.android.safetycenter.resources:string/privacy_controls_search_terms"/>
+ <issue-only-safety-source
+ id="AndroidAccessibility"
+ packageName="com.android.permissioncontroller"
+ profile="all_profiles"
+ notificationsAllowed="true"
+ refreshOnPageOpenAllowed="true"/>
+ <issue-only-safety-source
+ id="AndroidNotificationListener"
+ packageName="com.android.permissioncontroller"
+ profile="primary_profile_only"
+ notificationsAllowed="true"
+ refreshOnPageOpenAllowed="true"/>
+ <issue-only-safety-source
+ id="AndroidBackgroundLocation"
+ packageName="com.android.permissioncontroller"
+ profile="all_profiles"
+ notificationsAllowed="true"
+ refreshOnPageOpenAllowed="true"/>
+ <issue-only-safety-source
+ id="AndroidPermissionAutoRevoke"
+ packageName="com.android.permissioncontroller"
+ profile="all_profiles"
+ notificationsAllowed="true"
+ refreshOnPageOpenAllowed="true"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="AndroidAdvancedSources"
+ title="@com.android.safetycenter.resources:string/advanced_title">
+ <dynamic-safety-source
+ id="AndroidWorkPolicyInfo"
+ packageName="com.android.permissioncontroller"
+ profile="primary_profile_only"
+ title="@com.android.safetycenter.resources:string/work_policy_title"
+ initialDisplayState="hidden"
+ refreshOnPageOpenAllowed="true"/>
+ <static-safety-source
+ id="AndroidMoreSettings"
+ profile="primary_profile_only"
+ intentAction="com.android.settings.MORE_SECURITY_PRIVACY_SETTINGS"
+ title="@com.android.safetycenter.resources:string/more_settings_title"
+ summary="@com.android.safetycenter.resources:string/more_settings_summary"
+ searchTerms="@com.android.safetycenter.resources:string/more_settings_search_terms"/>
+ <dynamic-safety-source
+ id="AndroidPrivateSpace"
+ packageName="com.android.settings"
+ profile="primary_profile_only"
+ title="@com.android.safetycenter.resources:string/private_space_title"
+ summary="@com.android.safetycenter.resources:string/private_space_summary"
+ searchTerms="@com.android.safetycenter.resources:string/private_space_search_terms"
+ initialDisplayState="hidden"
+ maxSeverityLevel="0"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Resources/res/values-af-v34/strings.xml b/SafetyCenter/Resources/res/values-af-v34/strings.xml
index d54ed46b1..ad8401412 100644
--- a/SafetyCenter/Resources/res/values-af-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-af-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Gesondheid, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Datadelingopdaterings vir ligging"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, datadeling, datadelingopdaterings, datadelingopdaterings vir ligging, deling"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Advertensieprivaatheid"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Pasmaak inligting wat apps gebruik om vir jou advertensies te wys"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"advertensies, advertensieprivaatheid, privacy sandbox, advertensie-onderwerpe, appvoorgestelde advertensies, advertensiemeting"</string>
<string name="advanced_title" msgid="6259362998269627310">"Ander instellings"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Meer sekuriteit en privaatheid"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Outovul, kennisgewings en meer"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Jou werkbeleidinligting"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-af-v35/strings.xml b/SafetyCenter/Resources/res/values-af-v35/strings.xml
new file mode 100644
index 000000000..42ccf293c
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-af-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Selnetwerksekuriteit"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Netwerktipe, enkripsie, kennisgewingkontroles"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privaat ruimte"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Stel privaat ruimte op, en meer"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privaat ruimte"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-af/strings.xml b/SafetyCenter/Resources/res/values-af/strings.xml
index e46fb352d..ff0fc873d 100644
--- a/SafetyCenter/Resources/res/values-af/strings.xml
+++ b/SafetyCenter/Resources/res/values-af/strings.xml
@@ -28,7 +28,7 @@
<string name="privacy_sources_title" msgid="4061110826457365957">"Privaatheid"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Kontroleskerm, toestemmings, kontroles"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privaatheidkontroleskerm"</string>
- <string name="permission_usage_summary" msgid="5323079206029964468">"Wys watter programme onlangs toestemmings gebruik het"</string>
+ <string name="permission_usage_summary" msgid="5323079206029964468">"Wys watter apps onlangs toestemmings gebruik het"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Privaatheid, Privaatheidkontroleskerm"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Toestemmingbestuurder"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Beheer apptoegang tot jou data"</string>
diff --git a/SafetyCenter/Resources/res/values-am-v34/strings.xml b/SafetyCenter/Resources/res/values-am-v34/strings.xml
index 13d95ff68..6b94d58ca 100644
--- a/SafetyCenter/Resources/res/values-am-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-am-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"ጤና፣ የጤና አገናኝ"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"የአካባቢ የውሂብ ማጋራት ዝማኔዎች"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ውሂብ፣ የውሂብ ማጋራት፣ የውሂብ ማጋራት ዝማኔዎች፣ የአካባቢ የውሂብ ማጋራት ዝማኔዎች፣ ማጋራት"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"የማስታወቂያ ግላዊነት"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"መተግበሪያዎች ማስታወቂያዎችን ለማሳየት የሚጠቀሙበትን መረጃ ያብጁ"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ማስታወቂያዎች፣ የማስታወቂያ ግላዊነት፣ የግላዊነት Sandbox፣ የማስታወቂያ ርዕሶች፣ በመተግበሪያ የተጠቆሙ ማስታወቂያዎች፣ የማስታወቂያ ልኬት"</string>
<string name="advanced_title" msgid="6259362998269627310">"ሌሎች ቅንብሮች"</string>
- <string name="more_settings_title" msgid="9033454654010697185">"ተጨማሪ ደህንነት &amp; እና ግላዊነት"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"ተጨማሪ ደህንነት እና ግላዊነት"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ራስ-ሙላ፣ ማሳወቂያዎች እና ሌሎችም"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"የእርስዎ የሥራ መመሪያ መረጃ"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-am-v35/strings.xml b/SafetyCenter/Resources/res/values-am-v35/strings.xml
new file mode 100644
index 000000000..948277aa8
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-am-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"የተንቀሳቃሽ ስልክ አውታረ መረብ ደህንነት"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"የአውታረ መረብ ዓይነት፣ ምስጠራ፣ የማሳወቂያ መቆጣጠሪያዎች"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"የግል ቦታ"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"የግል ቦታን እና ሌሎችን ያዋቅሩ"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"የግል ቦታ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-am/strings.xml b/SafetyCenter/Resources/res/values-am/strings.xml
index 32e7fd8b5..5d0914a79 100644
--- a/SafetyCenter/Resources/res/values-am/strings.xml
+++ b/SafetyCenter/Resources/res/values-am/strings.xml
@@ -20,9 +20,9 @@
<string name="safetyCenterResourcesAppLabel" msgid="4043334186295695930">"የደህንነት ማዕከል መርጃዎች"</string>
<string name="lock_screen_sources_title" msgid="3317906280484627707">"የመሣሪያ ቁልፍ"</string>
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
- <string name="lock_screen_title" msgid="4069104894527169877">"የማያ ገጽ ቁልፍ"</string>
+ <string name="lock_screen_title" msgid="4069104894527169877">"የማያ ገፅ ቁልፍ"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"ገና ምንም መረጃ የለም"</string>
- <string name="lock_screen_search_terms" msgid="2678486357779794826">"የመሣሪያ ቁልፍ፣ የማያ ገጽ መቆለፊያ፣ የማያ ገጽ ቁልፍ፣ የማያ ገጽ ቁልፍ፣ የይለፍ ቃል፣ ፒን፣ ስርዓተ ጥለት"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"የመሣሪያ ቁልፍ፣ የማያ ገፅ መቆለፊያ፣ የማያ ገፅ ቁልፍ፣ የማያ ገፅ ቁልፍ፣ የይለፍ ቃል፣ ፒን፣ ስርዓተ ጥለት"</string>
<string name="biometrics_title" msgid="5859504610285212938">"ባዮሜትሪክስ"</string>
<string name="biometrics_search_terms" msgid="6040319118762671981">"የጣት አሻራ፣ ጣት፣ የጣት አሻራ ያክሉ፣ በመልክ መክፈት፣ መልክ"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"ግላዊነት"</string>
diff --git a/SafetyCenter/Resources/res/values-ar-v34/strings.xml b/SafetyCenter/Resources/res/values-ar-v34/strings.xml
index d4cd4ec86..4449b333c 100644
--- a/SafetyCenter/Resources/res/values-ar-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ar-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"‏الصحة، Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"تعديلات مشاركة بيانات الموقع الجغرافي"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"البيانات، مشاركة البيانات، تعديلات مشاركة البيانات، تعديلات مشاركة بيانات الموقع الجغرافي، المشاركة"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"الخصوصية في عرض الإعلانات"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"تخصيص المعلومات التي تستخدمها التطبيقات لعرض الإعلانات لك"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"الإعلانات، الخصوصية في عرض الإعلانات، مبادرة حماية الخصوصية، مواضيع الإعلانات، الإعلانات المقترَحة من التطبيقات، قياس أداء الإعلانات"</string>
<string name="advanced_title" msgid="6259362998269627310">"إعدادات أخرى"</string>
<string name="more_settings_title" msgid="9033454654010697185">"تعزيز الأمان والخصوصية"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"الملء التلقائي والإشعارات والمزيد"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"معلومات سياسة العمل"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ar-v35/strings.xml b/SafetyCenter/Resources/res/values-ar-v35/strings.xml
new file mode 100644
index 000000000..969edb241
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ar-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"أمان شبكة الجوّال"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"عناصر التحكم في نوع الشبكة والتشفير والإشعارات"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"مساحة خاصة"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ضبط إعدادات مساحة خاصة وغير ذلك"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"مساحة خاصة"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ar/strings.xml b/SafetyCenter/Resources/res/values-ar/strings.xml
index e0e027987..2a97af99a 100644
--- a/SafetyCenter/Resources/res/values-ar/strings.xml
+++ b/SafetyCenter/Resources/res/values-ar/strings.xml
@@ -30,7 +30,7 @@
<string name="permission_usage_title" msgid="3633779688945350407">"لوحة بيانات الخصوصية"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"عرض التطبيقات التي استخدمت الأذونات مؤخرًا"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"الخصوصية، لوحة بيانات الخصوصية"</string>
- <string name="permission_manager_title" msgid="5277347862821255015">"مدير الأذونات"</string>
+ <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>
diff --git a/SafetyCenter/Resources/res/values-as-v34/strings.xml b/SafetyCenter/Resources/res/values-as-v34/strings.xml
index 094f41869..e8a084491 100644
--- a/SafetyCenter/Resources/res/values-as-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-as-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"স্বাস্থ্য, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"অৱস্থানৰ বাবে ডেটা শ্বেয়াৰ কৰাৰ আপডে’ট"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ডেটা, ডেটা শ্বেয়াৰ কৰা, ডেটা শ্বেয়াৰ কৰা সম্পৰ্কীয় আপডে’ট, অৱস্থানৰ বাবে ডেটা শ্বেয়াৰ কৰাৰ আপডে’ট, শ্বেয়াৰ কৰা"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"বিজ্ঞাপনৰ গোপনীয়তা"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"আপোনাক বিজ্ঞাপন দেখুৱাবলৈ তথ্য এপৰ ব্যৱহাৰ কাষ্টমাইজ কৰক"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"বিজ্ঞাপন, বিজ্ঞাপনৰ গোপনীয়তা, প্ৰাইভেচি ছেণ্ডবক্স, বিজ্ঞাপনৰ বিষয়বস্তু, এপে পৰামৰ্শ দিয়া বিজ্ঞাপন, বিজ্ঞাপনৰ জোখ-মাখ"</string>
<string name="advanced_title" msgid="6259362998269627310">"অন্য ছেটিং"</string>
<string name="more_settings_title" msgid="9033454654010697185">"অধিক সুৰক্ষা আৰু গোপনীয়তা"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"স্বয়ংক্ৰিয়ভাৱে পূৰ হোৱাৰ সুবিধা, জাননী আৰু আন বহুতো"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"আপোনাৰ কৰ্মস্থানৰ নীতিৰ তথ্য"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-as-v35/strings.xml b/SafetyCenter/Resources/res/values-as-v35/strings.xml
new file mode 100644
index 000000000..5923f97cd
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-as-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"চেলুলাৰ নেটৱৰ্কৰ সুৰক্ষা"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"নেটৱৰ্কৰ প্ৰকাৰ, এনক্ৰিপশ্বন, জাননীৰ নিয়ন্ত্ৰণসমূহ"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"ব্যক্তিগত স্পে’চ"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ব্যক্তিগত স্পে’চ আৰু আন বহুতো ছেটআপ কৰক"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"ব্যক্তিগত স্পে’চ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-az-v34/strings.xml b/SafetyCenter/Resources/res/values-az-v34/strings.xml
index 6fba4f5c0..474dec23c 100644
--- a/SafetyCenter/Resources/res/values-az-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-az-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Sağlamlıq, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Məkan üzrə data paylaşımı yenilikləri"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Data paylaşımı, Data paylaşımı yenilikləri, Məkan üzrə data paylaşımı, paylaşım"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Reklam məxfiliyi"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Tətbiqlərin sizə reklam göstərmək üçün istifadə etdiyi məlumatları fərdiləşdirin"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklamlar, reklam məxfiliyi, təhlükəsiz sandbox, reklam mövzuları, tətbiq tərəfindən təklif edilən reklamlar, reklam ölçüsü"</string>
<string name="advanced_title" msgid="6259362998269627310">"Digər ayarlar"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Güvənlik və məxfilik ayarlarının ardı"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Avto doldurma, bildirişlər və s."</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"İş siyasəti məlumatı"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-az-v35/strings.xml b/SafetyCenter/Resources/res/values-az-v35/strings.xml
new file mode 100644
index 000000000..39ea9a982
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-az-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobil şəbəkə təhlükəsizliyi"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Şəbəkə növü, şifrələmə, bildiriş nizamlayıcıları"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Şəxsi yer"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Şəxsi yer və s. ayarlayın"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Şəxsi yer"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-b+sr+Latn-v34/strings.xml b/SafetyCenter/Resources/res/values-b+sr+Latn-v34/strings.xml
index 0709cce9f..a61fc129a 100644
--- a/SafetyCenter/Resources/res/values-b+sr+Latn-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-b+sr+Latn-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"zdravlje, povezivanje zdravlja"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Ažuriranja deljenja podataka za lokaciju"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"podaci, deljenje podataka, ažuriranja deljenja podataka, ažuriranja deljenja podataka za lokaciju, deljenje"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privatnost sa oglasima"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Prilagodite informacije koje aplikacije koriste da bi vam prikazivale oglase"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"oglasi, privatnost sa oglasima, zaštićeno okruženje privatnosti, teme oglasa, oglasi koje predlažu aplikacije, merenje oglasa"</string>
<string name="advanced_title" msgid="6259362998269627310">"Ostala podešavanja"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Još bezbednosti i privatnosti"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automatsko popunjavanje, obaveštenja i drugo"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informacije o smernicama za posao"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-b+sr+Latn-v35/strings.xml b/SafetyCenter/Resources/res/values-b+sr+Latn-v35/strings.xml
new file mode 100644
index 000000000..c877922b0
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-b+sr+Latn-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Bezbednost mobilne mreže"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tip mreže, šifrovanje, kontrole obaveštenja"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privatni prostor"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Podesite privatni prostor i drugo"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privatni prostor"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml b/SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml
index 607286886..c4328fe12 100644
--- a/SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml
+++ b/SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml
@@ -20,7 +20,7 @@
<string name="safetyCenterResourcesAppLabel" msgid="4043334186295695930">"Resursi Centra za bezbednost"</string>
<string name="lock_screen_sources_title" msgid="3317906280484627707">"Zaključavanje uređaja"</string>
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
- <string name="lock_screen_title" msgid="4069104894527169877">"Zaključavanje ekrana"</string>
+ <string name="lock_screen_title" msgid="4069104894527169877">"Otključavanje ekrana"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Još nema informacija"</string>
<string name="lock_screen_search_terms" msgid="2678486357779794826">"zaključavanje uređaja, zaključavanje ekrana, zaključani ekran, lozinka, PIN, šablon"</string>
<string name="biometrics_title" msgid="5859504610285212938">"Biometrija"</string>
diff --git a/SafetyCenter/Resources/res/values-be-v34/strings.xml b/SafetyCenter/Resources/res/values-be-v34/strings.xml
index 765791502..6c348b44c 100644
--- a/SafetyCenter/Resources/res/values-be-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-be-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Здароўе, Здароўе і спорт"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Змяненні ў абагульванні даных пра месцазнаходжанне"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Даныя, абагульванне даных, Змяненні ў абагульванні даных, Змяненні ў абагульванні даных пра месцазнаходжанне, абагульванне"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Прыватнасць у рэкламе"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Наладзьце інфармацыю, якую праграмы выкарыстоўваюць для паказу вам рэкламы"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"рэклама, прыватнасць у рэкламе, Privacy Sandbox, тэмы аб\'явы, рэклама, прапанаваная праграмай, эфектыўнасць рэкламы"</string>
<string name="advanced_title" msgid="6259362998269627310">"Іншыя налады"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Дадатковыя налады бяспекі і прыватнасці"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Аўтазапаўненне, апавяшчэнні і іншае"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Інфармацыя пра вашу палітыку арганізацыі"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-be-v35/strings.xml b/SafetyCenter/Resources/res/values-be-v35/strings.xml
new file mode 100644
index 000000000..27799b191
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-be-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Бяспека сотавай сеткі"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Тып сеткі, шыфраванне, налады апавяшчэнняў"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Прыватная вобласць"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Наладжванне прыватнай вобласці і не толькі"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Прыватная вобласць"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-be/strings.xml b/SafetyCenter/Resources/res/values-be/strings.xml
index d62a5c256..b1d0b58cc 100644
--- a/SafetyCenter/Resources/res/values-be/strings.xml
+++ b/SafetyCenter/Resources/res/values-be/strings.xml
@@ -28,10 +28,10 @@
<string name="privacy_sources_title" msgid="4061110826457365957">"Прыватнасць"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Панэль кіравання, дазволы, налады"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Панэль кіравання доступам"</string>
- <string name="permission_usage_summary" msgid="5323079206029964468">"Паказ праграм, якія нядаўна выкарыстоўвалі дазволы"</string>
+ <string name="permission_usage_summary" msgid="5323079206029964468">"Глядзіце, якія праграмы нядаўна выкарыстоўвалі дазволы"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Прыватнасць, панэль кіравання доступам"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Менеджар дазволаў"</string>
- <string name="permission_manager_summary" msgid="8099852107340970790">"Кіраванне доступам праграм да вашых даных"</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_summary" msgid="2402066941190435424">"Кіраванне доступам прылады да мікрафона, камеры і іншых функцый"</string>
diff --git a/SafetyCenter/Resources/res/values-bg-v34/strings.xml b/SafetyCenter/Resources/res/values-bg-v34/strings.xml
index 6557b3e60..4799cdaec 100644
--- a/SafetyCenter/Resources/res/values-bg-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-bg-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"здраве, health connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Актуализации за споделянето на данни за местоположението"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"данни, споделяне на данни, актуализации за споделянето на данни, актуализации за споделянето на данни за местоположението, споделяне"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Поверителност при рекламите"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Персонализиране на информацията, която приложенията използват, за да ви показват реклами"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"реклами, поверителност при рекламите, privacy sandbox, рекламни теми, предлагани от приложенията реклами, измерване на рекламите"</string>
<string name="advanced_title" msgid="6259362998269627310">"Други настройки"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Още настройки за сигурност и поверителност"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Автоматично попълване, известия и др."</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Информация за служебните правила"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-bg-v35/strings.xml b/SafetyCenter/Resources/res/values-bg-v35/strings.xml
new file mode 100644
index 000000000..bb0de817f
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-bg-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Сигурност на мобилната мрежа"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Тип мрежа, шифроване, контроли за известията"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Лично пространство"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Настройване на лично пространство и др."</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Лично пространство"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-bn-v34/strings.xml b/SafetyCenter/Resources/res/values-bn-v34/strings.xml
index ff9fc5063..02435f415 100644
--- a/SafetyCenter/Resources/res/values-bn-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-bn-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"স্বাস্থ্য, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"লোকেশনের জন্য ডেটা শেয়ারিং সম্পর্কিত আপডেট"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ডেটা, ডেটা শেয়ার করা, ডেটা শেয়ার করা সংক্রান্ত আপডেট, লোকেশনের জন্য ডেটা শেয়ারিং সম্পর্কিত আপডেট, শেয়ার করা"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"বিজ্ঞাপন সংক্রান্ত গোপনীয়তা"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"আপনাকে বিজ্ঞাপন দেখানোর জন্য অ্যাপের ব্যবহার করা তথ্য কাস্টমাইজ করুন"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"বিজ্ঞাপন, বিজ্ঞাপন সংক্রান্ত গোপনীয়তা, প্রাইভেসি স্যান্ডবক্স, বিজ্ঞাপনের বিষয়, অ্যাপের সাজেস্ট করা বিজ্ঞাপন, বিজ্ঞাপন সম্পর্কিত পরিমাপ"</string>
<string name="advanced_title" msgid="6259362998269627310">"অন্যান্য সেটিংস"</string>
<string name="more_settings_title" msgid="9033454654010697185">"আরও সুরক্ষা ও গোপনীয়তা"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"অটোফিল, বিজ্ঞপ্তি ও আরও অনেক কিছু"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"আপনার অফিসের নীতি সংক্রান্ত তথ্য"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-bn-v35/strings.xml b/SafetyCenter/Resources/res/values-bn-v35/strings.xml
new file mode 100644
index 000000000..6b8104a04
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-bn-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"মোবাইল নেটওয়ার্কের সুরক্ষা"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"নেটওয়ার্কের ধরন, এনক্রিপশন, বিজ্ঞপ্তির নিয়ন্ত্রণ"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"ব্যক্তিগত স্পেস"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"\'ব্যক্তিগত স্পেস\' সেট-আপ ও আরও অনেক কিছু করুন"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"ব্যক্তিগত স্পেস"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-bs-v34/strings.xml b/SafetyCenter/Resources/res/values-bs-v34/strings.xml
index e7c2d65b4..f863c8824 100644
--- a/SafetyCenter/Resources/res/values-bs-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-bs-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Zdravlje, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Promjene u dijeljenju podataka za lokaciju"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Podaci, dijeljenje podataka, ažuriranja dijeljenja podataka, ažuriranje dijeljenja podataka za lokaciju, dijeljenje"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privatnost pri izloženosti oglasima"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Prilagodite informacije koje aplikacije koriste da vam prikazuju oglase"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"oglasi, privatnost pri izloženosti oglasima, okruženje zaštićene privatnosti, teme oglasa, oglasi koje predlažu aplikacije, mjerenje oglasa"</string>
<string name="advanced_title" msgid="6259362998269627310">"Ostale postavke"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Dodatna sigurnost i privatnost"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automatsko popunjavanje, obavještenja i drugo"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informacije o radnim pravilima"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-bs-v35/strings.xml b/SafetyCenter/Resources/res/values-bs-v35/strings.xml
new file mode 100644
index 000000000..fc5a58c4d
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-bs-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sigurnost mobilne mreže"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Vrsta mreže, šifriranje i kontrole obavještenja"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privatni prostor"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Postavite privatni prostor i drugo"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privatni prostor"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ca-v34/strings.xml b/SafetyCenter/Resources/res/values-ca-v34/strings.xml
index 88dfe0879..fb88118fd 100644
--- a/SafetyCenter/Resources/res/values-ca-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ca-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"salut, salut connectada"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Canvis en la compartició de dades per a la ubicació"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"dades, compartició de dades, canvis en la compartició de dades, canvis en la compartició de dades per a la ubicació, compartició"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privadesa d\'anuncis"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personalitza la informació que les aplicacions utilitzen per mostrar-te anuncis"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"anuncis, privadesa d\'anuncis, privacy sandbox, temes d\'anuncis, anuncis suggerits per aplicacions, mesurament d\'anuncis"</string>
<string name="advanced_title" msgid="6259362998269627310">"Altres opcions de configuració"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Més seguretat i privadesa"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Emplenament automàtic, notificacions i més"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informació de la teva política de treball"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ca-v35/strings.xml b/SafetyCenter/Resources/res/values-ca-v35/strings.xml
new file mode 100644
index 000000000..6a76c3032
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ca-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Seguretat de la xarxa mòbil"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipus de xarxa, encriptació, controls de notificació"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espai privat"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configura l\'espai privat i més"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espai privat"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ca/strings.xml b/SafetyCenter/Resources/res/values-ca/strings.xml
index 950d0b79e..97fb5f8be 100644
--- a/SafetyCenter/Resources/res/values-ca/strings.xml
+++ b/SafetyCenter/Resources/res/values-ca/strings.xml
@@ -18,7 +18,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="safetyCenterResourcesAppLabel" msgid="4043334186295695930">"Recursos del Centre de seguretat"</string>
- <string name="lock_screen_sources_title" msgid="3317906280484627707">"Bloqueig de dispositius"</string>
+ <string name="lock_screen_sources_title" msgid="3317906280484627707">"Bloqueig del dispositiu"</string>
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Bloqueig de pantalla"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Encara no hi ha informació"</string>
diff --git a/SafetyCenter/Resources/res/values-cs-v34/strings.xml b/SafetyCenter/Resources/res/values-cs-v34/strings.xml
index 9e2cf4981..4f9c811aa 100644
--- a/SafetyCenter/Resources/res/values-cs-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-cs-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"zdraví, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Aktualizace sdílení údajů o poloze"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"data, sdílení dat, aktualizace sdílení dat, aktualizace sdílení údajů o poloze, sdílení"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Ochrana soukromí v reklamách"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Přizpůsobte údaje, které aplikace používají k zobrazování reklam"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklamy, ochrana, soukromí v reklamách, privacy sandbox, témata reklam, reklamy navrhované aplikacemi, měření reklam"</string>
<string name="advanced_title" msgid="6259362998269627310">"Další nastavení"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Další zabezpečení a ochrana soukromí"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automatické vyplňování, oznámení atd."</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informace o vašich pracovních zásadách"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-cs-v35/strings.xml b/SafetyCenter/Resources/res/values-cs-v35/strings.xml
new file mode 100644
index 000000000..c09ce3722
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-cs-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Zabezpečení mobilní sítě"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Nastavení typu sítě, šifrování a oznámení"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Soukromý prostor"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Nastavte si Soukromý prostor atd."</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Soukromý prostor"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-da-v34/strings.xml b/SafetyCenter/Resources/res/values-da-v34/strings.xml
index b43adc2cf..d4dbdf7b9 100644
--- a/SafetyCenter/Resources/res/values-da-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-da-v34/strings.xml
@@ -18,17 +18,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="lock_screen_sources_title" msgid="5493678510117489865">"Enhedsoplåsning"</string>
- <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometri til arbejdet"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometri til arbejdsprofil"</string>
<string name="privacy_sources_summary" msgid="4083646673569677049">"Tilladelser, kontrolpanel, indstillinger"</string>
<string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Opdateringer om deling af lokationsdata"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, datadeling, opdateringer om datadeling, opdateringer om deling af lokationsdata, deling"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privatliv ved annoncering"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Tilpas de oplysninger, apps bruger til at vise dig annoncer"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"annoncer, privatliv ved annoncering, privacy sandbox, annonceemner, annoncer foreslået af apps, annoncemåling"</string>
<string name="advanced_title" msgid="6259362998269627310">"Andre indstillinger"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Mere sikkerhed og privatliv"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofyld, notifikationer m.m."</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Oplysninger om din arbejdspolitik"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-da-v35/strings.xml b/SafetyCenter/Resources/res/values-da-v35/strings.xml
new file mode 100644
index 000000000..e5c3c2173
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-da-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sikkerhed for mobilnetværk"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Netværkstype, kryptering, notifikationsstyring"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privat område"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Konfigurer et privat rum m.m."</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privat område"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-da/strings.xml b/SafetyCenter/Resources/res/values-da/strings.xml
index 16df659b8..59d275320 100644
--- a/SafetyCenter/Resources/res/values-da/strings.xml
+++ b/SafetyCenter/Resources/res/values-da/strings.xml
@@ -24,7 +24,7 @@
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Der er ingen oplysninger endnu"</string>
<string name="lock_screen_search_terms" msgid="2678486357779794826">"Enhedslås, skærmlås, låseskærm, adgangskode, pinkode, mønster"</string>
<string name="biometrics_title" msgid="5859504610285212938">"Biometri"</string>
- <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingeraftryk, finger, tilføj fingeraftryk, ansigtslås, ansigt"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingeraftryk, finger, tilføj fingeraftryk, ansigtsoplåsning, ansigt"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privatliv"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Kontrolpanel, tilladelser, styringselementer"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privatlivspanel"</string>
diff --git a/SafetyCenter/Resources/res/values-de-v34/strings.xml b/SafetyCenter/Resources/res/values-de-v34/strings.xml
index 7d9310728..4289c14a0 100644
--- a/SafetyCenter/Resources/res/values-de-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-de-v34/strings.xml
@@ -24,13 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Änderungen bei der Weitergabe von Standortdaten"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Daten, Datenweitergabe, Aktualisierungen der Datenweitergabe, Aktualisierungen der Weitergabe von Standortdaten, Weitergabe"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Datenschutz bei Anzeigen"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Informationen anpassen, die Apps verwenden, um dir Werbung anzuzeigen"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"Anzeigen, Datenschutz bei Anzeigen, Privacy Sandbox, Werbethemen, von Apps vorgeschlagene Werbung, Analyse von Werbeanzeigen"</string>
- <!-- no translation found for advanced_title (6259362998269627310) -->
- <skip />
- <!-- no translation found for more_settings_title (9033454654010697185) -->
- <skip />
+ <string name="advanced_title" msgid="6259362998269627310">"Weitere Einstellungen"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"Mehr Sicherheit und Datenschutz"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofill, Benachrichtigungen und mehr"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informationen zu den Arbeitsrichtlinien"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-de-v35/strings.xml b/SafetyCenter/Resources/res/values-de-v35/strings.xml
new file mode 100644
index 000000000..b3573e2a8
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-de-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sicherheit von Mobilfunknetzen"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Netzwerktyp, Verschlüsselung, Benachrichtigungseinstellungen"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privater Bereich"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Privaten Bereich einrichten und mehr"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privater Bereich"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-el-v34/strings.xml b/SafetyCenter/Resources/res/values-el-v34/strings.xml
index cf3976381..651f580eb 100644
--- a/SafetyCenter/Resources/res/values-el-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-el-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"υγεία, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Ενημερώσεις στην κοινοποίηση δεδομένων για την τοποθεσία"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"δεδομένα, κοινοποίηση δεδομένων, ενημερώσεις κοινοποίησης δεδομένων, ενημερώσεις κοινοποίησης δεδομένων για την τοποθεσία, κοινοποίηση"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Απόρρητο διαφημίσεων"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Προσαρμόστε τις πληροφορίες που χρησιμοποιούν οι εφαρμογές για την εμφάνιση των διαφημίσεών σας"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"διαφημίσεις, απόρρητο διαφημίσεων, πλαίσιο ιδιωτικότητας, θέματα διαφημίσεων, διαφημίσεις που προτείνονται από εφαρμογές, μέτρηση διαφημίσεων"</string>
<string name="advanced_title" msgid="6259362998269627310">"Άλλες ρυθμίσεις"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Περισσότερες ρυθμίσεις για την ασφάλεια και το απόρρητο"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Αυτόματη συμπλήρωση, ειδοποιήσεις κ.ά."</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Πληροφορίες σχετικά με την πολιτική εργασίας"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-el-v35/strings.xml b/SafetyCenter/Resources/res/values-el-v35/strings.xml
new file mode 100644
index 000000000..51e8f6580
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-el-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Ασφάλεια δικτύου κινητής τηλεφωνίας"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Τύπος δικτύου, κρυπτογράφηση, στοιχεία ελέγχου ειδοποιήσεων"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Ιδιωτικός χώρος"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Ρύθμιση Ιδιωτικού χώρου κ.ά."</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Ιδιωτικός χώρος"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml
index d7f503f7c..af32d279d 100644
--- a/SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Data sharing updates for location"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Data sharing, Data sharing updates, Data sharing updates for location, sharing"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Ads privacy"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Customise info that apps use to show you ads"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ads, ad privacy, privacy sandbox, ad topics, app-suggested ads, ad measurement"</string>
<string name="advanced_title" msgid="6259362998269627310">"Other settings"</string>
- <string name="more_settings_title" msgid="9033454654010697185">"More security &amp; privacy"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"More security and privacy"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofill, notifications and more"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Your work policy info"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rAU-v35/strings.xml b/SafetyCenter/Resources/res/values-en-rAU-v35/strings.xml
new file mode 100644
index 000000000..41d4bb4ef
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rAU-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobile network security"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Network type, encryption, notification controls"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Private Space"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Set up Private Space, and more"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Private Space"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml
index 11cf54414..05cc98e75 100644
--- a/SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Data sharing updates for location"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Data sharing, Data sharing updates, Data sharing updates for location, sharing"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Ad privacy"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Customize info apps use to show you ads"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ads, ad privacy, privacy sandbox, ad topics, app-suggested ads, ad measurement"</string>
<string name="advanced_title" msgid="6259362998269627310">"Other settings"</string>
<string name="more_settings_title" msgid="9033454654010697185">"More security and privacy"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofill, notifications, and more"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Your work policy info"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rCA-v35/strings.xml b/SafetyCenter/Resources/res/values-en-rCA-v35/strings.xml
new file mode 100644
index 000000000..b5de7b0ef
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rCA-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Cellular network security"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Network type, encryption, notification controls"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Private Space"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Setup Private Space, and more"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Private Space"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml
index d7f503f7c..af32d279d 100644
--- a/SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Data sharing updates for location"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Data sharing, Data sharing updates, Data sharing updates for location, sharing"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Ads privacy"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Customise info that apps use to show you ads"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ads, ad privacy, privacy sandbox, ad topics, app-suggested ads, ad measurement"</string>
<string name="advanced_title" msgid="6259362998269627310">"Other settings"</string>
- <string name="more_settings_title" msgid="9033454654010697185">"More security &amp; privacy"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"More security and privacy"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofill, notifications and more"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Your work policy info"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rGB-v35/strings.xml b/SafetyCenter/Resources/res/values-en-rGB-v35/strings.xml
new file mode 100644
index 000000000..41d4bb4ef
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rGB-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobile network security"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Network type, encryption, notification controls"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Private Space"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Set up Private Space, and more"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Private Space"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml
index d7f503f7c..af32d279d 100644
--- a/SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Data sharing updates for location"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Data sharing, Data sharing updates, Data sharing updates for location, sharing"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Ads privacy"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Customise info that apps use to show you ads"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ads, ad privacy, privacy sandbox, ad topics, app-suggested ads, ad measurement"</string>
<string name="advanced_title" msgid="6259362998269627310">"Other settings"</string>
- <string name="more_settings_title" msgid="9033454654010697185">"More security &amp; privacy"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"More security and privacy"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofill, notifications and more"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Your work policy info"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rIN-v35/strings.xml b/SafetyCenter/Resources/res/values-en-rIN-v35/strings.xml
new file mode 100644
index 000000000..41d4bb4ef
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rIN-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobile network security"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Network type, encryption, notification controls"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Private Space"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Set up Private Space, and more"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Private Space"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml
index 28d4151ea..f408d1fdb 100644
--- a/SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎Health, Health Connect‎‏‎‎‏‎"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎Data sharing updates for location‎‏‎‎‏‎"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎Data, Data sharing, Data sharing updates, Data sharing updates for location, sharing‎‏‎‎‏‎"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‎‎‎‎‎Ad privacy‎‏‎‎‏‎"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎Customize info apps use to show you ads‎‏‎‎‏‎"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎ads, ad privacy, privacy sandbox, ad topics, app-suggested ads, ad measurement‎‏‎‎‏‎"</string>
<string name="advanced_title" msgid="6259362998269627310">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎Other settings‎‏‎‎‏‎"</string>
<string name="more_settings_title" msgid="9033454654010697185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‎‏‎More security &amp; privacy‎‏‎‎‏‎"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎Autofill, notifications, and more‎‏‎‎‏‎"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎Your work policy info‎‏‎‎‏‎"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rXC-v35/strings.xml b/SafetyCenter/Resources/res/values-en-rXC-v35/strings.xml
new file mode 100644
index 000000000..4b9327829
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rXC-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‏‎‏‎Cellular network security‎‏‎‎‏‎"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎Network type, encryption, notification controls‎‏‎‎‏‎"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‎Private Space‎‏‎‎‏‎"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎Setup Private Space, and more‎‏‎‎‏‎"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‎‎Private Space‎‏‎‎‏‎"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml b/SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml
index 2bfbc6ed7..4158efa92 100644
--- a/SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Actualizaciones del uso compartido de los datos de ubicación"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"datos, uso compartido de los datos, actualizaciones del uso compartido de los datos, actualizaciones del uso compartido de los datos de ubicación, uso compartido"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privacidad en los anuncios"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personaliza la información que usan las apps para mostrarte anuncios"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"anuncios, privacidad en los anuncios, privacy sandbox, temas de anuncios, anuncios sugeridos por apps, medición de anuncios"</string>
<string name="advanced_title" msgid="6259362998269627310">"Otras opciones"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Mayor seguridad y privacidad"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autocompletar, notificaciones y más"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Información sobre la política de tu trabajo"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-es-rUS-v35/strings.xml b/SafetyCenter/Resources/res/values-es-rUS-v35/strings.xml
new file mode 100644
index 000000000..b6227fa5f
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-es-rUS-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Seguridad de red móvil"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipo de red, encriptación, controles de notificaciones"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espacio privado"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configura el Espacio privado y mucho más"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espacio privado"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-es-v34/strings.xml b/SafetyCenter/Resources/res/values-es-v34/strings.xml
index 1a087e2e6..d03b74605 100644
--- a/SafetyCenter/Resources/res/values-es-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-es-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Salud, Salud conectada"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Cambios en los datos compartidos de ubicación"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"datos, compartir datos, cambios en los datos que se comparten, cambios en los datos compartidos de ubicación, compartir"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privacidad en la publicidad"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personaliza la información que usan las aplicaciones para mostrarte anuncios"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"anuncios, privacidad en la publicidad, Privacy Sandbox, temas de anuncios, anuncios sugeridos por aplicaciones, medición de anuncios"</string>
<string name="advanced_title" msgid="6259362998269627310">"Otros ajustes"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Más seguridad y privacidad"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autocompletar, notificaciones y más"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Información sobre la política de tu trabajo"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-es-v35/strings.xml b/SafetyCenter/Resources/res/values-es-v35/strings.xml
new file mode 100644
index 000000000..fcd0a9870
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-es-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Seguridad de la red móvil"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipo de red, cifrado, controles de notificaciones"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espacio privado"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configura el espacio privado y más"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espacio privado"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-et-v34/strings.xml b/SafetyCenter/Resources/res/values-et-v34/strings.xml
index 6e9d06cc2..914dcc54b 100644
--- a/SafetyCenter/Resources/res/values-et-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-et-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Tervis, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Andmete jagamise värskendused asukoha kohta"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Andmed, andmete jagamine, andmete jagamise värskendused, andmete jagamise värskendused asukoha kohta, jagamine"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Reklaamide privaatsus"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Kohandage teavet, mida rakendused kasutavad teile reklaamide näitamiseks"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklaamid, reklaamide privaatsus, privaatsuse liivakast, reklaamiteemad, rakenduse soovitatud reklaamid, reklaamide mõõtmine"</string>
<string name="advanced_title" msgid="6259362998269627310">"Muud seaded"</string>
- <string name="more_settings_title" msgid="9033454654010697185">"Rohkem turvalisust ja privaatsust"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"Rohkem turvalisuse ja privaatsuse kohta"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automaattäide, märguanded jm"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Teie töökoha eeskirjade teave"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-et-v35/strings.xml b/SafetyCenter/Resources/res/values-et-v35/strings.xml
new file mode 100644
index 000000000..dab6f073e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-et-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobiilsidevõrgu turvalisus"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Võrgu tüüp, krüpteerimine, märguannete juhtnupud"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privaatne ruum"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Privaatse ruumi seadistamine ja muu"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privaatne ruum"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-eu-v34/strings.xml b/SafetyCenter/Resources/res/values-eu-v34/strings.xml
index 3785ce577..20f2cfbaf 100644
--- a/SafetyCenter/Resources/res/values-eu-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-eu-v34/strings.xml
@@ -22,13 +22,11 @@
<string name="privacy_sources_summary" msgid="4083646673569677049">"Baimenak, panela eta ezarpenak"</string>
<string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
<string name="health_connect_search_terms" msgid="4998970586245680829">"Osasuna, Health Connect"</string>
- <string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Kokapen-datuak partekatzeko moduaren inguruko berritasunak"</string>
- <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"datuak, datuak partekatzea, datuak partekatzeko moduaren inguruko berritasunak, kokapen-datuak partekatzeko moduaren inguruko berritasunak, partekatzea"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Iragarkien pribatutasuna"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Pertsonalizatu aplikazioek iragarkiak erakusteko erabiltzen duten informazioa"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"iragarkiak, iragarkien pribatutasuna, privacy sandbox-a, iragarkien gaiak, aplikazioek iradokitako iragarkiak, iragarkien neurketa"</string>
+ <string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Kokapen-datuak partekatzeko aukeraren berritasunak"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"datuak, datuak partekatzeko aukera, datuak partekatzeko aukeraren berritasunak, kokapen-datuak partekatzeko aukeraren berritasunak, partekatzea"</string>
<string name="advanced_title" msgid="6259362998269627310">"Beste ezarpen batzuk"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Segurtasun eta pribatutasun gehiago"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Betetze automatikoa, jakinarazpenak eta abar"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Laneko gidalerroei buruzko informazioa"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-eu-v35/strings.xml b/SafetyCenter/Resources/res/values-eu-v35/strings.xml
new file mode 100644
index 000000000..02e53aedd
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-eu-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sare mugikorraren segurtasuna"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Sare mota, enkriptatzea, jakinarazpenak kontrolatzeko aukerak"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Eremu pribatua"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Konfiguratu eremu pribatua eta abar"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Eremu pribatua"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-fa-v34/strings.xml b/SafetyCenter/Resources/res/values-fa-v34/strings.xml
index 618c7f5f3..d8bf2b762 100644
--- a/SafetyCenter/Resources/res/values-fa-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-fa-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"‏سلامت، Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"به‌روزرسانی‌های هم‌رسانی داده برای مکان"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"داده، هم‌رسانی داده، به‌روزرسانی‌های هم‌رسانی داده، به‌روزرسانی‌های هم‌رسانی داده مکان، هم‌رسانی"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"حریم خصوصی آگهی"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"سفارشی‌سازی اطلاعات مورداستفاده برنامه‌ها برای نمایش آگهی به شما"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"آگهی‌ها، حریم خصوصی آگهی، جعبه ایمنی حریم خصوصی، موضوع آگهی‌ها، آگهی‌های پیشنهادی برنامه، سنجش آگهی"</string>
<string name="advanced_title" msgid="6259362998269627310">"تنظیمات دیگر"</string>
<string name="more_settings_title" msgid="9033454654010697185">"امنیت و حریم خصوصی بیشتر"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"تکمیل خودکار، اعلان‌ها، و موارد دیگر"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"اطلاعات خط‌مشی کاری شما"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-fa-v35/strings.xml b/SafetyCenter/Resources/res/values-fa-v35/strings.xml
new file mode 100644
index 000000000..45b2b8605
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-fa-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"امنیت شبکه تلفن همراه"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"نوع شبکه، رمزگذاری، کنترل‌های اعلان"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"فضای خصوصی"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"راه‌اندازی «فضای خصوصی»، و موارد دیگر"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"فضای خصوصی"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-fa/strings.xml b/SafetyCenter/Resources/res/values-fa/strings.xml
index 41a3121ea..cf277b7c1 100644
--- a/SafetyCenter/Resources/res/values-fa/strings.xml
+++ b/SafetyCenter/Resources/res/values-fa/strings.xml
@@ -37,7 +37,7 @@
<string name="privacy_controls_summary" msgid="2402066941190435424">"کنترل دسترسی دستگاه به میکروفون، دوربین، و غیره"</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_title" msgid="1126833338772188155">"تنظیمات ایمنی بیشتر"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"رمزگذاری، اطلاعات اعتباری، و غیره"</string>
<string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"تنظیمات حریم خصوصی بیشتر"</string>
diff --git a/SafetyCenter/Resources/res/values-fi-v34/strings.xml b/SafetyCenter/Resources/res/values-fi-v34/strings.xml
index 71ef63fe1..3b0f8300b 100644
--- a/SafetyCenter/Resources/res/values-fi-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-fi-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Terveys, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Sijaintidatan jakamisen päivitykset"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, datan jakaminen, datan jakamisen päivitykset, sijaintidatan jakamisen päivitykset, jakaminen"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Mainosyksityisyys"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Muuta tietoja, joiden perusteella sovellukset näyttävät sinulle mainoksia"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"mainokset, mainosyksityisyys, privacy sandbox, mainosaiheet, sovellusten ehdottamat mainokset, mainosten mittaus"</string>
<string name="advanced_title" msgid="6259362998269627310">"Muut asetukset"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Lisää tietoturva‑ ja yksityisyysasetuksia"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automaattinen täyttö, ilmoitukset ja muuta"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Työkäytäntötietosi"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-fi-v35/strings.xml b/SafetyCenter/Resources/res/values-fi-v35/strings.xml
new file mode 100644
index 000000000..e280f71e1
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-fi-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobiiliverkon tietoturva"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Verkon tyyppi, salaus, ilmoitusvalinnat"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Yksityinen tila"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Ota esimerkiksi yksityinen tila käyttöön"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Yksityinen tila"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml b/SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml
index 3097bb762..f1a8ad068 100644
--- a/SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Santé, Connexion Santé"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Mises à jour des pratiques de partage des données pour la localisation"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Données, Partage des données, Mises à jour du partage des données, Mises à jour du partage des données pour la localisation, partage"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Confidentialité des annonces"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personnalisez les renseignements utilisés par les applications pour vous montrer des annonces"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"annonces, confidentialité de l\'annonce, bac à sable de confidentialité, sujet de l\'annonce, annonces suggérées par les applications, mesure de l\'annonce"</string>
<string name="advanced_title" msgid="6259362998269627310">"Autres paramètres"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Plus de paramètres de sécurité et de confidentialité"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Remplissage automatique, notifications, etc."</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Infos sur votre politique de travail"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-fr-rCA-v35/strings.xml b/SafetyCenter/Resources/res/values-fr-rCA-v35/strings.xml
new file mode 100644
index 000000000..dbae68c8e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-fr-rCA-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sécurité du réseau cellulaire"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Contrôles du type de réseau, du chiffrement et des notifications"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espace privé"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configuration de l\'espace privé, et plus"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espace privé"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-fr-rCA/strings.xml b/SafetyCenter/Resources/res/values-fr-rCA/strings.xml
index 1ae13ac4b..a835c7139 100644
--- a/SafetyCenter/Resources/res/values-fr-rCA/strings.xml
+++ b/SafetyCenter/Resources/res/values-fr-rCA/strings.xml
@@ -40,7 +40,7 @@
<string name="advanced_security_title" msgid="1126833338772188155">"Plus de paramètres de sécurité"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Chiffrement, authentifiants et plus"</string>
<string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
- <string name="advanced_privacy_title" msgid="1117725225706176643">"Plus de paramètres de sécurité"</string>
+ <string name="advanced_privacy_title" msgid="1117725225706176643">"Plus de paramètres de confidentialité"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Remplissage automatique, commandes d\'activité et plus"</string>
<string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-fr-v34/strings.xml b/SafetyCenter/Resources/res/values-fr-v34/strings.xml
index f4f320e94..92af5db49 100644
--- a/SafetyCenter/Resources/res/values-fr-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-fr-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Santé, Santé Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Mises à jour du partage des données pour la localisation"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Données, partage de données, mises à jour du partage des données, mises à jour du partage des données pour la localisation, partage"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Confidentialité des annonces"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personnalisez les infos qu\'utilisent les applis pour vous proposer des annonces"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"annonces, confidentialité des annonces, Privacy Sandbox, thèmes d\'annonces, annonces suggérées par les applis, mesure des performances des annonces"</string>
<string name="advanced_title" msgid="6259362998269627310">"Autres paramètres"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Sécurité et confidentialité renforcées"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Saisie automatique, notifications et plus"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Infos sur vos règles professionnelles"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-fr-v35/strings.xml b/SafetyCenter/Resources/res/values-fr-v35/strings.xml
new file mode 100644
index 000000000..306c769ae
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-fr-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sécurité des réseaux mobiles"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Type de réseau, chiffrement, paramètres de notifications"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espace privé"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configurez votre espace privé et bien plus"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espace privé"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-gl-v34/strings.xml b/SafetyCenter/Resources/res/values-gl-v34/strings.xml
index cdb2fd71f..16f9f9781 100644
--- a/SafetyCenter/Resources/res/values-gl-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-gl-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Saúde, Saúde conectada"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Actualizacións do uso compartido de datos de localización"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"datos, uso compartido de datos, actualizacións do uso compartido de datos, actualizacións do uso compartido de datos de localización, uso compartido"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privacidade dos anuncios"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personaliza a información que usan as aplicacións para mostrarche anuncios"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"anuncios, privacidade nos anuncios, privacy sandbox, temas dos anuncios, anuncios suxeridos polas aplicacións, medición de anuncios"</string>
<string name="advanced_title" msgid="6259362998269627310">"Outras opcións de configuración"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Máis seguranza e privacidade"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autocompletar, notificacións e outras opcións"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Información sobre a túa política do traballo"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-gl-v35/strings.xml b/SafetyCenter/Resources/res/values-gl-v35/strings.xml
new file mode 100644
index 000000000..c3ef9f8d8
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-gl-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Seguranza da rede de telefonía móbil"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipo de rede, encriptación, controis de notificacións"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espazo privado"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configura o espazo privado e moito máis"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espazo privado"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-gu-v34/strings.xml b/SafetyCenter/Resources/res/values-gu-v34/strings.xml
index 62f1adeda..0517fad28 100644
--- a/SafetyCenter/Resources/res/values-gu-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-gu-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"આરોગ્ય, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"લોકેશન માટે ડેટા શેરિંગ સંબંધિત અપડેટ"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ડેટા, ડેટા શેરિંગ, ડેટા શેરિંગ સંબંધિત અપડેટ, લોકેશન માટે ડેટા શેરિંગ સંબંધિત અપડેટ, શેરિંગ"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"જાહેરાત સંબંધિત પ્રાઇવસી"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"તમને જાહેરાતો બતાવવા માટે ઍપ દ્વારા ઉપયોગમાં લેવાતી માહિતી કસ્ટમાઇઝ કરો"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"જાહેરાતો, જાહેરાત સંબંધિત પ્રાઇવસી, પ્રાઇવસી સૅન્ડબૉક્સ, જાહેરાતના વિષયો, ઍપ દ્વારા સૂચવેલી જાહેરાતો, જાહેરાતની માપણી"</string>
<string name="advanced_title" msgid="6259362998269627310">"અન્ય સેટિંગ"</string>
<string name="more_settings_title" msgid="9033454654010697185">"વધુ સુરક્ષા અને પ્રાઇવસી"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ઑટોમૅટિક રીતે ભરવાની સુવિધા, નોટિફિકેશન અને બીજું ઘણું"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"તમારી ઑફિસની પૉલિસીની માહિતી"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-gu-v35/strings.xml b/SafetyCenter/Resources/res/values-gu-v35/strings.xml
new file mode 100644
index 000000000..a3eb9ff61
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-gu-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"સેલ્યુલર નેટવર્ક સંબંધી સુરક્ષા"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"નેટવર્કનો પ્રકાર, એન્ક્રિપ્શન, નોટિફિકેશનના નિયંત્રણો"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"ખાનગી સ્પેસ"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ખાનગી સ્પેસનું સેટઅપ કરો અને બીજું ઘણું કરો"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"ખાનગી સ્પેસ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-hi-v34/strings.xml b/SafetyCenter/Resources/res/values-hi-v34/strings.xml
index 6dd399b93..3a941dc97 100644
--- a/SafetyCenter/Resources/res/values-hi-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-hi-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"जगह की जानकारी शेयर करने के तरीके के बारे में अपडेट"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"डेटा, डेटा शेयर करना, डेटा शेयर करने के अपडेट, जगह की जानकारी शेयर करने के बारे में अपडेट, शेयर करना"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"विज्ञापन देखने वाले की निजता बनाए रखने की सुविधा"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"अपने हिसाब से यह तय करें कि ऐप्लिकेशन आपको विज्ञापन दिखाने के लिए, कौनसी जानकारी का इस्तेमाल कर सकते हैं"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"विज्ञापन, विज्ञापन देखने वाले की निजता बनाए रखना, प्राइवसी सैंडबॉक्स, विज्ञापन का विषय, ऐप्लिकेशन के सुझाए गए विज्ञापन, और विज्ञापन की परफ़ॉर्मेंस का आकलन करना"</string>
<string name="advanced_title" msgid="6259362998269627310">"बेहतर सेटिंग"</string>
<string name="more_settings_title" msgid="9033454654010697185">"सुरक्षा और निजता की ज़्यादा सेटिंग"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ऑटोमैटिक भरना, सूचनाएं वगैरह"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"आपके ऑफ़िस की नीति के बारे में जानकारी"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-hi-v35/strings.xml b/SafetyCenter/Resources/res/values-hi-v35/strings.xml
new file mode 100644
index 000000000..6a3d68007
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-hi-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"मोबाइल नेटवर्क की सुरक्षा"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"नेटवर्क टाइप, एन्क्रिप्ट करने का तरीका, सूचनाएं कंट्रोल करने की सेटिंग"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"प्राइवेट स्पेस"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"प्राइवेट स्पेस सेटअप करें और अन्य काम करें"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"प्राइवेट स्पेस"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-hr-v34/strings.xml b/SafetyCenter/Resources/res/values-hr-v34/strings.xml
index cf938415d..ef467b89b 100644
--- a/SafetyCenter/Resources/res/values-hr-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-hr-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Zdravlje, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Ažuriranja o dijeljenju podataka za lokaciju"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"podaci, dijeljenje podataka, ažuriranja dijeljenja podataka, ažuriranja dijeljenja podataka za lokaciju, dijeljenje"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Zaštita privatnosti u online oglašavanju"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Prilagodite podatke koje aplikacije koriste da bi vam prikazivale oglase"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"oglasi, zaštita privatnosti u online oglašavanju, privacy sandbox, teme oglasa, oglasi koje predlažu aplikacije, mjerenje oglasa"</string>
<string name="advanced_title" msgid="6259362998269627310">"Druge postavke"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Više sigurnosti i privatnosti"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automatsko popunjavanje, obavijesti i drugo"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informacije o pravilima za poslovne uređaje"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-hr-v35/strings.xml b/SafetyCenter/Resources/res/values-hr-v35/strings.xml
new file mode 100644
index 000000000..20a0c34ba
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-hr-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sigurnost mobilne mreže"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Vrsta mreže, šifriranje, kontrole obavijesti"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privatni prostor"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Postavljanje privatnog prostora i drugo"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privatni prostor"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-hr/strings.xml b/SafetyCenter/Resources/res/values-hr/strings.xml
index a4c43add7..7306fcc76 100644
--- a/SafetyCenter/Resources/res/values-hr/strings.xml
+++ b/SafetyCenter/Resources/res/values-hr/strings.xml
@@ -22,16 +22,16 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Zaključavanje zaslona"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Još nema podataka"</string>
- <string name="lock_screen_search_terms" msgid="2678486357779794826">"Zaključavanje uređaja, zaključavanje zaslona, zaključan zaslon, zaključani zaslon, zaporka, PIN, uzorak"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Zaključavanje uređaja, zaključavanje zaslona, zaključani zaslon, zaključani zaslon, zaporka, PIN, uzorak"</string>
<string name="biometrics_title" msgid="5859504610285212938">"Biometrijski podaci"</string>
<string name="biometrics_search_terms" msgid="6040319118762671981">"Otisak prsta, prst, dodavanje otiska prsta, otključavanje licem, lice"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privatnost"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Nadzorna ploča, dopuštenja, kontrole"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Nadzorna ploča za privatnost"</string>
- <string name="permission_usage_summary" msgid="5323079206029964468">"Prikaži aplikacije koje su nedavno upotrebljavale dopuštenja"</string>
+ <string name="permission_usage_summary" msgid="5323079206029964468">"Pregledajte aplikacije koje su nedavno upotrebljavale dopuštenja"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Privatnost, nadzorna ploča za privatnost"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Upravitelj dopuštenja"</string>
- <string name="permission_manager_summary" msgid="8099852107340970790">"Upravljajte pristupom aplikacija svojim podacima"</string>
+ <string name="permission_manager_summary" msgid="8099852107340970790">"Upravljajte kojim podacima mogu pristupati vaše aplikacije"</string>
<string name="permission_manager_search_terms" msgid="2895147613099694722">"Dopuštenja, upravitelj dopuštenja"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Kontrole privatnosti"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontroliranje pristupanja uređaja mikrofonu, kameri i ostalome"</string>
diff --git a/SafetyCenter/Resources/res/values-hu-v34/strings.xml b/SafetyCenter/Resources/res/values-hu-v34/strings.xml
index a228b2d8f..811e192cb 100644
--- a/SafetyCenter/Resources/res/values-hu-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-hu-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Egészség, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"A helyadatok megosztását érintő frissítések"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Adatok, adatmegosztás, adatmegosztási változások, helyadatokat érintő adatmegosztási változások, megosztás"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Hirdetésekhez kapcsolódó adatvédelem"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Személyre szabhatja azokat az információkat, amelyeket az alkalmazások arra használnak, hogy hirdetéseket jelenítsenek meg Önnek"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"hirdetések, hirdetésekhez kapcsolódó adatvédelem, privacy sandbox, hirdetéstéma, alkalmazások által javasolt hirdetések, hirdetésmérés"</string>
<string name="advanced_title" msgid="6259362998269627310">"Egyéb beállítások"</string>
<string name="more_settings_title" msgid="9033454654010697185">"További biztonsági és adatvédelmi beállítások"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automatikus kitöltés, értesítések és egyebek"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Munkahelyi házirendekkel kapcsolatos adatok"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-hu-v35/strings.xml b/SafetyCenter/Resources/res/values-hu-v35/strings.xml
new file mode 100644
index 000000000..561aefc34
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-hu-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobilhálózat biztonsága"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Hálózattípus, titkosítás, értesítésvezérlők"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privát terület"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Privát terület beállítása és egyebek"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privát terület"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-hy-v34/strings.xml b/SafetyCenter/Resources/res/values-hy-v34/strings.xml
index 3c126a203..158cec7c0 100644
--- a/SafetyCenter/Resources/res/values-hy-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-hy-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Տեղադրության մասին տվյալներով կիսվելու թույլտվության թարմացում"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Տվյալներ, Տվյալների փոխանցում, Տվյալներով կիսվելու եղանակի փոփոխություն, Տեղադրության մասին տվյալներով կիսվելու թույլտվության թարմացում, փոխանցում"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Գովազդի գաղտնիություն"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Անհատականացված տեղեկություններ, որոնք հավելվածներն օգտագործում են՝ ձեզ գովազդ ցուցադրելու համար"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"գովազդներ, գովազդի գաղտնիություն, privacy sandbox, գովազդի թեմաներ, հավելվածների կողմից առաջարկվող գովազդներ, գովազդի արդյունավետության գնահատում"</string>
<string name="advanced_title" msgid="6259362998269627310">"Այլ կարգավորումներ"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Անվտանգության և գաղտնիության լրացուցիչ կարգավորումներ"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Ինքնալրացում, ծանուցումներ և ավելին"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Տեղեկություններ աշխատանքային կանոնների մասին"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-hy-v35/strings.xml b/SafetyCenter/Resources/res/values-hy-v35/strings.xml
new file mode 100644
index 000000000..9e6cde773
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-hy-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Բջջային ցանցի անվտանգություն"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Ցանցի տեսակը, գաղտնագրում, ծանուցումների կառավարում"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Անձնական տարածք"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Կարգավորեք անձնական տարածքը և ավելին"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Անձնական տարածք"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-in-v34/strings.xml b/SafetyCenter/Resources/res/values-in-v34/strings.xml
index bbb8aa1ae..9d375e022 100644
--- a/SafetyCenter/Resources/res/values-in-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-in-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Pembaruan berbagi data untuk lokasi"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Berbagi data, Pembaruan berbagi data, Pembaruan berbagi data untuk lokasi, berbagi"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privasi iklan"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Sesuaikan info yang digunakan aplikasi untuk menampilkan iklan kepada Anda"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"iklan, privasi iklan, privacy sandbox, topik iklan, iklan yang disarankan aplikasi, pengukuran iklan"</string>
<string name="advanced_title" msgid="6259362998269627310">"Setelan lainnya"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Keamanan &amp; privasi lainnya"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Isi otomatis, notifikasi, dan lainnya"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Info kebijakan profil kerja Anda"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-in-v35/strings.xml b/SafetyCenter/Resources/res/values-in-v35/strings.xml
new file mode 100644
index 000000000..924d010c6
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-in-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Keamanan jaringan seluler"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Jenis jaringan, enkripsi, kontrol notifikasi"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Ruang Pribadi"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Menyiapkan Ruang Pribadi, dan lainnya"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Ruang Pribadi"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-in/strings.xml b/SafetyCenter/Resources/res/values-in/strings.xml
index 4c3c2109b..d5579aa32 100644
--- a/SafetyCenter/Resources/res/values-in/strings.xml
+++ b/SafetyCenter/Resources/res/values-in/strings.xml
@@ -28,10 +28,10 @@
<string name="privacy_sources_title" msgid="4061110826457365957">"Privasi"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dasbor, izin, kontrol"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Dasbor privasi"</string>
- <string name="permission_usage_summary" msgid="5323079206029964468">"Menampilkan aplikasi yang baru-baru ini menggunakan izin"</string>
+ <string name="permission_usage_summary" msgid="5323079206029964468">"Tampilkan aplikasi yang baru-baru ini menggunakan izin"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Privasi, Dasbor privasi"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Pengelola izin"</string>
- <string name="permission_manager_summary" msgid="8099852107340970790">"Mengontrol akses aplikasi ke data Anda"</string>
+ <string name="permission_manager_summary" msgid="8099852107340970790">"Kontrol akses aplikasi ke data Anda"</string>
<string name="permission_manager_search_terms" msgid="2895147613099694722">"Izin, Pengelola izin"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Kontrol privasi"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontrol akses perangkat ke mikrofon, kamera, dan lainnya"</string>
diff --git a/SafetyCenter/Resources/res/values-is-v34/strings.xml b/SafetyCenter/Resources/res/values-is-v34/strings.xml
index 6eb83bf7d..6533a7ac3 100644
--- a/SafetyCenter/Resources/res/values-is-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-is-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Heilsa, Heilsutenging"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Uppfærslur um gagnadeilingu varðandi staðsetningu"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Gögn, gagnadeiling, uppfærslur á gagnadeilingu, uppfærslur á gagnadeilingu varðandi staðsetningu, deiling"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Persónuvernd auglýsinga"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Sérsníddu hvaða upplýsingar forrit nota til að birta þér auglýsingar"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"auglýsingar, persónuvernd auglýsinga, privacy sandbox, efni auglýsinga, auglýsingatillögur forrita, auglýsingamælingar"</string>
<string name="advanced_title" msgid="6259362998269627310">"Aðrar stillingar"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Aukið öryggi og persónuvernd"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Sjálfvirk útfylling, tilkynningar og fleira"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Upplýsingar um vinnureglurnar þínar"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-is-v35/strings.xml b/SafetyCenter/Resources/res/values-is-v35/strings.xml
new file mode 100644
index 000000000..3ee0b4078
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-is-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Öryggi farsímakerfis"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tegund netkerfis, dulkóðun, tilkynningastýringar"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Einkarými"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Setja upp einkarými og fleira"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Einkarými"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-it-v34/strings.xml b/SafetyCenter/Resources/res/values-it-v34/strings.xml
index fdc8d1cd9..ffbb82c41 100644
--- a/SafetyCenter/Resources/res/values-it-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-it-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Salute, Connessione Salute"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Aggiornamenti alla condivisione dei dati per la posizione"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Dati, Condivisione dei dati, Aggiornamenti alla condivisione dei dati, Aggiornamenti alla condivisione dei dati per la posizione, Condivisione"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privacy per gli annunci"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personalizza le informazioni usate dalle app per mostrarti annunci"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"annunci, privacy per gli annunci, privacy sandbox, argomenti degli annunci, annunci suggeriti dalle app, misurazione degli annunci"</string>
<string name="advanced_title" msgid="6259362998269627310">"Altre impostazioni"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Più sicurezza e privacy"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Compilazione automatica, notifiche e altro ancora"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informazioni sulle norme di lavoro"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-it-v35/strings.xml b/SafetyCenter/Resources/res/values-it-v35/strings.xml
new file mode 100644
index 000000000..6161a1f24
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-it-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sicurezza rete mobile"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipo di rete, crittografia, controlli di notifica"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Spazio privato"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configura lo Spazio privato e altro ancora"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Spazio privato"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-it/strings.xml b/SafetyCenter/Resources/res/values-it/strings.xml
index b3ff1668c..02f431a9a 100644
--- a/SafetyCenter/Resources/res/values-it/strings.xml
+++ b/SafetyCenter/Resources/res/values-it/strings.xml
@@ -24,7 +24,7 @@
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ancora nessuna informazione"</string>
<string name="lock_screen_search_terms" msgid="2678486357779794826">"Blocco dispositivo, Blocco schermo, Schermata di blocco, Password, PIN, Sequenza"</string>
<string name="biometrics_title" msgid="5859504610285212938">"Dati biometrici"</string>
- <string name="biometrics_search_terms" msgid="6040319118762671981">"Impronta, Dito, Aggiungi impronta, Sblocco con il volto, Volto"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Impronta, Dito, Aggiungi impronta, Sblocco con il Volto, Volto"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacy"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashboard, autorizzazioni, impostazioni"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Dashboard della privacy"</string>
diff --git a/SafetyCenter/Resources/res/values-iw-v34/strings.xml b/SafetyCenter/Resources/res/values-iw-v34/strings.xml
index 245ca91bf..43296d1bf 100644
--- a/SafetyCenter/Resources/res/values-iw-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-iw-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"‏בריאות, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"עדכונים לגבי שיתוף נתונים עבור המיקום"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"נתונים, שיתוף נתונים, עדכונים לגבי שיתוף נתונים, עדכונים לגבי שיתוף נתונים עבור המיקום, שיתוף"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"פרטיות בפרסום"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"התאמה אישית של המידע שאפליקציות משתמשות בו כדי להציג לך מודעות"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"מודעות, פרטיות בפרסום, ארגז חול לפרטיות, נושאי מודעות, מודעות שאפליקציות מציעות, מדידת מודעות"</string>
<string name="advanced_title" msgid="6259362998269627310">"הגדרות אחרות"</string>
<string name="more_settings_title" msgid="9033454654010697185">"עוד אבטחה ופרטיות"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"מילוי אוטומטי, התראות ועוד"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"פרטי המדיניות של מקום העבודה"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-iw-v35/strings.xml b/SafetyCenter/Resources/res/values-iw-v35/strings.xml
new file mode 100644
index 000000000..adcea4384
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-iw-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"אבטחת הרשת הסלולרית"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"סוג הרשת, הצפנה, אמצעי בקרה של התראות"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"מרחב פרטי"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"הגדרת מרחב פרטי ועוד"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"מרחב פרטי"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ja-v34/strings.xml b/SafetyCenter/Resources/res/values-ja-v34/strings.xml
index 7bdb04e1c..8a49d1667 100644
--- a/SafetyCenter/Resources/res/values-ja-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ja-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"ヘルス, ヘルス コネクト"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"位置情報を共有する方法の更新"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"データ, データ 共有, データ 共有 更新, データ 共有 更新 位置情報, 共有"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"広告のプライバシー"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"広告を表示するためにアプリが使用する情報をカスタマイズします"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"広告, 広告のプライバシー, プライバシー サンドボックス, 広告 トピック, アプリによる広告の提案, 広告 測定"</string>
<string name="advanced_title" msgid="6259362998269627310">"その他の設定"</string>
<string name="more_settings_title" msgid="9033454654010697185">"その他のセキュリティとプライバシー"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"自動入力、通知など"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"仕事用ポリシーに関する情報"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ja-v35/strings.xml b/SafetyCenter/Resources/res/values-ja-v35/strings.xml
new file mode 100644
index 000000000..c7c9d3fe4
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ja-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"モバイル ネットワークのセキュリティ"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ネットワークの種類、暗号化、通知の管理"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"プライベート スペース"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"プライベート スペースの設定、その他"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"プライベート スペース"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ka-v34/strings.xml b/SafetyCenter/Resources/res/values-ka-v34/strings.xml
index d84af11e4..97e2afc2d 100644
--- a/SafetyCenter/Resources/res/values-ka-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ka-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"მონაცემების გაზიარების განახლებები მდებარეობისთვის"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"მონაცემები, მონაცემების გაზიარება, მონაცემების გაზიარების განახლებები, მონაცემების გაზიარების განახლებები მდებარეობისთვის, გაზიარება"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"რეკლამის კონფიდენციალურობა"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"ინფორმაციის მორგება, რომელსაც აპები იყენებს თქვენთვის რეკლამის საჩვენებლად"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"რეკლამები, რეკლამის კონფიდენციალურობა, privacy sandbox, სარეკლამო თემა, აპის შემოთავაზებული რეკლამები, რეკლამის გაზომვა"</string>
<string name="advanced_title" msgid="6259362998269627310">"სხვა პარამეტრები"</string>
<string name="more_settings_title" msgid="9033454654010697185">"მეტი უსაფრთხოება და კონფიდენციალურობა"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ავტომატური შევსება, შეტყობინებები, და სხვა"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"ინფორმაცია თქვენი სამსახურის წესების შესახებ"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ka-v35/strings.xml b/SafetyCenter/Resources/res/values-ka-v35/strings.xml
new file mode 100644
index 000000000..4549e2578
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ka-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"ფიჭური ქსელის უსაფრთხოება"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ქსელის ტიპი, დაშიფვრა, შეტყობინებების მართვის საშუალებები"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"პირადი სივრცე"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"დააყენეთ პირადი სივრცე და ა.შ."</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"პირადი სივრცე"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-kk-v34/strings.xml b/SafetyCenter/Resources/res/values-kk-v34/strings.xml
index ac7746d7e..1efaa3f6b 100644
--- a/SafetyCenter/Resources/res/values-kk-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-kk-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Денсаулық, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Локация деректерін бөлісу жаңартулары"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Деректер, Деректерді бөлісу, Деректерді бөлісу жаңартулары, Локация деректерін бөлісу жаңартулары"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Жарнама құпиялығы"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Қолданбалардың сізге жарнама көрсету үшін пайдаланатын ақпаратын реттеңіз."</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"жарнамалар, жарнамадағы құпиялық, privacy sandbox, жарнама тақырыптары, қолданба ұсынған жарнамалар, жарнама көрсеткіштерін өлшеу"</string>
<string name="advanced_title" msgid="6259362998269627310">"Басқа параметрлер"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Күшейтілген қауіпсіздік пен құпиялық"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Автотолтыру, хабарландырулар және тағы басқалар"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Жұмыс саясатыңыз туралы ақпарат"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-kk-v35/strings.xml b/SafetyCenter/Resources/res/values-kk-v35/strings.xml
new file mode 100644
index 000000000..d7f9d50ca
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-kk-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Ұялы желі қауіпсіздігі"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Желі түрі, шифрлауды, хабарландыруды басқару элементтері"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Жеке бөлме"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Жеке бөлмені реттеу және т.б."</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Жеке бөлме"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-kk/strings.xml b/SafetyCenter/Resources/res/values-kk/strings.xml
index 2d8a6ee6a..79b5204fa 100644
--- a/SafetyCenter/Resources/res/values-kk/strings.xml
+++ b/SafetyCenter/Resources/res/values-kk/strings.xml
@@ -28,7 +28,7 @@
<string name="privacy_sources_title" msgid="4061110826457365957">"Құпиялық"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Басқару тақтасы, рұқсаттар, басқару элементтері"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Құпиялық тақтасы"</string>
- <string name="permission_usage_summary" msgid="5323079206029964468">"Жақында рұқсаттарды пайдаланған қолданбаларды көрсетеді."</string>
+ <string name="permission_usage_summary" msgid="5323079206029964468">"Жақында рұқсаттарды пайдаланған қолданбаларды көрсету"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Құпиялық, құпиялық тақтасы"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Рұқсат менеджері"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Қолданбалардың деректерді пайдалану рұқсатын басқару"</string>
diff --git a/SafetyCenter/Resources/res/values-km-v34/strings.xml b/SafetyCenter/Resources/res/values-km-v34/strings.xml
index e9dd1fe35..df7009b2e 100644
--- a/SafetyCenter/Resources/res/values-km-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-km-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"សុខភាព Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"ការធ្វើបច្ចុប្បន្នភាពការចែករំលែកទិន្នន័យសម្រាប់ទីតាំង"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ទិន្នន័យ ការចែករំលែកទិន្នន័យ បច្ចុប្បន្នភាពការចែករំលែកទិន្នន័យ បច្ចុប្បន្នភាពការចែករំលែកទិន្នន័យសម្រាប់ទីតាំង ការចែករំលែក"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"ឯកជនភាពនៃការផ្សាយពាណិជ្ជកម្ម"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"ប្ដូរការប្រើប្រាស់កម្មវិធីព័ត៌មានតាមបំណង ដើម្បីបង្ហាញការផ្សាយពាណិជ្ជកម្មដល់អ្នក"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ការផ្សាយពាណិជ្ជកម្ម, ឯកជនភាពនៃការផ្សាយពាណិជ្ជកម្ម, privacy sandbox, ប្រធានបទផ្សាយពាណិជ្ជកម្ម, ការផ្សាយពាណិជ្ជកម្មដែលណែនាំដោយកម្មវិធី, ការវាស់ស្ទង់ការផ្សាយពាណិជ្ជកម្ម"</string>
<string name="advanced_title" msgid="6259362998269627310">"ការកំណត់​ផ្សេងទៀត"</string>
<string name="more_settings_title" msgid="9033454654010697185">"ឯកជនភាព និងសុវត្ថិភាពបន្ថែម"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"បំពេញស្វ័យប្រវត្តិ ការជូនដំណឹង និងច្រើនទៀត"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"ព័ត៌មាន​អំពីគោលការណ៍ការងារ​របស់អ្នក"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-km-v35/strings.xml b/SafetyCenter/Resources/res/values-km-v35/strings.xml
new file mode 100644
index 000000000..2dac2a0d6
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-km-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"សុវត្ថិភាពបណ្ដាញចល័ត"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ប្រភេទបណ្ដាញ ការអ៊ីនគ្រីប ការគ្រប់គ្រងការជូនដំណឹង"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"បន្ទប់​ឯកជន"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"រៀបចំបន្ទប់ឯកជន និងធ្វើអ្វីៗជាច្រើនទៀត"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"បន្ទប់​ឯកជន"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-km/strings.xml b/SafetyCenter/Resources/res/values-km/strings.xml
index 898f533d1..be8b2369d 100644
--- a/SafetyCenter/Resources/res/values-km/strings.xml
+++ b/SafetyCenter/Resources/res/values-km/strings.xml
@@ -24,7 +24,7 @@
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"មិន​ទាន់​មាន​ព័ត៌មាន​នៅ​ឡើយ​ទេ"</string>
<string name="lock_screen_search_terms" msgid="2678486357779794826">"ការចាក់សោឧបករណ៍, ការចាក់សោអេក្រង់, អេក្រង់ចាក់សោ, អេក្រង់ចាក់សោ, ពាក្យសម្ងាត់, កូដ​ PIN, លំនាំ"</string>
<string name="biometrics_title" msgid="5859504610285212938">"ជីវមាត្រ"</string>
- <string name="biometrics_search_terms" msgid="6040319118762671981">"ស្នាមម្រាមដៃ, ម្រាមដៃ, បញ្ចូលស្នាមម្រាមដៃ, ការដោះសោតាមទម្រង់មុខ, មុខ"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"ស្នាមម្រាមដៃ, ម្រាមដៃ, បញ្ចូលស្នាមម្រាមដៃ, ការដោះសោដោយស្កេនមុខ, មុខ"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"ឯកជនភាព"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"ផ្ទាំងគ្រប់គ្រង ការអនុញ្ញាត ការគ្រប់គ្រង"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"ផ្ទាំងគ្រប់គ្រង​ឯកជនភាព"</string>
diff --git a/SafetyCenter/Resources/res/values-kn-v34/strings.xml b/SafetyCenter/Resources/res/values-kn-v34/strings.xml
index 7df9bf60a..19dcdad15 100644
--- a/SafetyCenter/Resources/res/values-kn-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-kn-v34/strings.xml
@@ -17,18 +17,16 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="lock_screen_sources_title" msgid="5493678510117489865">"ಸಾಧನದ ಅನ್‌ಲಾಕ್"</string>
+ <string name="lock_screen_sources_title" msgid="5493678510117489865">"ಸಾಧನ ಅನ್‌ಲಾಕ್"</string>
<string name="biometrics_title_for_work" msgid="1842284049407771568">"ಕೆಲಸದ ಕುರಿತ ಬಯೋಮೆಟ್ರಿಕ್ಸ್"</string>
<string name="privacy_sources_summary" msgid="4083646673569677049">"ಅನುಮತಿಗಳು, ಡ್ಯಾಶ್‌ಬೋರ್ಡ್, ಕಂಟ್ರೋಲ್‌ಗಳು"</string>
<string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
<string name="health_connect_search_terms" msgid="4998970586245680829">"ಆರೋಗ್ಯ, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"ಸ್ಥಳದ ಡೇಟಾ ಹಂಚಿಕೊಳ್ಳುವಿಕೆ ಕುರಿತ ಅಪ್‌ಡೇಟ್‌ಗಳು"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ಡೇಟಾ, ಡೇಟಾ ಹಂಚಿಕೆ, ಡೇಟಾ ಹಂಚಿಕೆಯ ಅಪ್‌ಡೇಟ್‌ಗಳು, ಸ್ಥಳ ಹಂಚಿಕೆಗಾಗಿ ಡೇಟಾ ಹಂಚಿಕೆಯ ಅಪ್‌ಡೇಟ್‌ಗಳು"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"ಜಾಹೀರಾತು ಗೌಪ್ಯತೆ"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"ನಿಮಗೆ ಜಾಹೀರಾತುಗಳನ್ನು ತೋರಿಸಲು ಬಳಸುವ ಮಾಹಿತಿ ಆ್ಯಪ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ಜಾಹೀರಾತುಗಳು, ಜಾಹೀರಾತು ಗೌಪ್ಯತೆ, ಪ್ರೈವೆಸಿ ಸ್ಯಾಂಡ್‌ಬಾಕ್ಸ್, ಆ್ಯಡ್ ವಿಷಯಗಳು, ಆ್ಯಪ್ ಶಿಫಾರಸು ಮಾಡಿದ ಜಾಹೀರಾತುಗಳು, ಜಾಹೀರಾತು ಮಾಪನ"</string>
<string name="advanced_title" msgid="6259362998269627310">"ಇತರ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="more_settings_title" msgid="9033454654010697185">"ಇನ್ನಷ್ಟು ಭದ್ರತೆ ಮತ್ತು ಗೌಪ್ಯತೆ"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ಆಟೋಫಿಲ್, ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಇನ್ನಷ್ಟು"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"ನಿಮ್ಮ ಉದ್ಯೋಗ ನೀತಿಯ ಮಾಹಿತಿ"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-kn-v35/strings.xml b/SafetyCenter/Resources/res/values-kn-v35/strings.xml
new file mode 100644
index 000000000..821c577b6
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-kn-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"ಸೆಲ್ಯುಲಾರ್ ನೆಟ್‌ವರ್ಕ್ ಭದ್ರತೆ"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ನೆಟ್‌ವರ್ಕ್ ಪ್ರಕಾರ, ಎನ್‌ಕ್ರಿಪ್ಶನ್, ನೋಟಿಫಿಕೇಶನ್ ಕಂಟ್ರೋಲ್‌ಗಳು"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"ಖಾಸಗಿ ಸ್ಪೇಸ್"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಅನ್ನು ಸೆಟಪ್ ಮಾಡಿ ಹಾಗೂ ಇನ್ನಷ್ಟನ್ನು ಮಾಡಿ"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"ಖಾಸಗಿ ಸ್ಪೇಸ್"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ko-v34/strings.xml b/SafetyCenter/Resources/res/values-ko-v34/strings.xml
index 85108406a..347b46bdb 100644
--- a/SafetyCenter/Resources/res/values-ko-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ko-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"건강, 헬스 커넥트"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"위치 데이터 공유 방법 업데이트"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"데이터, 데이터 공유, 데이터 공유 업데이트, 위치 관련 데이터 공유 업데이트, 공유"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"광고 개인 정보 보호"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"앱에서 광고 표시에 사용하는 정보를 맞춤설정합니다."</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"광고, 광고 개인 정보 보호, 개인 정보 보호 샌드박스, 광고 주제, 앱 추천 광고, 광고 측정"</string>
<string name="advanced_title" msgid="6259362998269627310">"기타 설정"</string>
<string name="more_settings_title" msgid="9033454654010697185">"보안 및 개인 정보 보호 더보기"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"자동 완성, 알림 등"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"직장 프로필 정책 정보"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ko-v35/strings.xml b/SafetyCenter/Resources/res/values-ko-v35/strings.xml
new file mode 100644
index 000000000..4cde1dd2c
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ko-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"셀룰러 네트워크 보안"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"네트워크 유형, 암호화, 알림 설정"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"비공개 스페이스"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"비공개 스페이스 설정 등"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"비공개 스페이스"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ky-v34/strings.xml b/SafetyCenter/Resources/res/values-ky-v34/strings.xml
index cfd1f8ed2..9d4a1ede9 100644
--- a/SafetyCenter/Resources/res/values-ky-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ky-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Ден соолук, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Жүргөн жер тууралуу маалыматты бөлүшүү ыкмасын жаңыртуу"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Маалымат, маалыматты бөлүшүү, маалыматты бөлүшүү ыкмасын жаңыртуу, кайда жүргөнүмдү көрсөтүү функциясы үчүн маалыматты бөлүшүү ыкмасын жаңыртуу"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Жарнаманын купуялыгы"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Колдонмолор жарнамаларды кандай маалыматты негизинде көрсөтөрүн тандайсыз"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"жарнамалар, жарнаманын купуялыгы, privacy sandbox, жарнама темалары, колдонмолор сунуштаган жарнамалар, жарнаманы өлчөө"</string>
- <string name="advanced_title" msgid="6259362998269627310">"Башка жөндөөлөр"</string>
+ <string name="advanced_title" msgid="6259362998269627310">"Башка параметрлер"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Көбүрөөк коопсуздук жана купуялык"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Автотолтуруу, билдирмелер жана башкалар"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Жумуш саясаты тууралуу маалымат"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ky-v35/strings.xml b/SafetyCenter/Resources/res/values-ky-v35/strings.xml
new file mode 100644
index 000000000..a0dd4cd57
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ky-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Мобилдик тармактын коопсуздугу"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Тармактын түрү, шифрлөө, билдирмелерди башкаруу элементтери"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Жеке чөйрө"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Жеке чөйрөнү тууралоо жана башка нерселер"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Жеке чөйрө"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-lo-v34/strings.xml b/SafetyCenter/Resources/res/values-lo-v34/strings.xml
index a301cf8c0..fe18b3024 100644
--- a/SafetyCenter/Resources/res/values-lo-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-lo-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"ສຸຂະພາບ, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"ການອັບເດດການແບ່ງປັນຂໍ້ມູນສະຖານທີ່"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ຂໍ້ມູນ, ການແບ່ງປັນຂໍ້ມູນ, ການອັບເດດການແບ່ງປັນຂໍ້ມູນ, ການອັບເດດການແບ່ງປັນຂໍ້ມູນສະຖານທີ່, ການແບ່ງປັນ"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"ຄວາມເປັນສ່ວນກ່ຽວກັບຕົວໂຄສະນາ"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"ປັບແຕ່ງຂໍ້ມູນແອັບທີ່ໃຊ້ສະແດງໂຄສະນາໃຫ້ທ່ານເຫັນ"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ໂຄສະນາ, ຄວາມເປັນສ່ວນຕົວກ່ຽວກັບຕົວໂຄສະນາ, Privacy Sandbox, ຫົວຂໍ້ໂຄສະນາ, ໂຄສະນາແນະນຳແອັບ, ການວັດແທກໂຄສະນາ"</string>
<string name="advanced_title" msgid="6259362998269627310">"ການຕັ້ງຄ່າອື່ນໆ"</string>
<string name="more_settings_title" msgid="9033454654010697185">"ຄວາມປອດໄພ ແລະ ຄວາມເປັນສ່ວນຕົວເພີ່ມເຕີມ"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ການຕື່ມຂໍ້ມູນອັດຕະໂນມັດ, ການແຈ້ງເຕືອນ ແລະ ອື່ນໆ"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"ຂໍ້ມູນນະໂຍບາຍບ່ອນເຮັດວຽກຂອງທ່ານ"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-lo-v35/strings.xml b/SafetyCenter/Resources/res/values-lo-v35/strings.xml
new file mode 100644
index 000000000..731ab407c
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-lo-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"ຄວາມປອດໄພຂອງເຄືອຂ່າຍມືຖື"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ປະເພດເຄືອຂ່າຍ, ການເຂົ້າລະຫັດ, ການຄວບຄຸມການແຈ້ງເຕືອນ"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"ພື້ນທີ່ສ່ວນຕົວ"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ຕັ້ງຄ່າພື້ນທີ່ສ່ວນຕົວ ແລະ ອື່ນໆ"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"ພື້ນທີ່ສ່ວນຕົວ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-lt-v34/strings.xml b/SafetyCenter/Resources/res/values-lt-v34/strings.xml
index 844910cd8..ffe1d55e0 100644
--- a/SafetyCenter/Resources/res/values-lt-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-lt-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Sveikata, „Health Connect“"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Vietovės duomenų bendrinimo naujiniai"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Duomenys, duomenų bendrinimas, duomenų bendrinimo naujiniai, vietovės duomenų bendrinimo naujiniai, bendrinimas"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Su skelbimais susijęs privatumas"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Tinkinti informaciją, kurią programos naudoja skelbimams rodyti"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"skelbimai, su skelbimais susijęs privatumas, Privatumo „sandbox“ (smėlio dėžė), skelbimų temos, programų siūlomi skelbimai, skelbimų vertinimas"</string>
<string name="advanced_title" msgid="6259362998269627310">"Kiti nustatymai"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Geresnė sauga ir privatumas"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automatinis pildymas, pranešimai ir kt."</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Darbo politikos informacija"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-lt-v35/strings.xml b/SafetyCenter/Resources/res/values-lt-v35/strings.xml
new file mode 100644
index 000000000..cccfd5465
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-lt-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobiliojo ryšio tinklo sauga"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tinklo tipas, šifruotė, pranešimų valdikliai"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privati erdvė"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Nustatykite privačią erdvę ir atlikite kitų veiksmų"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privati erdvė"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-lv-v34/strings.xml b/SafetyCenter/Resources/res/values-lv-v34/strings.xml
index 24753a3c8..b6f5238c2 100644
--- a/SafetyCenter/Resources/res/values-lv-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-lv-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Atjauninājumi atrašanās vietas datu kopīgošanā"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Dati, datu kopīgošana, datu kopīgošanas atjauninājumi, atjauninājumi atrašanās vietas datu kopīgošanā, kopīgošana"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Reklāmu konfidencialitāte"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Pielāgojiet informāciju, ko lietotnes var izmantot, lai rādītu jums reklāmas"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklāmas, reklāmu konfidencialitāte, konfidencialitātes smilškaste, reklāmu tēmas, lietotņu ieteiktas reklāmas, reklāmu izvērtēšana"</string>
<string name="advanced_title" msgid="6259362998269627310">"Citi iestatījumi"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Citi drošības un konfidencialitātes iestatījumi"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automātiskā aizpilde, paziņojumi un citi iestatījumi"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informācija par jūsu darbavietas politiku"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-lv-v35/strings.xml b/SafetyCenter/Resources/res/values-lv-v35/strings.xml
new file mode 100644
index 000000000..3c5cf9224
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-lv-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobilā tīkla drošība"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tīkla veids, šifrējums, paziņojumu vadīklas"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privātā mape"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Privātās mapes iestatīšana un citas iespējas"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privātā mape"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-mk-v34/strings.xml b/SafetyCenter/Resources/res/values-mk-v34/strings.xml
index 93c7d5d49..b3c1db290 100644
--- a/SafetyCenter/Resources/res/values-mk-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-mk-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Здравје, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Промени во споделувањето на податоците за локација"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Податоци, споделување податоци, промени во споделувањето податоци, промени во споделувањето на податоците за локација, споделување"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Приватност за реклами"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Приспособете ги податоците што апликациите ги користат за да ви прикажуваат реклами"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"реклами, приватност за реклами, privacy sandbox, теми на реклами, реклами предложени од апликации, мерење реклами"</string>
<string name="advanced_title" msgid="6259362998269627310">"Други поставки"</string>
- <string name="more_settings_title" msgid="9033454654010697185">"Повеќе безбедност и приватност"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"Дополнителни поставки"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Автоматско пополнување, известувања и друго"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Податоци за работните правила"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-mk-v35/strings.xml b/SafetyCenter/Resources/res/values-mk-v35/strings.xml
new file mode 100644
index 000000000..244d8c340
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-mk-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Безбедност на мобилната мрежа"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Контроли за известувања на тип мрежа, шифрирање"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Приватен простор"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Поставување „Приватен простор“ и друго"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Приватен простор"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-mk/strings.xml b/SafetyCenter/Resources/res/values-mk/strings.xml
index bc3dbfd9d..2b2414d0d 100644
--- a/SafetyCenter/Resources/res/values-mk/strings.xml
+++ b/SafetyCenter/Resources/res/values-mk/strings.xml
@@ -24,15 +24,15 @@
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Сѐ уште нема податоци"</string>
<string name="lock_screen_search_terms" msgid="2678486357779794826">"Заклучување уред, Заклучување екран, Заклучен екран, Лозинка, PIN, Шема"</string>
<string name="biometrics_title" msgid="5859504610285212938">"Биометрика"</string>
- <string name="biometrics_search_terms" msgid="6040319118762671981">"Отпечаток, Прст, Додај отпечаток, Отклучување со лик, Лице"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Отпечаток, Прст, Додај отпечаток, Отклучување со лик, Лик"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Приватност"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Контролна табла, дозволи, контроли"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Контролна табла за приватност"</string>
- <string name="permission_usage_summary" msgid="5323079206029964468">"Прикажи кои апликации користеа дозволи неодамна"</string>
+ <string name="permission_usage_summary" msgid="5323079206029964468">"Прикажува кои апликации користеле дозволи неодамна"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Приватност, Контролна табла за приватност"</string>
- <string name="permission_manager_title" msgid="5277347862821255015">"Управник со дозволи"</string>
+ <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="permission_manager_search_terms" msgid="2895147613099694722">"Дозволи, Управувач со дозволи"</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>
diff --git a/SafetyCenter/Resources/res/values-ml-v34/strings.xml b/SafetyCenter/Resources/res/values-ml-v34/strings.xml
index 445cb0598..a53898e00 100644
--- a/SafetyCenter/Resources/res/values-ml-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ml-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"ലൊക്കേഷൻ ഡാറ്റ പങ്കിടുന്നത് സംബന്ധിച്ച അപ്‌ഡേറ്റുകൾ"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ഡാറ്റ, ഡാറ്റ പങ്കിടൽ, ഡാറ്റ പങ്കിടൽ അപ്‌ഡേറ്റുകൾ, ലൊക്കേഷനുമായി ബന്ധപ്പെട്ട ഡാറ്റ പങ്കിടൽ അപ്ഡേറ്റുകൾ, പങ്കിടൽ"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"പരസ്യവുമായി ബന്ധപ്പെട്ട സ്വകാര്യത"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"നിങ്ങളെ പരസ്യങ്ങൾ കാണിക്കുന്നതിന് ആപ്പുകൾ ഉപയോഗിക്കുന്ന വിവരങ്ങൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"പരസ്യങ്ങൾ, പരസ്യവുമായി ബന്ധപ്പെട്ട സ്വകാര്യത, സ്വകാര്യതാ സാൻഡ്ബോക്‌സ്, പരസ്യത്തിന്റെ വിഷയങ്ങൾ, ആപ്പ് നിർദ്ദേശിക്കുന്ന പരസ്യങ്ങൾ, ആഡ് മെഷർമെന്റ്"</string>
<string name="advanced_title" msgid="6259362998269627310">"മറ്റ് ക്രമീകരണം"</string>
<string name="more_settings_title" msgid="9033454654010697185">"കൂടുതൽ സുരക്ഷയും സ്വകാര്യതയും"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"സ്വയമേവ പൂരിപ്പിക്കൽ, അറിയിപ്പുകൾ എന്നിവയും മറ്റും"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"നിങ്ങളുടെ ഔദ്യോഗിക നയ വിവരങ്ങൾ"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ml-v35/strings.xml b/SafetyCenter/Resources/res/values-ml-v35/strings.xml
new file mode 100644
index 000000000..4772cb9af
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ml-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"സെല്ലുലാർ നെറ്റ്‌വർക്ക് സുരക്ഷ"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"നെറ്റ്‌വർക്ക് തരം, എൻ‍ക്രിപ്ഷൻ, അറിയിപ്പ് നിയന്ത്രണങ്ങൾ"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"സ്വകാര്യ Space"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"സ്വകാര്യ Space സജ്ജീകരിക്കുകയും മറ്റും ചെയ്യൂ"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"സ്വകാര്യ Space"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-mn-v34/strings.xml b/SafetyCenter/Resources/res/values-mn-v34/strings.xml
index bb696e20e..2f498893b 100644
--- a/SafetyCenter/Resources/res/values-mn-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-mn-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Байршлын өгөгдөл хуваалцах шинэчлэлт"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Өгөгдөл, өгөгдөл хуваалцах, өгөгдөл хуваалцах шинэчлэлт, байршлын өгөгдөл хуваалцах шинэчлэлт, хуваалцах"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Зарын нууцлал"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Танд зар харуулахын тулд мэдээллийн аппуудын ашиглалтыг өөрчлөх"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"зар, зарын нууцлал, privacy sandbox, зарын сэдэв, аппын санал болгосон зар, зарын хэмжилт"</string>
<string name="advanced_title" msgid="6259362998269627310">"Бусад тохиргоо"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Бусад аюулгүй байдал, нууцлал"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Автоматаар бөглөх хэсэг, мэдэгдэл болон бусад"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Таны ажлын бодлогын мэдээлэл"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-mn-v35/strings.xml b/SafetyCenter/Resources/res/values-mn-v35/strings.xml
new file mode 100644
index 000000000..afcb7f960
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-mn-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Үүрэн холбооны сүлжээний аюулгүй байдал"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Сүлжээний төрөл, шифрлэлт, мэдэгдлийн тохиргоо"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Хувийн орон зай"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Хувийн орон зай тохируулах болон илүү ихийг хийх"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Хувийн орон зай"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-mr-v34/strings.xml b/SafetyCenter/Resources/res/values-mr-v34/strings.xml
index 60cb16f3c..f2d620adc 100644
--- a/SafetyCenter/Resources/res/values-mr-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-mr-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"स्थानासाठी डेटा शेअरिंगसंबंधित अपडेट"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"डेटा, डेटा शेअरिंग, डेटा शेअरिंगसंबंधित अपडेट, स्थानासाठी डेटा शेअरिंगसंबंधित अपडेट, शेअरिंग"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"जाहिरात गोपनीयता"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"तुम्‍हाला जाहिराती दाखवण्‍यासाठी ॲप्सनी कोणती माहिती वापरावी ते कस्टमाइझ करा"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"जाहिराती, जाहिरातीसंबंधित गोपनीयता, प्रायव्हसी सॅंडबाॅक्स, जाहिरातीचे विषय, अ‍ॅपने सुचवलेल्या जाहिराती, जाहिरातीशी संबंधित मापन"</string>
<string name="advanced_title" msgid="6259362998269627310">"इतर सेटिंग्ज"</string>
<string name="more_settings_title" msgid="9033454654010697185">"आणखी सुरक्षा आणि गोपनीयता"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ऑटोफिल, सूचना आणि आणखी बरेच काही"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"तुमच्या कामासंबंधित धोरणाची माहिती"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-mr-v35/strings.xml b/SafetyCenter/Resources/res/values-mr-v35/strings.xml
new file mode 100644
index 000000000..39bbededf
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-mr-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"मोबाइल नेटवर्कची सुरक्षा"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"नेटवर्क प्रकार, एन्क्रिप्शन, सूचना नियंत्रणे"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"खाजगी स्पेस"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"खाजगी स्पेस आणि आणखी बरेच काही सेट करा"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"खाजगी स्पेस"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ms-v34/strings.xml b/SafetyCenter/Resources/res/values-ms-v34/strings.xml
index 101490bc0..68102f138 100644
--- a/SafetyCenter/Resources/res/values-ms-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ms-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Kemaskinian perkongsian data untuk lokasi"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Perkongsian data, Kemaskinian perkongsian data, Kemaskinian perkongsian data untuk lokasi, perkongsian"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privasi iklan"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Sesuaikan maklumat yang digunakan apl untuk menunjukkan iklan kepada anda"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"iklan, privasi iklan, kotak pasir privasi, topik iklan, iklan cadangan apl, ukuran iklan"</string>
<string name="advanced_title" msgid="6259362998269627310">"Tetapan lain"</string>
- <string name="more_settings_title" msgid="9033454654010697185">"Lebih banyak sekuriti &amp; privasi"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"Lagi sekuriti &amp; privasi"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autolengkap, pemberitahuan dan banyak lagi"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Maklumat dasar kerja anda"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ms-v35/strings.xml b/SafetyCenter/Resources/res/values-ms-v35/strings.xml
new file mode 100644
index 000000000..6be1180bb
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ms-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Keselamatan rangkaian selular"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Jenis rangkaian, penyulitan, kawalan pemberitahuan"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Ruang Peribadi"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Sediakan Ruang Peribadi dan pelbagai lagi"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Ruang Peribadi"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-my-v34/strings.xml b/SafetyCenter/Resources/res/values-my-v34/strings.xml
index 9415ecbd1..9b2b27707 100644
--- a/SafetyCenter/Resources/res/values-my-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-my-v34/strings.xml
@@ -17,18 +17,16 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="lock_screen_sources_title" msgid="5493678510117489865">"စက်ပစ္စည်းဖွင့်ခြင်း"</string>
+ <string name="lock_screen_sources_title" msgid="5493678510117489865">"စက်ပစ္စည်းလော့ခ်ဖွင့်ရန်"</string>
<string name="biometrics_title_for_work" msgid="1842284049407771568">"အလုပ်အတွက် ဇီဝမက်ထရစ် အချက်အလက်များ"</string>
- <string name="privacy_sources_summary" msgid="4083646673569677049">"ခွင့်ပြုချက်များ၊ ဒက်ရှ်ဘုတ်၊ သတ်မှတ်ချက်များ"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"ခွင့်ပြုချက်များ၊ ဒက်ရှ်ဘုတ်၊ ထိန်းချုပ်မှုများ"</string>
<string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
<string name="health_connect_search_terms" msgid="4998970586245680829">"ကျန်းမာရေး၊ Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"တည်နေရာအတွက် ဒေတာမျှဝေခြင်း အပ်ဒိတ်"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ဒေတာ၊ ဒေတာမျှဝေခြင်း၊ ဒေတာမျှဝေခြင်း အပ်ဒိတ်၊ တည်နေရာအတွက် ဒေတာမျှဝေခြင်း အပ်ဒိတ်၊ မျှဝေခြင်း"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"ကြော်ငြာဆိုင်ရာ အချက်အလက်လုံခြုံမှု"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"အက်ပ်များက သင့်အား ကြော်ငြာများပြရန်သုံးသော အချက်အလက်ကို စိတ်ကြိုက်လုပ်နိုင်သည်"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ကြော်ငြာ၊ ကြော်ငြာဆိုင်ရာ အချက်အလက်လုံခြုံမှု၊ privacy sandbox၊ ကြော်ငြာအကြောင်းအရာ၊ အက်ပ်အကြံပြုကြော်ငြာ၊ ကြော်ငြာ တိုင်းတာအကဲဖြတ်မှု"</string>
<string name="advanced_title" msgid="6259362998269627310">"အခြား ဆက်တင်များ"</string>
<string name="more_settings_title" msgid="9033454654010697185">"နောက်ထပ် လုံခြုံရေးနှင့် ကိုယ်ရေးဒေတာ လုံခြုံမှု"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"အော်တိုဖြည့်၊ အကြောင်းကြားချက်များစသည်"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"သင့်အလုပ်ခွင်မူဝါဒ အချက်အလက်"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-my-v35/strings.xml b/SafetyCenter/Resources/res/values-my-v35/strings.xml
new file mode 100644
index 000000000..0e5fed737
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-my-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"ဆယ်လူလာကွန်ရက် လုံခြုံရေး"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ကွန်ရက်အမျိုးအစား၊ အသွင်ဝှက်ခြင်း၊ အကြောင်းကြားချက် သတ်မှတ်ချက်များ"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"သီးသန့်ချတ်ခန်း"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"သီးသန့်ချတ်ခန်း စသည်တို့ကို စနစ်ထည့်သွင်းသည်"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"သီးသန့်ချတ်ခန်း"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-nb-v34/strings.xml b/SafetyCenter/Resources/res/values-nb-v34/strings.xml
index f247aae19..6ccbb06bd 100644
--- a/SafetyCenter/Resources/res/values-nb-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-nb-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Helse, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Oppdateringer av datadeling for posisjon"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, datadeling, oppdateringer av datadeling, oppdateringer av datadeling for posisjon, deling"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Annonsepersonvern"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Tilpass informasjonen apper bruker for å vise deg annonser"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"annonser, annonsepersonvern, Privacy Sandbox, annonseemner, annonser foreslått av apper, annonsemåling"</string>
<string name="advanced_title" msgid="6259362998269627310">"Andre innstillinger"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Mer sikkerhet og personvern"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofyll, varsler med mer"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informasjon om jobbreglene dine"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-nb-v35/strings.xml b/SafetyCenter/Resources/res/values-nb-v35/strings.xml
new file mode 100644
index 000000000..7f5142b96
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-nb-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Sikkerhet for mobilnettverk"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Nettverkstype, kryptering, varselskontroller"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Private Space"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Konfigurer Private Space med mer"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Private Space"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ne-v34/strings.xml b/SafetyCenter/Resources/res/values-ne-v34/strings.xml
index 4d79f599c..4a90e99b6 100644
--- a/SafetyCenter/Resources/res/values-ne-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ne-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"लोकेसन डेटा सेयर गर्नेसम्बन्धी अभ्यासका बारेमा अद्यावधिक जानकारी"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"जानकारी, जानकारी सेयर गर्नेसम्बन्धी अभ्यास, जानकारी सेयर गर्नेसम्बन्धी अभ्यासका बारेमा अद्यावधिक जानकारी, लोकेसन डेटा सेयर गर्नेसम्बन्धी अभ्यासका बारेमा अद्यावधिक जानकारी, सेयरिङ"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"विज्ञापनको गोपनीयता"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"तपाईंलाई विज्ञापनहरू देखाउन एपहरूले प्रयोग गर्ने जानकारी कस्टमाइज गर्नुहोस्"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"विज्ञापन, विज्ञापनको गोपनीयता, प्राइभेसी स्यान्डबक्स, विज्ञापनको विषय, एपले सिफारिस गरेका विज्ञापनहरू, विज्ञापनको पर्फर्मेन्स मापन गर्ने सुविधा"</string>
<string name="advanced_title" msgid="6259362998269627310">"अन्य सेटिङ"</string>
<string name="more_settings_title" msgid="9033454654010697185">"थप सुरक्षा तथा गोपनीयता"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"अटोफिल, सूचना र अन्य कुराहरू"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"तपाईंको कामसम्बन्धी नीतिको जानकारी"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ne-v35/strings.xml b/SafetyCenter/Resources/res/values-ne-v35/strings.xml
new file mode 100644
index 000000000..226388fbe
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ne-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"मोबाइल नेटवर्कको सुरक्षा"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"नेटवर्कको प्रकार, इन्क्रिप्सन, सूचनाका सेटिङ"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"निजी स्पेस"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"निजी स्पेस सेटअप गर्नुहोस् र अन्य कार्यहरू गर्नुहोस्"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"निजी स्पेस"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ne/strings.xml b/SafetyCenter/Resources/res/values-ne/strings.xml
index 5ceab041e..4ef5c9609 100644
--- a/SafetyCenter/Resources/res/values-ne/strings.xml
+++ b/SafetyCenter/Resources/res/values-ne/strings.xml
@@ -30,7 +30,7 @@
<string name="permission_usage_title" msgid="3633779688945350407">"गोपनीयतासम्बन्धी ड्यासबोर्ड"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"हालसालै कुन कुन एपले अनुमतिहरू प्रयोग गरेका छन् भन्ने कुरा हेर्नुहोस्"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"गोपनीयता, गोपनीयतासम्बन्धी ड्यासबोर्ड"</string>
- <string name="permission_manager_title" msgid="5277347862821255015">"पर्मिसन म्यानेजर"</string>
+ <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>
diff --git a/SafetyCenter/Resources/res/values-nl-v34/strings.xml b/SafetyCenter/Resources/res/values-nl-v34/strings.xml
index 5e4e4c729..e5a446c52 100644
--- a/SafetyCenter/Resources/res/values-nl-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-nl-v34/strings.xml
@@ -17,18 +17,16 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="lock_screen_sources_title" msgid="5493678510117489865">"Apparaatontgrendeling"</string>
+ <string name="lock_screen_sources_title" msgid="5493678510117489865">"Apparaat­ontgrendeling"</string>
<string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrische systemen voor het werk"</string>
<string name="privacy_sources_summary" msgid="4083646673569677049">"Rechten, dashboard, bedieningselementen"</string>
<string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
<string name="health_connect_search_terms" msgid="4998970586245680829">"Gezondheid, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Updates voor het delen van locatiegegevens"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Gegevens, Gegevens delen, Updates voor het delen van gegevens, Updates voor het delen van locatiegegevens, delen"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Advertentieprivacy"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Pas de informatie aan die apps gebruiken om advertenties te tonen"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"advertenties, advertentieprivacy, privacy sandbox, advertentieonderwerpen, door apps voorgestelde advertenties, advertentiemeting"</string>
<string name="advanced_title" msgid="6259362998269627310">"Overige instellingen"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Meer beveiliging en privacy"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automatisch invullen, meldingen en meer"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informatie over je werkbeleid"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-nl-v35/strings.xml b/SafetyCenter/Resources/res/values-nl-v35/strings.xml
new file mode 100644
index 000000000..c0990f160
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-nl-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Beveiliging van mobiele netwerken"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Netwerktype, versleuteling, beheeropties voor meldingen"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privéruimte"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Privéruimte instellen en meer"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privéruimte"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-nl/strings.xml b/SafetyCenter/Resources/res/values-nl/strings.xml
index 068dc5be4..5232c280b 100644
--- a/SafetyCenter/Resources/res/values-nl/strings.xml
+++ b/SafetyCenter/Resources/res/values-nl/strings.xml
@@ -30,7 +30,7 @@
<string name="permission_usage_title" msgid="3633779688945350407">"Privacydashboard"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Toon welke apps onlangs rechten hebben gebruikt"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacy, Privacydashboard"</string>
- <string name="permission_manager_title" msgid="5277347862821255015">"Rechtenbeheer"</string>
+ <string name="permission_manager_title" msgid="5277347862821255015">"Rechten­beheer"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Beheer de toegang van apps tot je gegevens"</string>
<string name="permission_manager_search_terms" msgid="2895147613099694722">"Rechten, Rechtenbeheer"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privacyopties"</string>
diff --git a/SafetyCenter/Resources/res/values-or-v34/strings.xml b/SafetyCenter/Resources/res/values-or-v34/strings.xml
index 38069cf80..df4d07e17 100644
--- a/SafetyCenter/Resources/res/values-or-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-or-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"ସ୍ୱାସ୍ଥ୍ୟ, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"ଲୋକେସନ ପାଇଁ ଡାଟା ସେୟାରିଂ ଅପଡେଟଗୁଡ଼ିକ"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ଡାଟା, ଡାଟା ସେୟାରିଂ, ଡାଟା ସେୟାରିଂ ଅପଡେଟ, ଲୋକେସନ ପାଇଁ ଡାଟା ସେୟାରିଂ ଅପଡେଟ, ସେୟାରିଂ"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"ବିଜ୍ଞାପନ ଗୋପନୀୟତା"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"ଆପଣଙ୍କୁ ବିଜ୍ଞାପନଗୁଡ଼ିକ ଦେଖାଇବା ପାଇଁ ଆପ୍ସ ବ୍ୟବହାର କରୁଥିବା ସୂଚନାକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ବିଜ୍ଞାପନ, ବିଜ୍ଞାପନ ଗୋପନୀୟତା, ପ୍ରାଇଭେସି ସେଣ୍ଡବକ୍ସ, ବିଜ୍ଞାପନ ବିଷୟ, ଆପ ଦ୍ୱାରା-ପରାମର୍ଶ ଦିଆଯାଇଥିବା ବିଜ୍ଞାପନଗୁଡ଼ିକ, ବିଜ୍ଞାପନର ପରିମାପ"</string>
<string name="advanced_title" msgid="6259362998269627310">"ଅନ୍ୟ ସେଟିଂସ"</string>
<string name="more_settings_title" msgid="9033454654010697185">"ଅଧିକ ସୁରକ୍ଷା ଏବଂ ଗୋପନୀୟତା"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ଅଟୋଫିଲ, ବିଜ୍ଞପ୍ତି ଏବଂ ଆହୁରି ଅନେକ କିଛି"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"ଆପଣଙ୍କ ୱାର୍କ ନୀତି ସୂଚନା"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-or-v35/strings.xml b/SafetyCenter/Resources/res/values-or-v35/strings.xml
new file mode 100644
index 000000000..ede3b5e80
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-or-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"ସେଲୁଲାର ନେଟୱାର୍କ ସୁରକ୍ଷା"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ନେଟୱାର୍କ ପ୍ରକାର, ଏନକ୍ରିପସନ, ବିଜ୍ଞପ୍ତି ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ପ୍ରାଇଭେଟ ସ୍ପେସ ଏବଂ ଆହୁରି ଅନେକ କିଛି ସେଟଅପ କରନ୍ତୁ"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-or/strings.xml b/SafetyCenter/Resources/res/values-or/strings.xml
index 2d3ffb67d..d4d8d1a4a 100644
--- a/SafetyCenter/Resources/res/values-or/strings.xml
+++ b/SafetyCenter/Resources/res/values-or/strings.xml
@@ -27,10 +27,10 @@
<string name="biometrics_search_terms" msgid="6040319118762671981">"ଫିଙ୍ଗରପ୍ରିଣ୍ଟ, ଆଙ୍ଗୁଠି, ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଯୋଗ କରନ୍ତୁ, ଫେସ ଅନଲକ, ଫେସ"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"ଗୋପନୀୟତା"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"ଡ୍ୟାସବୋର୍ଡ, ଅନୁମତି, ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
- <string name="permission_usage_title" msgid="3633779688945350407">"ଗୋପନୀୟତା ଡ୍ୟାସବୋର୍ଡ"</string>
+ <string name="permission_usage_title" msgid="3633779688945350407">"ଗୋପନୀୟତା ଡେସବୋର୍ଡ"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"କେଉଁ ଆପ୍ସ ଏବେ ଅନୁମତିଗୁଡ଼ିକ ବ୍ୟବହାର କରିଛି ତାହା ଦେଖାନ୍ତୁ"</string>
- <string name="permission_usage_search_terms" msgid="3852343592870257104">"ଗୋପନୀୟତା, ଗୋପନୀୟତା ଡ୍ୟାସବୋର୍ଡ"</string>
- <string name="permission_manager_title" msgid="5277347862821255015">"ଅନୁମତି ପରିଚାଳକ"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"ଗୋପନୀୟତା, ଗୋପନୀୟତା ଡେସବୋର୍ଡ"</string>
+ <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>
diff --git a/SafetyCenter/Resources/res/values-pa-v34/strings.xml b/SafetyCenter/Resources/res/values-pa-v34/strings.xml
index 5aa67f5c8..b30bcce37 100644
--- a/SafetyCenter/Resources/res/values-pa-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-pa-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"ਸਿਹਤ, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"ਟਿਕਾਣੇ ਲਈ ਡਾਟਾ ਸਾਂਝਾਕਰਨ ਅੱਪਡੇਟ"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ਡਾਟਾ, ਡਾਟਾ ਸਾਂਝਾਕਰਨ, ਡਾਟਾ ਸਾਂਝਾਕਰਨ ਅੱਪਡੇਟ, ਟਿਕਾਣੇ ਲਈ ਡਾਟਾ ਸਾਂਝਾਕਰਨ ਅੱਪਡੇਟ, ਸਾਂਝਾਕਰਨ"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"ਵਿਗਿਆਪਨ ਪਰਦੇਦਾਰੀ"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"ਇਹ ਵਿਉਂਤਬੱਧ ਕਰੋ ਕਿ ਐਪਾਂ ਤੁਹਾਨੂੰ ਵਿਗਿਆਪਨ ਦਿਖਾਉਣ ਲਈ ਕਿਹੜੀ ਜਾਣਕਾਰੀ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"ਵਿਗਿਆਪਨ, ਵਿਗਿਆਪਨ ਪਰਦੇਦਾਰੀ, ਪ੍ਰਾਈਵੇਸੀ ਸੈਂਡਬਾਕਸ, ਵਿਗਿਆਪਨ ਦੇ ਵਿਸ਼ੇ, ਐਪ ਵੱਲੋਂ ਸੁਝਾਏ ਵਿਗਿਆਪਨ, ਵਿਗਿਆਪਨ ਮਾਪ"</string>
<string name="advanced_title" msgid="6259362998269627310">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="more_settings_title" msgid="9033454654010697185">"ਹੋਰ ਸੁਰੱਖਿਆ ਅਤੇ ਪਰਦੇਦਾਰੀ"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ਆਟੋਫਿਲ, ਸੂਚਨਾਵਾਂ ਅਤੇ ਹੋਰ"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"ਤੁਹਾਡੀ ਕਾਰਜ ਨੀਤੀ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pa-v35/strings.xml b/SafetyCenter/Resources/res/values-pa-v35/strings.xml
new file mode 100644
index 000000000..8aeb6fb28
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pa-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"ਸੈਲਿਊਲਰ ਨੈੱਟਵਰਕ ਸੁਰੱਖਿਆ"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ਨੈੱਟਵਰਕ ਦੀ ਕਿਸਮ, ਇਨਕ੍ਰਿਪਸ਼ਨ, ਸੂਚਨਾ ਕੰਟਰੋਲ"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"ਨਿੱਜੀ ਸਪੇਸ"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ਨਿੱਜੀ ਸਪੇਸ ਦਾ ਸੈੱਟਅੱਪ ਅਤੇ ਹੋਰ ਕੰਮ ਕਰੋ"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"ਨਿੱਜੀ ਸਪੇਸ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-pl-v34/strings.xml b/SafetyCenter/Resources/res/values-pl-v34/strings.xml
index bf39edf14..7ee39b539 100644
--- a/SafetyCenter/Resources/res/values-pl-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-pl-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Zmiany w udostępnianiu danych o lokalizacji"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"dane, udostępnianie danych, zmiany w udostępnianiu danych, zmiany w udostępnianiu danych o lokalizacji, udostępnianie"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Prywatność w reklamach"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Dostosuj informacje używane przez aplikacje przy wyświetlaniu reklam"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklamy, prywatność w reklamach, Piaskownica prywatności, tematy reklam, reklamy sugerowane przez aplikację, pomiar skuteczności reklam"</string>
<string name="advanced_title" msgid="6259362998269627310">"Inne ustawienia"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Więcej ustawień bezpieczeństwa i prywatności"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autouzupełnianie, powiadomienia i inne ustawienia"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informacje o zasadach obowiązujących w firmie"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pl-v35/strings.xml b/SafetyCenter/Resources/res/values-pl-v35/strings.xml
new file mode 100644
index 000000000..3ce6984ac
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pl-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Zabezpieczenia sieci komórkowej"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Typ sieci, szyfrowanie, ustawienia powiadomień"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Obszar prywatny"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Skonfiguruj obszar prywatny i inne ustawienia"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Obszar prywatny"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml b/SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml
index 8a11ca969..a69cf32ca 100644
--- a/SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Saúde, Conexão Saúde"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Atualizações no compartilhamento de dados de local"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Dados, Compartilhamento de dados, Atualizações de compartilhamento de dados, Atualizações de compartilhamento de dados para localização, compartilhamento"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privacidade de anúncios"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personalize as informações que os apps usam para mostrar anúncios"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"anúncios, privacidade de anúncios, Sandbox de privacidade, temas de anúncios, anúncios sugeridos por apps, medição de anúncio"</string>
<string name="advanced_title" msgid="6259362998269627310">"Outras configurações"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Mais segurança e privacidade"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Preenchimento automático, notificações e mais"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informações sobre sua política de trabalho"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-rBR-v35/strings.xml b/SafetyCenter/Resources/res/values-pt-rBR-v35/strings.xml
new file mode 100644
index 000000000..a9806e3db
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pt-rBR-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Segurança da rede celular"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipo de rede, criptografia, controles de notificação"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espaço particular"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configurar Espaço particular e mais"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espaço particular"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml b/SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml
index e768cce11..643fa469d 100644
--- a/SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Saúde, Saúde Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Atualizações da partilha de dados para a localização"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Dados, partilha de dados, atualizações de partilha de dados, atualizações da partilha de dados para a localização, partilha"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privacidade dos anúncios"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personalize as informações que as apps usam para lhe mostrar anúncios"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"anúncios, privacidade de anúncios, Privacy Sandbox, tópicos de anúncios, anúncios sugeridos por apps, medição de anúncios"</string>
<string name="advanced_title" msgid="6259362998269627310">"Outras definições"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Maior segurança e privacidade"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Preenchimento automático, notificações e muito mais"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"As suas informações da Política de Trabalho"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-rPT-v35/strings.xml b/SafetyCenter/Resources/res/values-pt-rPT-v35/strings.xml
new file mode 100644
index 000000000..fc0990db0
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pt-rPT-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Segurança da rede móvel"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipo de rede, encriptação, controlos de notificação"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espaço privado"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configure o espaço privado e muito mais"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espaço privado"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-rPT/strings.xml b/SafetyCenter/Resources/res/values-pt-rPT/strings.xml
index 80fda0dde..5773d657b 100644
--- a/SafetyCenter/Resources/res/values-pt-rPT/strings.xml
+++ b/SafetyCenter/Resources/res/values-pt-rPT/strings.xml
@@ -28,7 +28,7 @@
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacidade"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Painel de controlo, autorizações e controlos"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Painel de privacidade"</string>
- <string name="permission_usage_summary" msgid="5323079206029964468">"Mostrar apps que usaram autorizações recentemente"</string>
+ <string name="permission_usage_summary" msgid="5323079206029964468">"Mostre apps que usaram autorizações recentemente"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacidade, painel de privacidade"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Gestor de autorizações"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controle o acesso de apps aos seus dados"</string>
diff --git a/SafetyCenter/Resources/res/values-pt-v34/strings.xml b/SafetyCenter/Resources/res/values-pt-v34/strings.xml
index 8a11ca969..a69cf32ca 100644
--- a/SafetyCenter/Resources/res/values-pt-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-pt-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Saúde, Conexão Saúde"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Atualizações no compartilhamento de dados de local"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Dados, Compartilhamento de dados, Atualizações de compartilhamento de dados, Atualizações de compartilhamento de dados para localização, compartilhamento"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privacidade de anúncios"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personalize as informações que os apps usam para mostrar anúncios"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"anúncios, privacidade de anúncios, Sandbox de privacidade, temas de anúncios, anúncios sugeridos por apps, medição de anúncio"</string>
<string name="advanced_title" msgid="6259362998269627310">"Outras configurações"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Mais segurança e privacidade"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Preenchimento automático, notificações e mais"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informações sobre sua política de trabalho"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-v35/strings.xml b/SafetyCenter/Resources/res/values-pt-v35/strings.xml
new file mode 100644
index 000000000..a9806e3db
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pt-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Segurança da rede celular"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipo de rede, criptografia, controles de notificação"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Espaço particular"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configurar Espaço particular e mais"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Espaço particular"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ro-v34/strings.xml b/SafetyCenter/Resources/res/values-ro-v34/strings.xml
index 1ac0f0fce..9292c43d3 100644
--- a/SafetyCenter/Resources/res/values-ro-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ro-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Actualizări privind permiterea accesului la date pentru locație"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"date, permiterea accesului la date, actualizări privind permiterea accesului la date, actualizări privind permiterea accesului la date pentru locație, permiterea accesului"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Confidențialitatea anunțurilor"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Personalizează informațiile pe care le folosesc aplicațiile pentru a-ți afișa anunțuri"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"anunțuri, confidențialitatea anunțurilor, privacy sandbox, subiectele anunțurilor, anunțuri sugerate de aplicații, cuantificarea anunțurilor"</string>
<string name="advanced_title" msgid="6259362998269627310">"Alte setări"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Mai multe setări pentru securitate și confidențialitate"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Completare automată, notificări și altele"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informații despre politica privind activitatea"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ro-v35/strings.xml b/SafetyCenter/Resources/res/values-ro-v35/strings.xml
new file mode 100644
index 000000000..1a6a5f43a
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ro-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Securitatea rețelei de date mobile"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tipul de rețea, criptarea, comenzile pentru notificări"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Spațiu privat"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Configurează Spațiul privat și altele"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Spațiu privat"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ru-v34/strings.xml b/SafetyCenter/Resources/res/values-ru-v34/strings.xml
index c2134acb9..b8a78d5ed 100644
--- a/SafetyCenter/Resources/res/values-ru-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ru-v34/strings.xml
@@ -22,13 +22,11 @@
<string name="privacy_sources_summary" msgid="4083646673569677049">"Разрешения, панель управления, параметры"</string>
<string name="health_connect_title" msgid="8318152190040327804">"Здоровье и спорт"</string>
<string name="health_connect_search_terms" msgid="4998970586245680829">"Здоровье, Здоровье и спорт"</string>
- <string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Обновление доступа к данным о местоположении"</string>
+ <string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Обновления в передаче данных о местоположении"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Данные, Передача данных, Обновления передачи данных, Обновление доступа к данным, Обновление доступа к данным о местоположении"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Конфиденциальность в рекламе"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Укажите, какую информацию приложения могут использовать для показа рекламы"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"объявления, конфиденциальность в рекламе, privacy sandbox, темы объявлений, реклама, предлагаемая приложениями, оценка эффективности рекламы"</string>
<string name="advanced_title" msgid="6259362998269627310">"Другие настройки"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Дополнительные настройки безопасности и конфиденциальности"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Автозаполнение, уведомления и другие настройки"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Сведения о правилах организации"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ru-v35/strings.xml b/SafetyCenter/Resources/res/values-ru-v35/strings.xml
new file mode 100644
index 000000000..3c1862167
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ru-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Безопасность мобильной сети"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Тип сети, шифрование, управление уведомлениями"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Личное пространство"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Настройка личного пространства и не только"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Личное пространство"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ru/strings.xml b/SafetyCenter/Resources/res/values-ru/strings.xml
index aaa71ae29..715e7ebb4 100644
--- a/SafetyCenter/Resources/res/values-ru/strings.xml
+++ b/SafetyCenter/Resources/res/values-ru/strings.xml
@@ -31,7 +31,7 @@
<string name="permission_usage_summary" msgid="5323079206029964468">"Посмотреть, какие приложения недавно использовали разрешения"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Конфиденциальность, панель управления разрешениями"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Управление разрешениями"</string>
- <string name="permission_manager_summary" msgid="8099852107340970790">"Настройки доступа приложений к вашим данным"</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_summary" msgid="2402066941190435424">"Настройки доступа к микрофону, камере и прочему"</string>
diff --git a/SafetyCenter/Resources/res/values-si-v34/strings.xml b/SafetyCenter/Resources/res/values-si-v34/strings.xml
index 0a54811f0..b2b291351 100644
--- a/SafetyCenter/Resources/res/values-si-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-si-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"සෞඛ්‍යය, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"ස්ථානය සඳහා දත්ත බෙදා ගැනීමේ යාවත්කාලීන"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"දත්ත, දත්ත බෙදා ගැනීම, දත්ත බෙදා ගැනීමේ යාවත්කාලීන, ස්ථානය සඳහා දත්ත බෙදා ගැනීමේ යාවත්කාලීන, බෙදා ගැනීම"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"දැන්වීම් පෞද්ගලිකත්වය"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"ඔබට දැන්වීම් පෙන්වීමට යෙදුම් භාවිතා කරන තතු අභිරුචිකරණය කරන්න"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"දැන්වීම්, දැන්වීම් පෞද්ගලිකත්වය, පෞද්ගලිකත්ව සෑන්ඩ්බොක්ස්, දැන්වීම් මාතෘකා, යෙදුම්-යෝජිත දැන්වීම්, දැන්වීම් මැනීම"</string>
<string name="advanced_title" msgid="6259362998269627310">"වෙනත් සැකසීම්"</string>
<string name="more_settings_title" msgid="9033454654010697185">"තව ආරක්ෂාව සහ පෞද්ගලිකත්වය"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ස්වයං පිරවීම, දැනුම්දීම්, සහ තවත් දේ"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"ඔබේ කාර්යාල ප්‍රතිපත්ති තතු"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-si-v35/strings.xml b/SafetyCenter/Resources/res/values-si-v35/strings.xml
new file mode 100644
index 000000000..1cf86f0e3
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-si-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"සෙලියුලර් ජාල ආරක්ෂාව"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ජාල වර්ගය, සංකේතනය, දැනුම්දීම් පාලන"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"පෞද්ගලික ඉඩ"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"පෞද්ගලික ඉඩ, සහ තවත් දේ පිහිටුවන්න"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"පෞද්ගලික ඉඩ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-sk-v34/strings.xml b/SafetyCenter/Resources/res/values-sk-v34/strings.xml
index 4b788d9fd..c3cdab5d2 100644
--- a/SafetyCenter/Resources/res/values-sk-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-sk-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Zdravie, Dáta o zdraví"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Aktualizácie zdieľania údajov o polohe"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Údaje, zdieľanie údajov, aktualizácie zdieľania údajov, aktualizácie zdieľania údajov o polohe, zdieľanie"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Ochrana súkromia pri reklamách"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Prispôsobovať informácie, podľa ktorých aplikácie zobrazujú reklamy"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklamy, ochrana súkromia pri reklamách, technológie privacy sandbox, témy reklám, reklamy navrhované aplikáciami, meranie reklám"</string>
<string name="advanced_title" msgid="6259362998269627310">"Ďalšie nastavenia"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Ďalšie zabezpečenie a ochrana súkromia"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Automatické dopĺňanie, upozornenia a ďalšie možnosti"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informácie o pracovných pravidlách"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sk-v35/strings.xml b/SafetyCenter/Resources/res/values-sk-v35/strings.xml
new file mode 100644
index 000000000..a0e64827e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sk-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Zabezpečenie mobilnej siete"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Ovládanie typu siete, šifrovania a upozornení"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Súkromný priestor"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Nastavte súkromný priestor a ďalšie možnosti"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Súkromný priestor"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-sl-v34/strings.xml b/SafetyCenter/Resources/res/values-sl-v34/strings.xml
index af8c92884..9898c2f0a 100644
--- a/SafetyCenter/Resources/res/values-sl-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-sl-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"zdravje, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Posodobitve deljenja podatkov o lokaciji"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"podatki, deljenje podatkov, posodobitve deljenja podatkov, posodobitve deljenja podatkov o lokaciji, deljenje"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Zasebnost pri oglaševanju"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Prilagodite, katere podatke uporabljajo aplikacije za prikazovanje oglasov."</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"oglasi, zasebnost pri oglaševanju, zasebni peskovnik, teme oglasov, oglasi na predlog aplikacij, merjenje oglasov"</string>
<string name="advanced_title" msgid="6259362998269627310">"Druge nastavitve"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Več varnosti in zasebnosti"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Samodejno izpolnjevanje, obvestila in drugo"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Podatki o službenem pravilniku"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sl-v35/strings.xml b/SafetyCenter/Resources/res/values-sl-v35/strings.xml
new file mode 100644
index 000000000..b36740d1e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sl-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Varnost mobilnega omrežja"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Vrsta omrežja, šifriranje, kontrolniki obvestil"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Zasebni prostor"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Nastavitev zasebnega prostora in drugo"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Zasebni prostor"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-sq-v34/strings.xml b/SafetyCenter/Resources/res/values-sq-v34/strings.xml
index 9306ad77d..64d7f4a4e 100644
--- a/SafetyCenter/Resources/res/values-sq-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-sq-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Shëndeti, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Përditësime për ndarjen e të dhënave për vendndodhjen"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Të dhënat, ndarja e të dhënave, përditësimet për ndarjen e të dhënave, përditësimet për ndarjen e të dhënave për vendndodhjen, ndarja"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privatësia e reklamave"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Informacionet e personalizuara që aplikacionet përdorin për të të shfaqur reklama"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklamat, privatësia e reklamave, privacy sandbox, temat e reklamave, reklamat e sugjeruara nga aplikacionet, matja e reklamave"</string>
<string name="advanced_title" msgid="6259362998269627310">"Cilësime të tjera"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Më shumë siguri dhe privatësi"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Plotësimi automatik, njoftimet dhe më shumë"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Informacioni i politikës së punës"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sq-v35/strings.xml b/SafetyCenter/Resources/res/values-sq-v35/strings.xml
new file mode 100644
index 000000000..6d0a4b25e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sq-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Siguria e rrjetit celular"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Lloji i rrjetit, enkriptimi, kontrollet e njoftimeve"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Hapësira private"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Konfiguro \"Hapësirën private\" dhe të tjera"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Hapësira private"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-sr-v34/strings.xml b/SafetyCenter/Resources/res/values-sr-v34/strings.xml
index 474c6a35d..9c69c8fad 100644
--- a/SafetyCenter/Resources/res/values-sr-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-sr-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"здравље, повезивање здравља"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Ажурирања дељења података за локацију"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"подаци, дељење података, ажурирања дељења података, ажурирања дељења података за локацију, дељење"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Приватност са огласима"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Прилагодите информације које апликације користе да би вам приказивале огласе"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"огласи, приватност са огласима, заштићено окружење приватности, теме огласа, огласи које предлажу апликације, мерење огласа"</string>
<string name="advanced_title" msgid="6259362998269627310">"Остала подешавања"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Још безбедности и приватности"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Аутоматско попуњавање, обавештења и друго"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Информације о смерницама за посао"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sr-v35/strings.xml b/SafetyCenter/Resources/res/values-sr-v35/strings.xml
new file mode 100644
index 000000000..814988c5c
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sr-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Безбедност мобилне мреже"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Тип мреже, шифровање, контроле обавештења"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Приватни простор"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Подесите приватни простор и друго"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Приватни простор"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-sr/strings.xml b/SafetyCenter/Resources/res/values-sr/strings.xml
index 4642ec771..2cd42d24c 100644
--- a/SafetyCenter/Resources/res/values-sr/strings.xml
+++ b/SafetyCenter/Resources/res/values-sr/strings.xml
@@ -20,7 +20,7 @@
<string name="safetyCenterResourcesAppLabel" msgid="4043334186295695930">"Ресурси Центра за безбедност"</string>
<string name="lock_screen_sources_title" msgid="3317906280484627707">"Закључавање уређаја"</string>
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
- <string name="lock_screen_title" msgid="4069104894527169877">"Закључавање екрана"</string>
+ <string name="lock_screen_title" msgid="4069104894527169877">"Откључавање екрана"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Још нема информација"</string>
<string name="lock_screen_search_terms" msgid="2678486357779794826">"закључавање уређаја, закључавање екрана, закључани екран, лозинка, PIN, шаблон"</string>
<string name="biometrics_title" msgid="5859504610285212938">"Биометрија"</string>
diff --git a/SafetyCenter/Resources/res/values-sv-v34/strings.xml b/SafetyCenter/Resources/res/values-sv-v34/strings.xml
index 3957a5e76..ef7de6322 100644
--- a/SafetyCenter/Resources/res/values-sv-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-sv-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Hälsa, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Uppdateringar om datadelning för plats"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Datadelning, Uppdateringar om datadelning, Uppdateringar om datadelning för plats, delning"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Annonsintegritet"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Anpassa information som appar använder för att visa annonser"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"annonser, annonsintegritet, privacy sandbox, annonsämnen, föreslagna annonser i appar, annonsmätning"</string>
<string name="advanced_title" msgid="6259362998269627310">"Andra inställningar"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Mer säkerhet och integritet"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofyll, aviseringar med mera"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Information om jobbprincip"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sv-v35/strings.xml b/SafetyCenter/Resources/res/values-sv-v35/strings.xml
new file mode 100644
index 000000000..108d28f75
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sv-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Säkerhet för mobilnätverk"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Nätverkstyp, kryptering, aviseringsinställningar"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Privat rum"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Ställ in privat rum med mera"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Privat rum"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-sw-v34/strings.xml b/SafetyCenter/Resources/res/values-sw-v34/strings.xml
index a9cb44a50..d065e2e03 100644
--- a/SafetyCenter/Resources/res/values-sw-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-sw-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Afya, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Masasisho ya kushiriki data ya mahali"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, kushiriki Data, masasisho ya kushiriki Data, Masasisho ya kushiriki data ya mahali, kushiriki"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Faragha ya matangazo"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Weka mapendeleo ya maelezo yanayotumiwa na programu kukuonyesha matangazo"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"matangazo, faragha ya matangazo, mazingira ya faragha, mada za tangazo, matangazo yanayopendekezwa na programu, upimaji wa tangazo"</string>
<string name="advanced_title" msgid="6259362998269627310">"Mipangilio mingine"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Usalama na faragha zaidi"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Kujaza kiotomatiki, arifa na zaidi"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Maelezo ya sera ya kazini"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sw-v35/strings.xml b/SafetyCenter/Resources/res/values-sw-v35/strings.xml
new file mode 100644
index 000000000..44a51760d
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sw-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Usalama wa mtandao wa simu"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Aina ya mtandao, usimbaji fiche, vidhibiti vya arifa"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Nafasi ya Faragha"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Weka mipangilio ya Nafasi ya Faragha na zaidi"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Nafasi ya Faragha"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-ta-v34/strings.xml b/SafetyCenter/Resources/res/values-ta-v34/strings.xml
index e59f639c9..b9f2a0b4e 100644
--- a/SafetyCenter/Resources/res/values-ta-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ta-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"இருப்பிடத்திற்கான தரவுப் பகிர்வு குறித்த அறிவிப்புகள்"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"தரவு, தரவுப் பகிர்வு, தரவுப் பகிர்வு குறித்த அறிவிப்புகள், இருப்பிடத்திற்கான தரவுப் பகிர்வு குறித்த அறிவிப்புகள், பகிர்வு"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"விளம்பரங்கள் தொடர்பான தனியுரிமை"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"உங்களுக்கு விளம்பரங்களைக் காட்டுவதற்காக ஆப்ஸ் பயன்படுத்தும் தகவல்களைப் பிரத்தியேகமாக்கலாம்"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"விளம்பரங்கள், விளம்பரங்கள் தொடர்பான தனியுரிமை, தனியுரிமை சாண்ட்பாக்ஸ், விளம்பரத் தலைப்புகள், ஆப்ஸால் பரிந்துரைக்கப்படும் விளம்பரங்கள், விளம்பர அளவீடு"</string>
<string name="advanced_title" msgid="6259362998269627310">"மற்ற அமைப்புகள்"</string>
<string name="more_settings_title" msgid="9033454654010697185">"கூடுதல் பாதுகாப்பு மற்றும் தனியுரிமை"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"தன்னிரப்பி, அறிவிப்புகள் மற்றும் பல"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"உங்கள் பணிக் கொள்கை பற்றிய தகவல்கள்"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ta-v35/strings.xml b/SafetyCenter/Resources/res/values-ta-v35/strings.xml
new file mode 100644
index 000000000..ba518fb66
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ta-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"மொபைல் நெட்வொர்க் பாதுகாப்பு"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"நெட்வொர்க் வகை, என்க்ரிப்ஷன், அறிவிப்புக் கட்டுப்பாடுகள்"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"தனிப்பட்ட சேமிப்பிடம்"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"தனிப்பட்ட சேமிப்பிடத்தை அமைக்கலாம் மற்றும் பலவற்றைச் செய்யலாம்"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"தனிப்பட்ட சேமிப்பிடம்"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-te-v34/strings.xml b/SafetyCenter/Resources/res/values-te-v34/strings.xml
index 6c9318f24..9ca7bea5f 100644
--- a/SafetyCenter/Resources/res/values-te-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-te-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"ఆరోగ్యం, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"లొకేషన్‌కు సంబంధించిన డేటా షేరింగ్ అప్‌డేట్‌లు"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"డేటా, డేటా షేరింగ్, డేటా షేరింగ్ అప్‌డేట్‌లు, లొకేషన్‌కు సంబంధించిన డేటా షేరింగ్ అప్‌డేట్‌లు, షేరింగ్"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"యాడ్‌ల విషయంలో గోప్యత"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"మీకు యాడ్‌లను చూపడానికి ఉపయోగించే సమాచార యాప్‌లను అనుకూలంగా మార్చండి"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"యాడ్‌లు, యాడ్‌ల విషయంలో గోప్యత, గోప్యతా పరిరక్షణ టెక్నాలజీల సెట్, యాడ్ టాపిక్‌లు, యాప్-సూచించిన యాడ్‌లు, యాడ్ మెజర్‌మెంట్"</string>
<string name="advanced_title" msgid="6259362998269627310">"ఇతర సెట్టింగ్‌లు"</string>
<string name="more_settings_title" msgid="9033454654010697185">"మరింత సెక్యూరిటీ &amp; గోప్యత"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"ఆటోఫిల్, నోటిఫికేషన్‌లు, అలాగే మరెన్నో"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"మీ వర్క్ పాలసీ సమాచారం"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-te-v35/strings.xml b/SafetyCenter/Resources/res/values-te-v35/strings.xml
new file mode 100644
index 000000000..757be94a0
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-te-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"సెల్యులర్ నెట్‌వర్క్ సెక్యూరిటీ"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"నెట్‌వర్క్ రకం, ఎన్‌క్రిప్షన్, నోటిఫికేషన్ కంట్రోల్స్"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"ప్రైవేట్ స్పేస్"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ప్రైవేట్ స్పేస్‌ను సెటప్ చేయండి, మరెన్నింటినో చేయండి"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"ప్రైవేట్ స్పేస్"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-te/strings.xml b/SafetyCenter/Resources/res/values-te/strings.xml
index 6763b1672..11c181a9c 100644
--- a/SafetyCenter/Resources/res/values-te/strings.xml
+++ b/SafetyCenter/Resources/res/values-te/strings.xml
@@ -28,10 +28,10 @@
<string name="privacy_sources_title" msgid="4061110826457365957">"గోప్యత"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"డ్యాష్‌బోర్డ్, అనుమతులు, కంట్రోల్స్"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"గోప్యతా డ్యాష్‌బోర్డ్"</string>
- <string name="permission_usage_summary" msgid="5323079206029964468">"ఇటీవల ఏ యాప్‌లు అనుమతులను ఉపయోగించాయో చూపించండి"</string>
+ <string name="permission_usage_summary" msgid="5323079206029964468">"ఇటీవల ఏ యాప్‌లు అనుమతులను ఉపయోగించాయో చూపిస్తుంది"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"గోప్యత, గోప్యతా డ్యాష్‌బోర్డ్"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"అనుమతి మేనేజర్"</string>
- <string name="permission_manager_summary" msgid="8099852107340970790">"మీ డేటాకు యాప్ యాక్సెస్‌ను కంట్రోల్ చేయండి"</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_summary" msgid="2402066941190435424">"మైక్రోఫోన్, కెమెరా, మరిన్నింటికి డివైజ్ యాక్సెస్‌ను కంట్రోల్ చేయండి"</string>
diff --git a/SafetyCenter/Resources/res/values-th-v34/strings.xml b/SafetyCenter/Resources/res/values-th-v34/strings.xml
index b323131b5..e334d9b5e 100644
--- a/SafetyCenter/Resources/res/values-th-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-th-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"สุขภาพ, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"การอัปเดตการแชร์ข้อมูลตำแหน่ง"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ข้อมูล, การแชร์ข้อมูล, การอัปเดตการแชร์ข้อมูล, การอัปเดตการแชร์ข้อมูลตำแหน่ง, การแชร์"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"ความเป็นส่วนตัวเกี่ยวกับโฆษณา"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"ปรับแต่งข้อมูลที่แอปใช้เพื่อแสดงโฆษณาต่อคุณ"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"โฆษณา, ความเป็นส่วนตัวเกี่ยวกับโฆษณา, Privacy Sandbox, หัวข้อโฆษณา, โฆษณาที่แอปแนะนำ, การวัดผลโฆษณา"</string>
<string name="advanced_title" msgid="6259362998269627310">"การตั้งค่าอื่นๆ"</string>
<string name="more_settings_title" msgid="9033454654010697185">"ความปลอดภัยและความเป็นส่วนตัวเพิ่มเติม"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"การป้อนข้อความอัตโนมัติ การแจ้งเตือน และอื่นๆ"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"ข้อมูลนโยบายการทำงาน"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-th-v35/strings.xml b/SafetyCenter/Resources/res/values-th-v35/strings.xml
new file mode 100644
index 000000000..8c00c1270
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-th-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"การรักษาความปลอดภัยของเครือข่ายมือถือ"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"ประเภทเครือข่าย การเข้ารหัส ส่วนควบคุมการแจ้งเตือน"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"พื้นที่ส่วนตัว"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"ตั้งค่าพื้นที่ส่วนตัวและอื่นๆ"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"พื้นที่ส่วนตัว"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-tl-v34/strings.xml b/SafetyCenter/Resources/res/values-tl-v34/strings.xml
index ef498d390..dd3754f15 100644
--- a/SafetyCenter/Resources/res/values-tl-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-tl-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Kalusugan, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Mga update sa pagbabahagi ng data para sa lokasyon"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Data, Pagbabahagi ng data, Mga update sa pagbabahagi ng data, Mga update sa pagbabahagi ng data para sa lokasyon, pagbabahagi"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Privacy sa ad"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"I-customize ang impormasyong ginagamit ng mga app para makapagpakita sa iyo ng mga ad"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"mga ad, privacy sa ad, privacy sandbox, mga paksa ng ad, mga ad na iminumungkahi ng app, pagsusukat ng ad"</string>
<string name="advanced_title" msgid="6259362998269627310">"Iba pang setting"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Higit na seguridad at privacy"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Autofill, mga notification, at higit pa"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Impormasyon tungkol sa iyong patakaran sa trabaho"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-tl-v35/strings.xml b/SafetyCenter/Resources/res/values-tl-v35/strings.xml
new file mode 100644
index 000000000..990f0e505
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-tl-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Seguridad ng cellular network"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Network type, pag-encrypt, mga kontrol sa notification"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Pribadong Space"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"I-set up ang Pribadong Space, at higit pa"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Pribadong Space"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-tr-v34/strings.xml b/SafetyCenter/Resources/res/values-tr-v34/strings.xml
index 8cf812a85..9d330c3ce 100644
--- a/SafetyCenter/Resources/res/values-tr-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-tr-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Sağlık, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Konum için veri paylaşımı güncellemeleri"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Veri, Veri paylaşımı, Veri paylaşımı güncellemeleri, Konum için veri paylaşımı güncellemeleri, paylaşım"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Reklam gizliliği"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Uygulamaların size reklam göstermek için kullandığı bilgileri özelleştirin"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklamlar, reklam gizliliği, özel korumalı alan, reklam konuları, uygulama tarafından önerilen reklamlar, reklam ölçümü"</string>
<string name="advanced_title" msgid="6259362998269627310">"Diğer ayarlar"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Daha fazla güvenlik ve gizlilik"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Otomatik doldurma, bildirimler ve daha fazlası"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"İş politikası bilgileriniz"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-tr-v35/strings.xml b/SafetyCenter/Resources/res/values-tr-v35/strings.xml
new file mode 100644
index 000000000..1c84e5cae
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-tr-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Hücresel ağ güvenliği"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Ağ türü, şifreleme, bildirim kontrolleri"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Gizli Alan"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Gizli alan yapılandırma ve daha fazlası"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Gizli Alan"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-uk-v34/strings.xml b/SafetyCenter/Resources/res/values-uk-v34/strings.xml
index b865ed57d..9d2ba565f 100644
--- a/SafetyCenter/Resources/res/values-uk-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-uk-v34/strings.xml
@@ -22,13 +22,11 @@
<string name="privacy_sources_summary" msgid="4083646673569677049">"Дозволи, панель керування, налаштування"</string>
<string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
<string name="health_connect_search_terms" msgid="4998970586245680829">"Здоров’я, Health Connect"</string>
- <string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Оновлення способу передавання геоданих"</string>
+ <string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Зміни в передаванні геоданих"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Дані, передавання даних, оновлення способу передавання даних, оновлення способу передавання геоданих, передавання"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Конфіденційність у рекламі"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Налаштуйте типи інформації, на основі якої додатки показуватимуть вам рекламу"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"реклама, конфіденційність у рекламі, privacy sandbox, теми оголошень, пропонована додатками реклама, вимірювання ефективності реклами"</string>
<string name="advanced_title" msgid="6259362998269627310">"Інші налаштування"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Краща безпека й конфіденційність"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Автозаповнення, сповіщення тощо"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Інформація про правила організації"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-uk-v35/strings.xml b/SafetyCenter/Resources/res/values-uk-v35/strings.xml
new file mode 100644
index 000000000..f8b981114
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-uk-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Безпека мобільної мережі"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Тип мережі, шифрування, налаштування сповіщень"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Приватний простір"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Налаштуйте приватний простір тощо"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Приватний простір"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-uk/strings.xml b/SafetyCenter/Resources/res/values-uk/strings.xml
index b7f6342db..0c1e109a3 100644
--- a/SafetyCenter/Resources/res/values-uk/strings.xml
+++ b/SafetyCenter/Resources/res/values-uk/strings.xml
@@ -24,13 +24,13 @@
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Поки немає інформації"</string>
<string name="lock_screen_search_terms" msgid="2678486357779794826">"блокування пристрою, блокування екрана, блокувати екран, заблокований екран, пароль, PIN-код, ключ"</string>
<string name="biometrics_title" msgid="5859504610285212938">"Біометрія"</string>
- <string name="biometrics_search_terms" msgid="6040319118762671981">"відбиток пальця, палець, додати відбиток пальця, фейсконтроль, обличчя"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"відбиток пальця, палець, додати відбиток пальця, фейс-контроль, обличчя"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Конфіденційність"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Панель керування, дозволи, параметри"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Панель керування дозволами"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Перегляньте, які додатки нещодавно використовували дозволи"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"конфіденційність, панель керування дозволами"</string>
- <string name="permission_manager_title" msgid="5277347862821255015">"Диспетчер дозволів"</string>
+ <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>
diff --git a/SafetyCenter/Resources/res/values-ur-v34/strings.xml b/SafetyCenter/Resources/res/values-ur-v34/strings.xml
index b03da6a69..eb6e1e407 100644
--- a/SafetyCenter/Resources/res/values-ur-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-ur-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"‏صحت، Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"مقام کے لیے ڈیٹا کے اشتراک کی اپ ڈیٹس"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ڈیٹا، ڈیٹا کا اشتراک، ڈیٹا کے اشتراک کی اپ ڈیٹس، ڈیٹا کے اشتراک کی اپ ڈیٹس برائے مقام، اشتراک کرنا"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"اشتہار کی رازداری"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"اس معلومات کو حسب ضرورت بنائیں جس کو ایپس آپ کو اشتہارات دکھانے کیلئے استعمال کرتی ہیں"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"اشتہارات، اشتہار کی رازداری، رازداری سینڈ باکس، اشتہار کے عنوانات، ایپس کے تجویز کردہ اشتہارات، اشتہار کی پیمائش"</string>
<string name="advanced_title" msgid="6259362998269627310">"دیگر ترتیبات"</string>
<string name="more_settings_title" msgid="9033454654010697185">"مزید سیکیورٹی اور رازداری"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"آٹوفل، اطلاعات اور مزید"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"آپ کے کام سے متعلق پالیسی کی معلومات"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ur-v35/strings.xml b/SafetyCenter/Resources/res/values-ur-v35/strings.xml
new file mode 100644
index 000000000..5dd2ca23b
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ur-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"سیلولر نیٹ ورک سیکیورٹی"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"نیٹ ورک کی قسم، مرموز کاری، نوٹیفکیشن کنٹرولز"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"نجی اسپیس"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"نجی اسپیس اور بھی بہت کچھ سیٹ اپ کریں"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"نجی اسپیس"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-uz-v34/strings.xml b/SafetyCenter/Resources/res/values-uz-v34/strings.xml
index 8c85eedea..1304a81f6 100644
--- a/SafetyCenter/Resources/res/values-uz-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-uz-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Joylashuv axboroti ulashuvida oʻzgarishlar"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Maʼlumotlar, maʼlumotlar ulashuvi, maʼlumotlar ulashuvi yangilanishi, joylashuv axboroti ulashuvida oʻzgarishlar, ulashuv"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Reklamadagi maxfiylik"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Reklamalarni chiqarishda ilovalar foydalanadigan maʼlumotlarni belgilang"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"reklama, reklamada maxfiylik, maxfiylik sinovi, reklama mavzulari, ilova taklif qiladigan reklama, reklama hisoblanishi"</string>
<string name="advanced_title" msgid="6259362998269627310">"Boshqa sozlamalar"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Qoʻshimcha xavfsizlik va maxfiylik sozlamalari"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Avtomatik kiritish, bildirishnomalar va boshqalar"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Ish siyosati haqida axborot"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-uz-v35/strings.xml b/SafetyCenter/Resources/res/values-uz-v35/strings.xml
new file mode 100644
index 000000000..f7822cfd5
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-uz-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Mobil tarmoq xavfsizligi"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Tarmoq turi, shifrlash, bildirishnomalar boshqaruvi"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Maxfiy joy"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Maxfiy joyni sozlash"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Maxfiy joy"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-uz/strings.xml b/SafetyCenter/Resources/res/values-uz/strings.xml
index 2d99d80b2..f97bfa320 100644
--- a/SafetyCenter/Resources/res/values-uz/strings.xml
+++ b/SafetyCenter/Resources/res/values-uz/strings.xml
@@ -27,7 +27,7 @@
<string name="biometrics_search_terms" msgid="6040319118762671981">"Barmoq izi, barmoq, barmoq izi qoʻshish, yuz bilan ochish, yuz"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Maxfiylik"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Boshqaruv paneli, ruxsatlar, boshqaruv"</string>
- <string name="permission_usage_title" msgid="3633779688945350407">"Maxfiylik boshqaruv paneli"</string>
+ <string name="permission_usage_title" msgid="3633779688945350407">"Maxfiylik boshqaruvi"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Oxirgi marta qaysi ilovalar ruxsatlardan foydalanganini koʻrsatish"</string>
<string name="permission_usage_search_terms" msgid="3852343592870257104">"Maxfiylik, maxfiylik boshqaruv paneli"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Ruxsatlar boshqaruvi"</string>
diff --git a/SafetyCenter/Resources/res/values-v34/config.xml b/SafetyCenter/Resources/res/values-v34/config.xml
index db79e5924..c3e1e38a2 100644
--- a/SafetyCenter/Resources/res/values-v34/config.xml
+++ b/SafetyCenter/Resources/res/values-v34/config.xml
@@ -20,4 +20,6 @@
<string name="config_same_task_safety_source_ids" translatable="false">AndroidAccessibility,AndroidBackgroundLocation,AndroidBiometrics,AndroidHealthConnect,AndroidLockScreen,AndroidMoreSettings,AndroidNotificationListener,AndroidPermissionAutoRevoke,AndroidPermissionManager,AndroidPermissionUsage,AndroidPrivacyAppDataSharingUpdates,AndroidPrivacyControls,AndroidWorkPolicyInfo</string>
<!-- Comma separated list of safety source IDs to add an Intent Extra confirming they should be displayed as if opened by a settings UI page. -->
<string name="config_useSettingsHomepageIntentExtra" translatable="false">AndroidMoreSettings,TestSource</string>
+ <!-- Comma separated list of safety source IDs that should be refreshed on page open by default. -->
+ <string name="config_defaultRefreshOnPageOpenSources" translatable="false">AndroidBiometrics</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-v35/config.xml b/SafetyCenter/Resources/res/values-v35/config.xml
new file mode 100644
index 000000000..3d8ac11ea
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-v35/config.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Comma separated list of safety source IDs to show in the same task as the safety center -->
+ <string name="config_same_task_safety_source_ids" translatable="false">AndroidAccessibility,AndroidBackgroundLocation,AndroidBiometrics,AndroidHealthConnect,AndroidLockScreen,AndroidPrivateSpace,AndroidMoreSettings,AndroidNotificationListener,AndroidPermissionAutoRevoke,AndroidPermissionManager,AndroidPermissionUsage,AndroidPrivacyAppDataSharingUpdates,AndroidPrivacyControls,AndroidWorkPolicyInfo</string>
+ <!-- Comma separated list of safety source IDs to add an Intent Extra confirming they should be displayed as if opened by a settings UI page. -->
+ <string name="config_useSettingsHomepageIntentExtra" translatable="false">AndroidMoreSettings,AndroidPrivateSpace,TestSource</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-v35/strings.xml b/SafetyCenter/Resources/res/values-v35/strings.xml
new file mode 100644
index 000000000..af43f11f2
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-v35/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Cellular Network Security -->
+ <string name="cellular_network_security_title" description="The title of the group of safety settings relating to cellular network security">Cellular network security</string>
+ <string name="cellular_network_security_summary" description="The summary of the group of safety settings relating to cellular network security, which describes the group contents">Network type, encryption, notification controls</string>
+
+ <!-- More settings -->
+ <string name="private_space_title" description="The title of the entry for Private Space">Private Space</string>
+ <string name="private_space_summary" description="The summary of the entry for Private Space settings, which describes the page contents">Setup Private Space, and more</string>
+ <string name="private_space_search_terms" description="Search keywords of the entry for Private Space settings">Private Space</string>
+
+</resources>
diff --git a/SafetyCenter/Resources/res/values-vi-v34/strings.xml b/SafetyCenter/Resources/res/values-vi-v34/strings.xml
index 473a3db59..c4b5ad44f 100644
--- a/SafetyCenter/Resources/res/values-vi-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-vi-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Sức khoẻ, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Cập nhật chế độ Chia sẻ dữ liệu vị trí"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Dữ liệu, tính năng Chia sẻ dữ liệu, cập nhật chế độ Chia sẻ dữ liệu, cập nhật chế độ Chia sẻ dữ liệu vị trí, chia sẻ"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Quyền riêng tư trong quảng cáo"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Tuỳ chỉnh thông tin được các ứng dụng dùng để hiển thị quảng cáo cho bạn"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"quảng cáo, quyền riêng tư trong quảng cáo, hộp cát về quyền riêng tư, chủ đề quảng cáo, quảng cáo do ứng dụng gợi ý, đo lường quảng cáo"</string>
<string name="advanced_title" msgid="6259362998269627310">"Chế độ cài đặt khác"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Các chế độ khác về bảo mật và quyền riêng tư"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Tự động điền, thông báo và nhiều chế độ cài đặt khác"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Thông tin về chính sách của nơi bạn làm việc"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-vi-v35/strings.xml b/SafetyCenter/Resources/res/values-vi-v35/strings.xml
new file mode 100644
index 000000000..cefc57faa
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-vi-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Chế độ bảo mật mạng di động"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Loại mạng, quy trình mã hoá, quyền kiểm soát thông báo"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Không gian riêng tư"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Thiết lập Không gian riêng tư và các tính năng khác"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Không gian riêng tư"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-vi/strings.xml b/SafetyCenter/Resources/res/values-vi/strings.xml
index 1a1b22ccc..e121cad41 100644
--- a/SafetyCenter/Resources/res/values-vi/strings.xml
+++ b/SafetyCenter/Resources/res/values-vi/strings.xml
@@ -37,7 +37,7 @@
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kiểm soát quyền truy cập của thiết bị vào micrô, máy ảnh và nhiều ứng dụng khác"</string>
<string name="privacy_controls_search_terms" msgid="3774472175934304165">"Quyền riêng tư, Chế độ kiểm soát quyền riêng tư"</string>
<string name="advanced_title" msgid="8745436380690561172">"Chế độ cài đặt khác"</string>
- <string name="advanced_security_title" msgid="1126833338772188155">"Các chế độ cài đặt bảo mật khác"</string>
+ <string name="advanced_security_title" msgid="1126833338772188155">"Chế độ cài đặt bảo mật khác"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Mã hoá, thông tin xác thực và các chế độ cài đặt khác"</string>
<string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Các chế độ cài đặt quyền riêng tư khác"</string>
diff --git a/SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml b/SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml
index 4109e8228..ff50335d8 100644
--- a/SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml
@@ -20,15 +20,13 @@
<string name="lock_screen_sources_title" msgid="5493678510117489865">"设备解锁"</string>
<string name="biometrics_title_for_work" msgid="1842284049407771568">"适用于工作应用的生物识别"</string>
<string name="privacy_sources_summary" msgid="4083646673569677049">"权限、信息中心和控件"</string>
- <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
- <string name="health_connect_search_terms" msgid="4998970586245680829">"健康, Health, Health Connect"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"健康数据共享"</string>
+ <string name="health_connect_search_terms" msgid="4998970586245680829">"健康, 健康数据共享, Health, Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"位置数据分享方面的更新"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"数据, 数据分享, 数据分享方面的更新, 位置数据分享方面的更新, 分享, Data, Data sharing, Data sharing updates, Data sharing updates for location, sharing"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"广告隐私权"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"自定义应用可以使用哪些信息来向您展示广告"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"广告, 广告隐私权, Privacy Sandbox, 广告主题, 应用建议的广告, 广告衡量, ads, ad privacy, privacy sandbox, ad topics, app-suggested ads, ad measurement"</string>
<string name="advanced_title" msgid="6259362998269627310">"其他设置"</string>
- <string name="more_settings_title" msgid="9033454654010697185">"更多安全性和隐私权设置"</string>
+ <string name="more_settings_title" msgid="9033454654010697185">"更多安全和隐私设置"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"自动填充、通知等"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"您的工作政策信息"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-zh-rCN-v35/strings.xml b/SafetyCenter/Resources/res/values-zh-rCN-v35/strings.xml
new file mode 100644
index 000000000..e0be57584
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-zh-rCN-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"移动网络安全性"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"网络类型、加密、通知控件"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"私密空间"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"设置私密空间等"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"私密空间"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml b/SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml
index 1d27b164c..c850335ad 100644
--- a/SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml
@@ -21,14 +21,12 @@
<string name="biometrics_title_for_work" msgid="1842284049407771568">"用於工作應用程式的生物識別選項"</string>
<string name="privacy_sources_summary" msgid="4083646673569677049">"權限、資訊主頁、控制項"</string>
<string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
- <string name="health_connect_search_terms" msgid="4998970586245680829">"健康, Health Connect"</string>
+ <string name="health_connect_search_terms" msgid="4998970586245680829">"健康, 健康資料同步"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"位置資料分享更新"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"資料, 資料分享, 資料分享更新, 位置資料分享更新, 分享"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"廣告私隱權"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"自訂應用程式根據哪些資料向您顯示廣告"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"廣告, 廣告私隱權, 私隱沙箱, 廣告主題, 應用程式建議廣告, 廣告評估功能"</string>
<string name="advanced_title" msgid="6259362998269627310">"其他設定"</string>
<string name="more_settings_title" msgid="9033454654010697185">"更多安全性和私隱權設定"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"自動填入、通知等"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"你的工作政策資料"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-zh-rHK-v35/strings.xml b/SafetyCenter/Resources/res/values-zh-rHK-v35/strings.xml
new file mode 100644
index 000000000..334da7a63
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-zh-rHK-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"流動網絡安全性"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"網絡類型、加密、通知控制項"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"私人空間"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"設定「私人空間」等項目"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"私人空間"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml b/SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml
index 4c00d5c77..09f8e9d5d 100644
--- a/SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml
@@ -20,15 +20,13 @@
<string name="lock_screen_sources_title" msgid="5493678510117489865">"裝置解鎖"</string>
<string name="biometrics_title_for_work" msgid="1842284049407771568">"工作應用程式的生物特徵辨識選項"</string>
<string name="privacy_sources_summary" msgid="4083646673569677049">"權限、資訊主頁、控制選項"</string>
- <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
- <string name="health_connect_search_terms" msgid="4998970586245680829">"健康、Health Connect"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"健康資料同步"</string>
+ <string name="health_connect_search_terms" msgid="4998970586245680829">"健康, 健康資料同步"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"位置資料分享更新"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"資料, 資料分享, 資料分享更新, 位置資料分享更新, 分享"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"廣告隱私權"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"自訂應用程式可用來放送廣告的資訊"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"廣告, 廣告隱私權, Privacy Sandbox, 廣告主題, 應用程式建議廣告, 廣告評估"</string>
<string name="advanced_title" msgid="6259362998269627310">"其他設定"</string>
<string name="more_settings_title" msgid="9033454654010697185">"其他安全性和隱私權設定"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"自動填入、通知等等"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"公司政策資訊"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-zh-rTW-v35/strings.xml b/SafetyCenter/Resources/res/values-zh-rTW-v35/strings.xml
new file mode 100644
index 000000000..2e21b3047
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-zh-rTW-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"行動網路安全性"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"網路類型、加密、通知控制選項"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"私人空間"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"設定私人空間等項目"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"私人空間"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-zu-v34/strings.xml b/SafetyCenter/Resources/res/values-zu-v34/strings.xml
index d7c75a0a8..d5c86c668 100644
--- a/SafetyCenter/Resources/res/values-zu-v34/strings.xml
+++ b/SafetyCenter/Resources/res/values-zu-v34/strings.xml
@@ -24,11 +24,9 @@
<string name="health_connect_search_terms" msgid="4998970586245680829">"Impilo, i-Health Connect"</string>
<string name="app_data_sharing_updates_title" msgid="7428862330643262588">"Izibuyekezo zokwabelana ngedatha zendawo"</string>
<string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Idatha, Ukwabelana ngedatha, Izibuyekezo zokwabelana ngedatha, Izibuyekezo zokwabelana ngedatha zendawo, ukwabelana"</string>
- <string name="ads_privacy_title" msgid="2478678200445158640">"Ubumfihlo besikhangiso"</string>
- <string name="ads_privacy_summary" msgid="4977699525670966049">"Enza ngokwezifiso ama-app asetshenziswayo ukukubonisa izikhangiso"</string>
- <string name="ads_privacy_search_terms" msgid="8008413316055240046">"izikhangiso, ubumfihlo bezikhangiso, i-sandbox yobumfihlo, izihloko zesikhangiso, izikhangiso zeziphakamiso ze-app, ukukalwa kwesikhangiso"</string>
<string name="advanced_title" msgid="6259362998269627310">"Amanye amasethingi"</string>
<string name="more_settings_title" msgid="9033454654010697185">"Ukuvikeleka okwengeziwe nobumfihlo"</string>
<string name="more_settings_summary" msgid="7086620830002515710">"Ukugcwalisa okuzenzekelayo, isaziso, nokuningi"</string>
<string name="more_settings_search_terms" msgid="1371913937610933955"></string>
+ <string name="work_policy_title" msgid="915692932391542104">"Ulwazi lwenqubomgomo yakho yomsebenzi"</string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-zu-v35/strings.xml b/SafetyCenter/Resources/res/values-zu-v35/strings.xml
new file mode 100644
index 000000000..4576f3dd0
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-zu-v35/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="cellular_network_security_title" msgid="2986431282931510973">"Ukuphepha kwenethiwekhi yeselula"</string>
+ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Uhlobo lwenethiwekhi, ukubethela, izilawuli zezaziso"</string>
+ <string name="private_space_title" msgid="6158245041481535879">"Isikhala Esiyimfihlo"</string>
+ <string name="private_space_summary" msgid="529869826714610294">"Setha Isikhala Esiyimfihlo, nokunye"</string>
+ <string name="private_space_search_terms" msgid="4820808478299116258">"Isikhala Esiyimfihlo"</string>
+</resources>
diff --git a/SafetyCenter/Resources/res/values/config.xml b/SafetyCenter/Resources/res/values/config.xml
index 6b20b69b4..2c92afb21 100644
--- a/SafetyCenter/Resources/res/values/config.xml
+++ b/SafetyCenter/Resources/res/values/config.xml
@@ -22,4 +22,6 @@
<string name="config_NotificationListenerServicePregrants" translatable="false"></string>
<!-- Comma separated list of safety source IDs to add an Intent Extra confirming they should be displayed as if opened by a settings UI page. -->
<string name="config_useSettingsHomepageIntentExtra" translatable="false">AndroidAdvancedPrivacy,AndroidAdvancedSecurity,TestSource</string>
+ <!-- Comma separated list of safety source IDs that should be refreshed on page open by default. -->
+ <string name="config_defaultRefreshOnPageOpenSources" translatable="false"></string>
</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-af/strings.xml b/SafetyCenter/Resources/shared_res/values-af/strings.xml
index 74ecafb6c..3c20c6428 100644
--- a/SafetyCenter/Resources/shared_res/values-af/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-af/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Skandeer tans"</string>
<string name="loading_summary" msgid="3740846439782713910">"Gaan tans toestelinstellings na …"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Lyk goed"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Geen probleme gevind nie"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Wenk beskikbaar}other{Wenke beskikbaar}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Geen kwessies is gekry nie"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Sien aanbeveling}other{Sien aanbevelings}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Handeling uitgevoer}other{Handelinge uitgevoer}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Gaan instellings na"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Gaan instellingslys na"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potensiële risiko’s gevind"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risiko’s gevind"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Rekening is dalk in gevaar"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Rekening is in gevaar"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Sien waarskuwing hieronder}other{Sien waarskuwings hieronder}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Rekening is in gevaar"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Sien waarskuwing}other{Sien waarskuwings}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Kon nie bladsy oopmaak nie"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Kon nie opletberig afhandel nie"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Kon nie instellings herlaai nie"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Kon nie instelling nagaan nie}other{Kon nie instellings nagaan nie}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Werkprofiel is onderbreek"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Nog geen inligting nie"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-am/strings.xml b/SafetyCenter/Resources/shared_res/values-am/strings.xml
index 0e123315a..d1080ebf7 100644
--- a/SafetyCenter/Resources/shared_res/values-am/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-am/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"በመቃኘት ላይ"</string>
<string name="loading_summary" msgid="3740846439782713910">"የመሣሪያ ቅንብሮችን በመፈተሽ ላይ…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ጥሩ ይመስላል"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"ምንም ችግሮች አልተገኙም"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{ጠቃሚ ምክር ይገኛል}one{ጠቃሚ ምክር ይገኛል}other{ጠቃሚ ምክሮች ይገኛሉ}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"ምንም ችግሮች አልተገኙም"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{ምክር ይመልከቱ}one{ምክር ይመልከቱ}other{ምክሮችን ይመልከቱ}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{የተወሰደ እርምጃ}one{የተወሰደ እርምጃ}other{የተወሰዱ እርምጃዎች}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ቅንብሮችን ይከልሱ"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"የቅንብሮች ዝርዝርን ይፈትሹ"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"ሊከሰቱ የሚችሉ አደጋዎች ተገኝተዋል"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"አደጋዎች ተገኝተዋል"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"መለያ አደጋ ላይ ሊሆን ይችላል"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"መለያ አደጋ ላይ ነው"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{ማንቂያን ከታች ይመልከቱ}one{ማንቂያን ከታች ይመልከቱ}other{ማንቂያዎችን ከታች ይመልከቱ}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"መለያ አደጋ ላይ ነው"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{ማንቂያ ይመልከቱ}one{ማንቂያ ይመልከቱ}other{ማንቂያዎች ይመልከቱ}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"ገጹን መከፈት አልተቻለም"</string>
<string name="resolving_action_error" msgid="371968886143262375">"ማንቂያን መፍታት አልተቻለም"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ቅንብሮችን ማደስ አልተቻለም"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ቅንብርን መፈተሽ አልተቻለም}one{ቅንብርን መፈተሽ አልተቻለም}other{ቅንብሮችን መፈተሽ አልተቻለም}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"የስራ መገለጫ ባለበት ቆሟል"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ገና ምንም መረጃ የለም"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ar/strings.xml b/SafetyCenter/Resources/shared_res/values-ar/strings.xml
index c83c5d713..49e16c39c 100644
--- a/SafetyCenter/Resources/shared_res/values-ar/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ar/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"جارٍ الفحص"</string>
<string name="loading_summary" msgid="3740846439782713910">"جارٍ التحقّق من إعدادات الجهاز…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"كل شيء على ما يرام"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"لم يتم العثور على أي مشاكل"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{تتوفّر نصيحة.}zero{تتوفّر نصائح.}two{تتوفّر نصيحتان.}few{تتوفّر نصائح.}many{تتوفّر نصائح.}other{تتوفّر نصائح.}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"لم يتم رصد أي مشاكل."</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{الاطّلاع على اقتراح}zero{الاطّلاع على اقتراحات}two{الاطّلاع على اقتراحَين}few{الاطّلاع على اقتراحات}many{الاطّلاع على اقتراحات}other{الاطّلاع على اقتراحات}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{الإجراء الذي تم اتخاذه}zero{الإجراءات التي تم اتخاذها}two{الإجراءان اللذان تم اتخاذهما}few{الإجراءات التي تم اتخاذها}many{الإجراءات التي تم اتخاذها}other{الإجراءات التي تم اتخاذها}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"مراجعة الإعدادات"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"الاطّلاع على قائمة الإعدادات"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"هناك مخاطر محتملة"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"هناك مخاطر"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"قد يكون الحساب معرّضًا للخطر"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"الحساب معرّض للخطر"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{راجِع التنبيه أدناه.}zero{راجِع التنبيهات أدناه.}two{راجِع التنبيهَين أدناه.}few{راجِع التنبيهات أدناه.}many{راجِع التنبيهات أدناه.}other{راجِع التنبيهات أدناه.}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"الحساب معرّض للخطر"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{الاطّلاع على التنبيه}zero{الاطّلاع على التنبيهات}two{الاطّلاع على التنبيهَين}few{الاطّلاع على التنبيهات}many{الاطّلاع على التنبيهات}other{الاطّلاع على التنبيهات}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"تعذَّر فتح الصفحة"</string>
<string name="resolving_action_error" msgid="371968886143262375">"تعذَّر التعامل بشكل نهائي مع التنبيه"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"تعذّر تحديث الإعدادات"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{تعذّر التحقّق من الإعداد.}zero{تعذّر التحقّق من الإعدادات.}two{تعذّر التحقّق من الإعدادَين.}few{تعذّر التحقّق من الإعدادات.}many{تعذّر التحقّق من الإعدادات.}other{تعذّر التحقّق من الإعدادات.}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"تم إيقاف الملف الشخصي للعمل مؤقتًا"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ما مِن معلومات بعد."</string>
diff --git a/SafetyCenter/Resources/shared_res/values-as/strings.xml b/SafetyCenter/Resources/shared_res/values-as/strings.xml
index 90ae9c5c2..4105c26d0 100644
--- a/SafetyCenter/Resources/shared_res/values-as/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-as/strings.xml
@@ -19,9 +19,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="scanning_title" msgid="5424849039854311398">"স্কেন কৰি থকা হৈছে"</string>
<string name="loading_summary" msgid="3740846439782713910">"ডিভাইচৰ ছেটিং পৰীক্ষা কৰি থকা হৈছে…"</string>
- <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ভাল যেন লাগিছে"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"কোনো সমস্যা পোৱা নগ’ল"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{পৰামৰ্শ উপলব্ধ}one{পৰামৰ্শ উপলব্ধ}other{পৰামৰ্শ উপলব্ধ}}"</string>
+ <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ঠিকেই লাগিছে"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"কোনো সমস্যা পোৱা নগ’ল"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{চুপাৰিছ চাওক}one{চুপাৰিছসমূহ চাওক}other{চুপাৰিছসমূহ চাওক}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{কাৰ্যব্যৱস্থা লোৱা হৈছে}one{কাৰ্যব্যৱস্থা লোৱা হৈছে}other{কাৰ্যব্যৱস্থা লোৱা হৈছে}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ছেটিং পৰ্যালোচনা কৰক"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ছেটিঙৰ সূচী পৰীক্ষা কৰক"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"সম্ভাব্য বিপদাশংকা পোৱা গৈছে"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"বিপদাশংকা পোৱা গৈছে"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"একাউণ্টটোত বিপদাশংকা থাকিব পাৰে"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"একাউণ্টৰ বিপদাশংকা আছে"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{তলত সতৰ্কবাৰ্তা চাওক}one{তলত সতৰ্কবাৰ্তা চাওক}other{তলত সতৰ্কবাৰ্তা চাওক}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"একাউণ্টটোত বিপদাশংকা আছে"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{সতৰ্কবাৰ্তা চাওক}one{সতৰ্কবাৰ্তাসমূহ চাওক}other{সতৰ্কবাৰ্তাসমূহ চাওক}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"পৃষ্ঠাখন খুলিব পৰা নগ’ল"</string>
<string name="resolving_action_error" msgid="371968886143262375">"সতৰ্কবাৰ্তা সমাধান কৰিব পৰা নগ’ল"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ছেটিং ৰিফ্ৰেশ্ব কৰিব পৰা নগ’ল"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ছেটিং পৰীক্ষা কৰিব পৰা নগ’ল}one{ছেটিং পৰীক্ষা কৰিব পৰা নগ’ল}other{ছেটিং পৰীক্ষা কৰিব পৰা নগ’ল}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"কৰ্মস্থানৰ প্ৰ’ফাইলটো পজ কৰা আছে"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"এতিয়ালৈকে কোনো তথ্য নাই"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-az/strings.xml b/SafetyCenter/Resources/shared_res/values-az/strings.xml
index a9c7e92ae..7e2e7c140 100644
--- a/SafetyCenter/Resources/shared_res/values-az/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-az/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Skan edilir"</string>
<string name="loading_summary" msgid="3740846439782713910">"Cihaz ayarları yoxlanılır…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Yaxşı görünür"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Heç bir problem tapılmadı"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{İpucu əlçatandır}other{İpucları əlçatandır}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Problem tapılmadı"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Tövsiyəyə baxın}other{Tövsiyələrə baxın}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Görülən tədbir}other{Görülən tədbirlər}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Ayarları nəzərdən keçirin"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Ayarlar siyahısını yoxlayın"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potensial risklər tapıldı"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risklər tapıldı"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Hesab risk altında ola bilər"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Hesab risk altındadır"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Aşağıdakı siqnala baxın}other{Aşağıdakı siqnallara baxın}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Hesab risk altındadır"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Xəbərdarlığa baxın}other{Xəbərdarlıqlara baxın}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Səhifəni açmaq mümkün olmadı"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Siqnalı həll etmək mümkün olmadı"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Ayarları yeniləmək mümkün olmadı"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Ayarı yoxlamaq alınmadı}other{Ayarları yoxlamaq alınmadı}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"İş profili durdurulub"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Hələ ki, məlumat yoxdur"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml b/SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml
index 2ce59e648..19660cb06 100644
--- a/SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Skenira se"</string>
<string name="loading_summary" msgid="3740846439782713910">"Proveravamo podešavanja uređaja…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Sve je u redu"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nije pronađen nijedan problem"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Dostupan je savet}one{Dostupni su saveti}few{Dostupni su saveti}other{Dostupni su saveti}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nije pronađen nijedan problem"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Prikaži preporuku}one{Prikaži preporuke}few{Prikaži preporuke}other{Prikaži preporuke}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Preduzeta radnja}one{Preduzete radnje}few{Preduzete radnje}other{Preduzete radnje}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Pregledajte podešavanja"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Proverite listu podešavanja"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Pronađeni su potencijalni rizici"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Pronađeni su rizici"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Nalog je možda ugrožen"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Nalog je ugrožen"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Pogledajte upozorenje ispod}one{Pogledajte upozorenja ispod}few{Pogledajte upozorenja ispod}other{Pogledajte upozorenja ispod}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Nalog je ugrožen"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Prikaži obaveštenje}one{Prikaži obaveštenja}few{Prikaži obaveštenja}other{Prikaži obaveštenja}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Otvaranje stranice nije uspelo"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Rešavanje obaveštenja nije uspelo"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Osvežavanje podešavanja nije uspelo"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Provera podešavanja nije uspela}one{Provera podešavanja nije uspela}few{Provera podešavanja nije uspela}other{Provera podešavanja nije uspela}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Poslovni profil je pauziran"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Još nema informacija"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-be/strings.xml b/SafetyCenter/Resources/shared_res/values-be/strings.xml
index 5dfc83cc5..2c27670e4 100644
--- a/SafetyCenter/Resources/shared_res/values-be/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-be/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Выконваецца праверка"</string>
<string name="loading_summary" msgid="3740846439782713910">"Праверка налад прылады…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Усё ў парадку"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Праблемы не знойдзены"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Скарыстайце параду}one{Скарыстайце парады}few{Скарыстайце парады}many{Скарыстайце парады}other{Скарыстайце парады}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Праблем не знойдзена"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Паглядзець рэкамендацыю}one{Паглядзець рэкамендацыі}few{Паглядзець рэкамендацыі}many{Паглядзець рэкамендацыі}other{Паглядзець рэкамендацыі}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Мера прынята}one{Меры прыняты}few{Меры прыняты}many{Меры прыняты}other{Меры прыняты}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Праглядзець налады"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Праверыць спіс налад"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Выяўлена патэнцыяльная небяспека"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Выяўлена небяспека"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Уліковы запіс можа быць у небяспецы"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Уліковы запіс у небяспецы"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Глядзіце апавяшчэнне ніжэй}one{Глядзіце апавяшчэнні ніжэй}few{Глядзіце апавяшчэнні ніжэй}many{Глядзіце апавяшчэнні ніжэй}other{Глядзіце апавяшчэнні ніжэй}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Уліковы запіс у небяспецы"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Паглядзець абвестку}one{Паглядзець абвесткі}few{Паглядзець абвесткі}many{Паглядзець абвесткі}other{Паглядзець абвесткі}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Не ўдалося адкрыць старонку"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Не ўдалося вырашыць праблему"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Не ўдалося абнавіць налады"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Не ўдалося праверыць наладу}one{Не ўдалося праверыць налады}few{Не ўдалося праверыць налады}many{Не ўдалося праверыць налады}other{Не ўдалося праверыць налады}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Працоўны профіль прыпынены"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Пакуль няма інфармацыі"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-bg/strings.xml b/SafetyCenter/Resources/shared_res/values-bg/strings.xml
index 74c581599..e3495d4d5 100644
--- a/SafetyCenter/Resources/shared_res/values-bg/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-bg/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Сканиране"</string>
<string name="loading_summary" msgid="3740846439782713910">"Настройките на устройството се проверяват…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Изглежда добре"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Няма открити проблеми"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Налице е съвет}other{Налице са съвети}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Няма открити проблеми"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Преглед на препоръката}other{Преглед на препоръките}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Предприето е действие}other{Предприети са действия}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Преглед на настройките"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Проверка на списъка с настройки"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Открити са потенциални рискове"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Открити са рискове"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Профилът може да е изложен на риск"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Профилът е изложен на риск"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Вижте сигнала по-долу}other{Вижте сигналите по-долу}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Профилът е изложен на риск"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Преглед на сигнала}other{Преглед на сигналите}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Страницата не се отвори"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Сигналът не се отстрани"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Настройките не бяха опреснени"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Настройката не бе проверена}other{Настройките не бяха проверени}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Служебният потребителски профил е поставен на пауза"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Още няма информация"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-bn/strings.xml b/SafetyCenter/Resources/shared_res/values-bn/strings.xml
index 99a2205b9..3f24f05a4 100644
--- a/SafetyCenter/Resources/shared_res/values-bn/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-bn/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"স্ক্যান করা হচ্ছে"</string>
<string name="loading_summary" msgid="3740846439782713910">"ডিভাইস সেটিংস চেক করা হচ্ছে…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"সব ঠিক আছে"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"কোনও সমস্যা পাওয়া যায়নি"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{পরামর্শ উপলভ্য আছে}one{পরামর্শ উপলভ্য আছে}other{পরামর্শ উপলভ্য আছে}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"কোনও সমস্যা পাওয়া যায়নি"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{সাজেশন দেখুন}one{সাজেশন দেখুন}other{সাজেশন দেখুন}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{অ্যাকশন নেওয়া হয়েছে}one{অ্যাকশন নেওয়া হয়েছে}other{অ্যাকশন নেওয়া হয়েছে}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"সেটিংস পর্যালোচনা করুন"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"সেটিংস তালিকা চেক করুন"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"সম্ভাব্য ঝুঁকি খুঁজে পাওয়া গেছে"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"ঝুঁকির বিষয়টি খুঁজে পাওয়া গেছে"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"অ্যাকাউন্টের হয়ত ক্ষতি হতে পারে"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"অ্যাকাউন্টের ক্ষতি হতে পারে"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{নিচে সতর্কতা দেখুন}one{নিচে সতর্কতা দেখুন}other{নিচে সতর্কতা দেখুন}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"অ্যাকাউন্ট সুরক্ষিত নয়"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{বিজ্ঞপ্তি দেখুন}one{বিজ্ঞপ্তি দেখুন}other{বিজ্ঞপ্তি দেখুন}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"পৃষ্ঠা খোলা যায়নি"</string>
<string name="resolving_action_error" msgid="371968886143262375">"সতর্কতার সমাধান করা যায়নি"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"সেটিংস রিফ্রেশ করা যায়নি"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{সেটিং চেক করা যায়নি}one{সেটিংস চেক করা যায়নি}other{সেটিংস চেক করা যায়নি}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"অফিস প্রোফাইল পজ করা আছে"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"এখনও কোনও তথ্য নেই"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-bs/strings.xml b/SafetyCenter/Resources/shared_res/values-bs/strings.xml
index 3b53a5b00..a877f8b36 100644
--- a/SafetyCenter/Resources/shared_res/values-bs/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-bs/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Skeniranje"</string>
<string name="loading_summary" msgid="3740846439782713910">"Provjera postavki uređaja…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Izgleda dobro"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nije pronađen nijedan problem"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Savjet je dostupan}one{Savjeti su dostupni}few{Savjeti su dostupni}other{Savjeti su dostupni}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nije pronađen nijedan problem"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Pogledajte preporuku}one{Pogledajte preporuke}few{Pogledajte preporuke}other{Pogledajte preporuke}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Poduzeta ja radnja}one{Poduzete su radnje}few{Poduzete su radnje}other{Poduzete su radnje}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Pregledajte postavke"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Provjerite listu postavki"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Pronađeni su potencijalni rizici"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Pronađeni su rizici"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Račun bi mogao biti izložen riziku"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Račun je izložen riziku"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Pogledajte upozorenje u nastavku}one{Pogledajte upozorenja u nastavku}few{Pogledajte upozorenja u nastavku}other{Pogledajte upozorenja u nastavku}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Račun je izložen riziku"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Pogledajte upozorenje}one{Pogledajte upozorenja}few{Pogledajte upozorenja}other{Pogledajte upozorenja}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Otvaranje stranice nije uspjelo"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Rješavanje upozorenja nije uspjelo"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Osvježavanje postavki nije uspjelo"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Provjera postavke nije uspjela}one{Provjera postavki nije uspjela}few{Provjera postavki nije uspjela}other{Provjera postavki nije uspjela}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Radni profil je pauziran"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Još uvijek nema informacija"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ca/strings.xml b/SafetyCenter/Resources/shared_res/values-ca/strings.xml
index 46e395667..640a723c1 100644
--- a/SafetyCenter/Resources/shared_res/values-ca/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ca/strings.xml
@@ -20,13 +20,13 @@
<string name="scanning_title" msgid="5424849039854311398">"S\'està analitzant"</string>
<string name="loading_summary" msgid="3740846439782713910">"S\'està comprovant la configuració del dispositiu…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Tot correcte"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"No s\'ha trobat cap problema"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Hi ha un consell disponible}many{Hi ha consells disponibles}other{Hi ha consells disponibles}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"No s\'ha trobat cap problema"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Mostra la recomanació}many{Mostra les recomanacions}other{Mostra les recomanacions}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{S\'ha dut a terme una acció}many{S\'han dut a terme accions}other{S\'han dut a terme accions}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Revisa la configuració"</string>
- <string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Comprova la llista de configuració"</string>
+ <string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Comprova la llista d\'opcions de configuració"</string>
<string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"El dispositiu pot estar en perill"</string>
- <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"El dispositiu està en perill"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Dispositiu en perill"</string>
<string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Les dades poden estar en perill"</string>
<string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Les dades estan en perill"</string>
<string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Contrasenyes en perill (antigues)"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"S\'han trobat possibles riscos"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"S\'han trobat riscos"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"El compte pot estar en perill"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Aquest compte està en perill"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Revisa l\'alerta següent}many{Revisa les alertes següents}other{Revisa les alertes següents}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"El compte està en perill"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Mostra l\'alerta}many{Mostra les alertes}other{Mostra les alertes}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"No s\'ha pogut obrir la pàgina"</string>
<string name="resolving_action_error" msgid="371968886143262375">"No s\'ha pogut resoldre l\'alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"No s\'ha pogut actualitzar la configuració"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{No s\'ha pogut comprovar la configuració}many{No s\'ha pogut comprovar la configuració}other{No s\'ha pogut comprovar la configuració}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"El perfil de treball s\'ha posat en pausa"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Encara no hi ha informació"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-cs/strings.xml b/SafetyCenter/Resources/shared_res/values-cs/strings.xml
index ef97185fb..28aabd4e8 100644
--- a/SafetyCenter/Resources/shared_res/values-cs/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-cs/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Probíhá kontrola"</string>
<string name="loading_summary" msgid="3740846439782713910">"Kontrola nastavení zařízení…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Všechno v pořádku"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nebyly nalezeny žádné problémy"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Je k dispozici tip}few{Jsou k dispozici tipy}many{Jsou k dispozici tipy}other{Jsou k dispozici tipy}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nebyly zjištěny žádné problémy"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Zobrazit doporučení}few{Zobrazit doporučení}many{Zobrazit doporučení}other{Zobrazit doporučení}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Bylo přijato opatření}few{Byla přijata opatření}many{Byla přijata opatření}other{Byla přijata opatření}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Zkontrolujte nastavení"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Zkontrolujte seznam nastavení"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Byla nalezena možná rizika"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Byla nalezena rizika"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Účet může být ohrožen"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Účet je ohrožen"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Přečtěte si upozornění níže}few{Přečtěte si upozornění níže}many{Přečtěte si upozornění níže}other{Přečtěte si upozornění níže}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Účet je ohrožen"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Zobrazit upozornění}few{Zobrazit upozornění}many{Zobrazit upozornění}other{Zobrazit upozornění}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Stránku nelze otevřít"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Upozornění se nepodařilo vyřešit"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nastavení se nepodařilo obnovit"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nastavení nelze zkontrolovat}few{Nastavení nelze zkontrolovat}many{Nastavení nelze zkontrolovat}other{Nastavení nelze zkontrolovat}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Pracovní profil je pozastaven"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Zatím žádné údaje"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-da/strings.xml b/SafetyCenter/Resources/shared_res/values-da/strings.xml
index 1903c2a23..e4d28aaf1 100644
--- a/SafetyCenter/Resources/shared_res/values-da/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-da/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Scanner"</string>
<string name="loading_summary" msgid="3740846439782713910">"Tjekker enheds­indstillinger…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Det ser fint ud"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Der blev ikke fundet nogen problemer"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Der er et tilgængeligt tip}one{Der er et tilgængeligt tip}other{Der er tilgængelige tips}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Der blev ikke fundet nogen problemer"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Se anbefaling}one{Se anbefaling}other{Se anbefalinger}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{En handling er udført}one{En handling er udført}other{Handlinger er udført}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Gennemgå indstillingerne"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Tjek listen over indstillinger"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Der blev fundet potentielle risici"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Der blev fundet risici"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Kontoen kan være sårbar"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Kontoen er sårbar"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Se underretningen nedenfor}one{Se underretningen nedenfor}other{Se underretningerne nedenfor}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Kontoen er sårbar"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Se underretning}one{Se underretning}other{Se underretninger}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Siden kunne ikke åbnes"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Underretningen kunne ikke behandles"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Indstillingerne kunne ikke opdateres"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Indstillingen kunne ikke tjekkes}one{Indstillingen kunne ikke tjekkes}other{Indstillingerne kunne ikke tjekkes}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Arbejdsprofilen er sat på pause"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Der er ingen oplysninger endnu"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-de/strings.xml b/SafetyCenter/Resources/shared_res/values-de/strings.xml
index d3777c6c9..0ff9ebfb8 100644
--- a/SafetyCenter/Resources/shared_res/values-de/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-de/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Scan wird ausgeführt"</string>
<string name="loading_summary" msgid="3740846439782713910">"Ge­räte­ein­stel­lungen wer­den ge­prüft…­"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Alles in Ordnung"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Keine Probleme gefunden"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Tipp verfügbar}other{Tipps verfügbar}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Keine Probleme gefunden"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Empfehlung ansehen}other{Empfehlungen ansehen}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Maßnahme ergriffen}other{Maßnahmen ergriffen}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Einstellungen prüfen"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Liste der Einstellungen prüfen"</string>
@@ -36,15 +36,14 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Mögliche Sicherheitsrisiken gefunden"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Sicherheitsrisiken gefunden"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Konto eventuell gefährdet"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Konto gefährdet"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Benachrichtigung unten ansehen}other{Benachrichtigungen unten ansehen}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Konto ist gefährdet"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Benachrichtigung ansehen}other{Benachrichtigungen ansehen}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Seite konnte nicht geöffnet werden"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Ursache konnte nicht behoben werden"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Einstellungen konnten nicht aktualisiert werden"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Einstellung konnte nicht überprüft werden}other{Einstellungen konnten nicht überprüft werden}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Arbeitsprofil pausiert"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Noch keine Angaben vorhanden"</string>
- <string name="notification_channel_group_name" msgid="7155072032524876859">"Sicherheit &amp; Datenschutz"</string>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Datenschutz &amp; Sicherheit"</string>
<string name="notification_channel_name_information" msgid="2966444432152990166">"Empfehlungen"</string>
<string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Warnungen"</string>
<string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Wichtige Warnungen"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-el/strings.xml b/SafetyCenter/Resources/shared_res/values-el/strings.xml
index 194ce7b43..c6f005d5f 100644
--- a/SafetyCenter/Resources/shared_res/values-el/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-el/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Σάρωση"</string>
<string name="loading_summary" msgid="3740846439782713910">"Έλεγχος ρυθμίσεων συσκευής…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Όλα εντάξει"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Δεν εντοπίστηκαν προβλήματα"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Διαθέσιμη συμβουλή}other{Διαθέσιμες συμβουλές}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Δεν βρέθηκαν προβλήματα"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Εμφάνιση πρότασης}other{Εμφάνιση προτάσεων}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Ενέργεια που εκτελέστηκε}other{Ενέργειες που εκτελέστηκαν}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Έλεγχος ρυθμίσεων"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Έλεγχος λίστας ρυθμίσεων"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Εντοπίστηκαν πιθανοί κίνδυνοι"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Εντοπίστηκαν κίνδυνοι"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Ο λογαριασμός μπορεί να κινδυνεύει"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Ο λογαριασμός βρίσκεται σε κίνδυνο"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Δείτε την παρακάτω ειδοποίηση}other{Δείτε τις παρακάτω ειδοποιήσεις}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Ο λογαριασμός κινδυνεύει"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Εμφάνιση ειδοποίησης}other{Εμφάνιση ειδοποιήσεων}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Δεν ήταν δυνατό το άνοιγμα της σελίδας"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Δεν ήταν δυνατή η επίλυση της ειδοποίησης"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Δεν ήταν δυνατή η ανανέωση των ρυθμίσεων"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Δεν ήταν δυνατός ο έλεγχος της ρύθμισης}other{Δεν ήταν δυνατός ο έλεγχος των ρυθμίσεων}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Το προφίλ εργασίας έχει τεθεί σε παύση"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Δεν υπάρχουν ακόμα πληροφορίες"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml
index 30a550534..f389be966 100644
--- a/SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Scanning"</string>
<string name="loading_summary" msgid="3740846439782713910">"Checking device settings…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Looks fine"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"No problems found"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Tip available}other{Tips available}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"No issues found"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{See recommendation}other{See recommendations}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Action taken}other{Actions taken}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Review settings"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Check settings list"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potential risks found"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risks found"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Account may be at risk"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Account is at risk"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{See alert below}other{See alerts below}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Account at risk"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{See alert}other{See alerts}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Couldn\'t open page"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Couldn\'t resolve alert"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Couldn\'t refresh settings"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Couldn\'t check setting}other{Couldn\'t check settings}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Work profile is paused"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"No info yet"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml
index de95f0bd0..00234beca 100644
--- a/SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Scanning"</string>
<string name="loading_summary" msgid="3740846439782713910">"Checking device settings…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Looks good"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"No problems found"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Tip available}other{Tips available}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"No issues found"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{See recommendation}other{See recommendations}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Action taken}other{Actions taken}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Review settings"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Check settings list"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potential risks found"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risks found"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Account may be at risk"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Account is at risk"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{See alert below}other{See alerts below}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Account at risk"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{See alert}other{See alerts}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Couldnt open page"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Couldnt resolve alert"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Couldnt refresh settings"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Couldnt check setting}other{Couldnt check settings}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Work profile is paused"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"No info yet"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml
index 30a550534..f389be966 100644
--- a/SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Scanning"</string>
<string name="loading_summary" msgid="3740846439782713910">"Checking device settings…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Looks fine"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"No problems found"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Tip available}other{Tips available}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"No issues found"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{See recommendation}other{See recommendations}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Action taken}other{Actions taken}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Review settings"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Check settings list"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potential risks found"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risks found"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Account may be at risk"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Account is at risk"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{See alert below}other{See alerts below}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Account at risk"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{See alert}other{See alerts}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Couldn\'t open page"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Couldn\'t resolve alert"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Couldn\'t refresh settings"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Couldn\'t check setting}other{Couldn\'t check settings}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Work profile is paused"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"No info yet"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml
index 30a550534..f389be966 100644
--- a/SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Scanning"</string>
<string name="loading_summary" msgid="3740846439782713910">"Checking device settings…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Looks fine"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"No problems found"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Tip available}other{Tips available}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"No issues found"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{See recommendation}other{See recommendations}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Action taken}other{Actions taken}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Review settings"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Check settings list"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potential risks found"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risks found"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Account may be at risk"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Account is at risk"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{See alert below}other{See alerts below}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Account at risk"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{See alert}other{See alerts}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Couldn\'t open page"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Couldn\'t resolve alert"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Couldn\'t refresh settings"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Couldn\'t check setting}other{Couldn\'t check settings}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Work profile is paused"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"No info yet"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml
index 111622cf3..811e6e7fd 100644
--- a/SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‏‏‎‎Scanning‎‏‎‎‏‎"</string>
<string name="loading_summary" msgid="3740846439782713910">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎Checking device settings…‎‏‎‎‏‎"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎Looks good‎‏‎‎‏‎"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎No problems found‎‏‎‎‏‎"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎Tip available‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎Tips available‎‏‎‎‏‎}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎No issues found‎‏‎‎‏‎"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‏‏‏‎See recommendation‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‏‏‏‎See recommendations‎‏‎‎‏‎}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎Action taken‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎Actions taken‎‏‎‎‏‎}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎Review settings‎‏‎‎‏‎"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‏‎Check settings list‎‏‎‎‏‎"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎Potential risks found‎‏‎‎‏‎"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎Risks found‎‏‎‎‏‎"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎Account may be at risk‎‏‎‎‏‎"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎Account is at risk‎‏‎‎‏‎"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎See alert below‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎See alerts below‎‏‎‎‏‎}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎Account at risk‎‏‎‎‏‎"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎See alert‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎See alerts‎‏‎‎‏‎}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎Couldnt open page‎‏‎‎‏‎"</string>
<string name="resolving_action_error" msgid="371968886143262375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎Couldnt resolve alert‎‏‎‎‏‎"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‎‎Couldnt refresh settings‎‏‎‎‏‎"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎Couldnt check setting‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎Couldnt check settings‎‏‎‎‏‎}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‏‎Work profile is paused‎‏‎‎‏‎"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎No info yet‎‏‎‎‏‎"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml b/SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml
index ef0ef2532..29613fc69 100644
--- a/SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml
@@ -20,10 +20,10 @@
<string name="scanning_title" msgid="5424849039854311398">"Explorando"</string>
<string name="loading_summary" msgid="3740846439782713910">"Verificando la configuración del dispositivo…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Todo en orden"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"No se encontraron problemas"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Sugerencia disponible}many{Sugerencias disponibles}other{Sugerencias disponibles}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"No se encontraron problemas"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Ver recomendación}many{Ver recomendaciones}other{Ver recomendaciones}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Se tomó una medida}many{Se tomaron medidas}other{Se tomaron medidas}}"</string>
- <string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Revisar la configuración"</string>
+ <string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Revisa la configuración"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Verifica la lista de configuración"</string>
<string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"El dispositivo podría estar en riesgo"</string>
<string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"El dispositivo está en riesgo"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Se detectaron riesgos potenciales"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Se detectaron riesgos"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"La cuenta podría estar en riesgo"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"La cuenta está en riesgo"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Ve la alerta a continuación}many{Ve las alertas a continuación}other{Ve las alertas a continuación}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"La cuenta está en riesgo"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Ver alerta}many{Ver alertas}other{Ver alertas}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"No se pudo abrir la página"</string>
<string name="resolving_action_error" msgid="371968886143262375">"No se pudo resolver la alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"No se pudo actualizar la configuración"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{No se pudo revisar el parámetro de configuración}many{No se pudieron revisar los parámetros de configuración}other{No se pudieron revisar los parámetros de configuración}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"El perfil de trabajo está en pausa"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Aún no hay información"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-es/strings.xml b/SafetyCenter/Resources/shared_res/values-es/strings.xml
index df61a3507..a13a68d8f 100644
--- a/SafetyCenter/Resources/shared_res/values-es/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-es/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Analizan­do"</string>
<string name="loading_summary" msgid="3740846439782713910">"Comprobando los ajustes del dispositivo…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Todo correcto"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"No se ha encontrado ningún problema"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Consejo disponible}many{Consejos disponibles}other{Consejos disponibles}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"No se ha detectado ningún problema"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Ver recomendación}many{Ver recomendaciones}other{Ver recomendaciones}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Medida tomada}many{Medidas tomadas}other{Medidas tomadas}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Revisa los ajustes"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Comprueba la lista de ajustes"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Posibles riesgos detectados"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Riesgos detectados"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"La cuenta puede estar en riesgo"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"La cuenta está en riesgo"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Consulta la alerta a continuación}many{Consulta las alertas a continuación}other{Consulta las alertas a continuación}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"La cuenta está en riesgo"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Ver alerta}many{Ver alertas}other{Ver alertas}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"No se ha podido abrir la página"</string>
<string name="resolving_action_error" msgid="371968886143262375">"No se ha podido resolver la alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"No se han podido actualizar los ajustes"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{No se ha podido comprobar el ajuste}many{No se han podido comprobar los ajustes}other{No se han podido comprobar los ajustes}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"El perfil de trabajo está en pausa"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Aún no hay información"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-et/strings.xml b/SafetyCenter/Resources/shared_res/values-et/strings.xml
index c3662a022..cfe0541d2 100644
--- a/SafetyCenter/Resources/shared_res/values-et/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-et/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Skannimine"</string>
<string name="loading_summary" msgid="3740846439782713910">"Seadme seadete kontrollimine …"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Korras"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Probleeme ei leitud"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Saadaval on nõuanne}other{Saadaval on nõuanded}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Ühtegi probleemi ei leitud"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Vaadake soovitust}other{Vaadake soovitusi}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Tehti toiming}other{Tehti toimingud}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Vaadake seaded üle"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Kontrollige seadete loendit"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Leiti võimalikud ohud"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Leiti ohud"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Konto võib olla ohus"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Konto on ohus"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Vaadake allolevat hoiatust}other{Vaadake allolevaid hoiatusi}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Konto on ohus"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Vaadake hoiatust}other{Vaadake hoiatusi}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Lehte ei saanud avada"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Hoiatusega seotud probleemi ei saanud lahendada"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Seadeid ei saanud värskendada"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Seadet ei õnnestunud kontrollida}other{Seadeid ei õnnestunud kontrollida}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Tööprofiil on peatatud"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Teavet ei ole veel"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-eu/strings.xml b/SafetyCenter/Resources/shared_res/values-eu/strings.xml
index 6ceb84df7..c00cb5827 100644
--- a/SafetyCenter/Resources/shared_res/values-eu/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-eu/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Aztertzen"</string>
<string name="loading_summary" msgid="3740846439782713910">"Gailuaren ezarpenak egiaztatzen…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Ondo dago"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Ez da aurkitu arazorik"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Aholku bat duzu}other{Aholkuak dituzu}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Ez da aurkitu arazorik"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Ikusi gomendioa}other{Ikusi gomendioak}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Zerbait egin da}other{Zerbait egin da}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Berrikusi ezarpenak"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Egiaztatu ezarpenen zerrenda"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Balizko arriskuak aurkitu dira"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Arriskuak aurkitu dira"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Baliteke kontua arriskuan egotea"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Kontua arriskuan dago"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Ikusi alerta behean}other{Ikusi alertak behean}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Kontua arriskuan dago"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Ikusi alerta}other{Ikusi alertak}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Ezin da ireki orria"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Ezin izan da ebatzi alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Ezin izan dira freskatu ezarpenak"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Ezin izan da egiaztatu ezarpena}other{Ezin izan dira egiaztatu ezarpenak}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Laneko profila pausatuta dago"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ez dago informaziorik oraindik"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-fa/strings.xml b/SafetyCenter/Resources/shared_res/values-fa/strings.xml
index 61f47275d..744ac950c 100644
--- a/SafetyCenter/Resources/shared_res/values-fa/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-fa/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"درحال اسکن کردن"</string>
<string name="loading_summary" msgid="3740846439782713910">"درحال بررسی تنظیمات دستگاه…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"خوب است"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"مشکلی پیدا نشد"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{نکته دردسترس است}one{نکته دردسترس است}other{نکته‌هایی دردسترس است}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"مشکلی پیدا نشد"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{دیدن توصیه}one{دیدن توصیه}other{دیدن توصیه‌ها}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{اقدام انجام شد}one{اقدام انجام شد}other{اقدامات انجام شد}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"مرور تنظیمات"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"بررسی فهرست تنظیمات"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"خطرات احتمالی پیدا شده است"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"خطراتی پیدا شده است"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ممکن است حساب درمعرض خطر باشد"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"حساب درمعرض خطر است"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{دیدن هشدار در زیر}one{دیدن هشدار در زیر}other{دیدن هشدارها در زیر}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"حساب درمعرض خطر است"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{دیدن هشدار}one{دیدن هشدار}other{دیدن هشدارها}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"صفحه باز نشد"</string>
<string name="resolving_action_error" msgid="371968886143262375">"هشدار رفع نشد"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"تنظیمات بازآوری نشد"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{تنظیم بررسی نشد}one{تنظیم بررسی نشد}other{تنظیمات بررسی نشدند}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"نمایه کاری موقتاً متوقف شده است"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"هنوز اطلاعاتی دردسترس نیست"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-fi/strings.xml b/SafetyCenter/Resources/shared_res/values-fi/strings.xml
index 667b9bef2..801b40081 100644
--- a/SafetyCenter/Resources/shared_res/values-fi/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-fi/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Skannataan"</string>
<string name="loading_summary" msgid="3740846439782713910">"Tarkistetaan laiteasetuksia…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Hyvältä näyttää"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Ongelmia ei löytynyt"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Vinkki saatavilla}other{Vinkkejä saatavilla}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Ongelmia ei havaittu"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Näytä suositus}other{Näytä suositukset}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Tehty toiminto}other{Tehdyt toiminnot}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Tarkista asetukset"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Tarkista asetuslista"</string>
@@ -36,15 +36,14 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Mahdollisia riskejä löydetty"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Tietoturvariskejä löydetty"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Tili voi olla vaarantunut"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Tili on vaarantunut"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Katso ilmoitus alla}other{Katso ilmoitukset alla}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Tili on vaarantunut"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Näytä ilmoitus}other{Näytä ilmoitukset}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Sivun avaaminen epäonnistui"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Hälytyksen ratkaiseminen epäonnistui"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Asetuksia ei voitu päivittää"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Asetuksen tarkistaminen ei onnistunut}other{Asetusten tarkistaminen ei onnistunut}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Työprofiilin käyttö on keskeytetty"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ei vielä tietoa"</string>
- <string name="notification_channel_group_name" msgid="7155072032524876859">"Tietoturva ja yksityisyys"</string>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Turvallisuus ja yksityisyys"</string>
<string name="notification_channel_name_information" msgid="2966444432152990166">"Suositukset"</string>
<string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Varoitukset"</string>
<string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kriittiset varoitukset"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml b/SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml
index 4c80652ad..3956c61f5 100644
--- a/SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Analyse en cours"</string>
<string name="loading_summary" msgid="3740846439782713910">"Vérification des paramètres de l\'appareil en cours…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Tout semble correct"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Aucun problème trouvé"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Conseil proposé}one{Conseil proposé}many{Conseils proposés}other{Conseils proposés}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Aucun problème détecté"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Afficher la recommandation}one{Afficher la recommandation}many{Afficher les recommandations}other{Afficher les recommandations}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Mesure prise}one{Mesure prise}many{Mesures prises}other{Mesures prises}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Vérifier les paramètres"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Vérifiez la liste des paramètres"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Dangers potentiels trouvés"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Dangers trouvés"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Le compte pourrait être en danger"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Le compte est en danger"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Consultez l\'alerte ci-dessous}one{Consultez l\'alerte ci-dessous}many{Consultez les alertes ci-dessous}other{Consultez les alertes ci-dessous}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Compte à risque"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Afficher l\'alerte}one{Afficher l\'alerte}many{Afficher les alertes}other{Afficher les alertes}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Impossible d\'ouvrir la page"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Impossible de résoudre l\'alerte"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Impossible d\'actualiser les paramètres"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Impossible de vérifier le paramètre}one{Impossible de vérifier le paramètre}many{Impossible de vérifier les paramètres}other{Impossible de vérifier les paramètres}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Le profil professionnel est interrompu"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Aucune donnée pour le moment"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-fr/strings.xml b/SafetyCenter/Resources/shared_res/values-fr/strings.xml
index 9a22eaea3..b05f99a15 100644
--- a/SafetyCenter/Resources/shared_res/values-fr/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-fr/strings.xml
@@ -20,13 +20,13 @@
<string name="scanning_title" msgid="5424849039854311398">"Analyse"</string>
<string name="loading_summary" msgid="3740846439782713910">"Vérification des paramètres de l\'appareil…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Tout semble bon"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Aucun problème détecté"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Conseil disponible}one{Conseil disponible}many{Conseils disponibles}other{Conseils disponibles}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Aucun problème détecté"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Voir la recommandation}one{Voir la recommandation}many{Voir les recommandations}other{Voir les recommandations}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Mesure prise}one{Mesure prise}many{Mesures prises}other{Mesures prises}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Vérifier les paramètres"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Vérifier la liste des paramètres"</string>
- <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Risque potentiel sur l\'appareil"</string>
- <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Risque sur l\'appareil"</string>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Appareil présentant un risque potentiel"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Appareil présentant un risque"</string>
<string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Risque potentiel sur vos données"</string>
<string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Risque sur vos données"</string>
<string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Mots de passe compromis (anciens)"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Risque de sécurité"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Risques potentiels détectés"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risques détectés"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Risque potentiel sur le compte"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Risque sur le compte"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Voir l\'alerte ci-dessous}one{Voir l\'alerte ci-dessous}many{Voir les alertes ci-dessous}other{Voir les alertes ci-dessous}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Compte présentant un risque potentiel"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Compte présentant un risque"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Voir l\'alerte}one{Voir l\'alerte}many{Voir les alertes}other{Voir les alertes}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Impossible d\'accéder à la page"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Impossible de résoudre l\'alerte"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Impossible d\'actualiser les paramètres"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Impossible de vérifier le paramètre}one{Impossible de vérifier le paramètre}many{Impossible de vérifier les paramètres}other{Impossible de vérifier les paramètres}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Profil professionnel en pause"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Aucune info pour l\'instant"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-gl/strings.xml b/SafetyCenter/Resources/shared_res/values-gl/strings.xml
index eaf924353..3a0251dd2 100644
--- a/SafetyCenter/Resources/shared_res/values-gl/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-gl/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Analizando"</string>
<string name="loading_summary" msgid="3740846439782713910">"Comprobando configuración do dispositivo…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Parece que todo está ben"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Non se atoparon problemas"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Consello dispoñible}other{Consellos dispoñibles}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Non se atopou ningún problema"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Consulta a recomendación}other{Consulta as recomendacións}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Acción levada a cabo}other{Accións levadas a cabo}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Revisa a configuración"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Revisa a lista de opcións de configuración"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Atopáronse posibles riscos"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Atopáronse riscos"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"A conta pode estar en risco"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"A conta está en risco"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Ver a alerta a continuación}other{Ver as alertas a continuación}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"A conta está en risco"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Consulta a alerta}other{Consulta as alertas}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Non se puido abrir a páxina"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Non se puido resolver a alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Non se puido actualizar a configuración"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Non se puido comprobar a opción de configuración}other{Non se puideron comprobar as opcións de configuración}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"O perfil de traballo está en pausa"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Aínda non hai información"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-gu/strings.xml b/SafetyCenter/Resources/shared_res/values-gu/strings.xml
index 6731ec6dd..ded82b3e5 100644
--- a/SafetyCenter/Resources/shared_res/values-gu/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-gu/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"સ્કૅનિંગ"</string>
<string name="loading_summary" msgid="3740846439782713910">"ડિવાઇસના સેટિંગ ચેક કરી રહ્યાં છીએ…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"સરસ દેખાય છે"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"કોઈ સમસ્યા મળી નથી"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{ટિપ ઉપલબ્ધ છે}one{ટિપ ઉપલબ્ધ છે}other{ટિપ ઉપલબ્ધ છે}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"કોઈ સમસ્યા મળી નથી"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{સુઝાવ જુઓ}one{સુઝાવ જુઓ}other{સુઝાવો જુઓ}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{લેવાયેલું પગલું}one{લેવાયેલું પગલું}other{લેવાયેલા પગલાં}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"સેટિંગનો રિવ્યૂ કરો"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"સેટિંગની સૂચિ ચેક કરો"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"સંભવિત જોખમો મળ્યા"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"જોખમો મળ્યા"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"એકાઉન્ટ જોખમમાં હોઈ શકે છે"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"એકાઉન્ટ જોખમમાં છે"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{નીચે આપેલું અલર્ટ જુઓ}one{નીચે આપેલું અલર્ટ જુઓ}other{નીચે આપેલા અલર્ટ જુઓ}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Google એકાઉન્ટ જોખમમાં"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{અલર્ટ જુઓ}one{અલર્ટ જુઓ}other{અલર્ટ જુઓ}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"પેજ ખોલી શક્યા નથી"</string>
<string name="resolving_action_error" msgid="371968886143262375">"અલર્ટનું નિરાકરણ લાવી શક્યા નથી"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"સેટિંગ રિફ્રેશ કરી શકાયા નથી"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{સેટિંગ ચેક કરી શકાયું નથી}one{સેટિંગ ચેક કરી શકાયું નથી}other{સેટિંગ ચેક કરી શકાયા નથી}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"ઑફિસની પ્રોફાઇલ થોભાવી છે"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"હજી સુધી કોઈ માહિતી નથી"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-hi/strings.xml b/SafetyCenter/Resources/shared_res/values-hi/strings.xml
index 2df7ef702..6fe62b414 100644
--- a/SafetyCenter/Resources/shared_res/values-hi/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-hi/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"स्कैन किया जा रहा है"</string>
<string name="loading_summary" msgid="3740846439782713910">"डिवाइस सेटिंग की जांच हो रही है…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"डिवाइस सुरक्षित लग रहा है"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"कोई समस्या नहीं मिली"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{सुझाव दिया गया है}one{सुझाव दिया गया है}other{सुझाव दिए गए हैं}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"कोई समस्या नहीं मिली"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{सुझाव देखें}one{सुझाव देखें}other{सुझावों को देखें}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{कार्रवाई की गई है}one{कार्रवाई की गई है}other{कार्रवाइयां की गई हैं}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"सेटिंग देखें"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"सेटिंग की सूची देखें"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"संभावित खतरे का पता चला"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"खतरे का पता चला"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"खाते की सुरक्षा खतरे में हो सकती है"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"खाते की सुरक्षा खतरे में है"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{यहां चेतावनी देखें}one{यहां चेतावनी देखें}other{यहां चेतावनियां देखें}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"खाता की सुरक्षा खतरे में है"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{चेतावनी देखें}one{चेतावनी देखें}other{चेतावनियां देखें}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"पेज को खोला नहीं जा सका"</string>
<string name="resolving_action_error" msgid="371968886143262375">"चेतावनी में बताई गई समस्या को ठीक नहीं किया जा सका"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"सेटिंग को रीफ़्रेश नहीं किया जा सका"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{सेटिंग की जांच नहीं की जा सकी}one{सेटिंग की जांच नहीं की जा सकी}other{सेटिंग की जांच नहीं की जा सकी}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"वर्क प्रोफ़ाइल रोक दी गई है"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"कोई जानकारी मौजूद नहीं है"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-hr/strings.xml b/SafetyCenter/Resources/shared_res/values-hr/strings.xml
index 93f7cba6e..a644d6126 100644
--- a/SafetyCenter/Resources/shared_res/values-hr/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-hr/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Pregled"</string>
<string name="loading_summary" msgid="3740846439782713910">"Provjera postavki uređaja…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Izgleda dobro"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Problemi nisu pronađeni"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Dostupan je savjet}one{Dostupni su savjeti}few{Dostupni su savjeti}other{Dostupni su savjeti}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nije pronađena nijedna poteškoća"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Pogledajte preporuku}one{Pogledajte preporuke}few{Pogledajte preporuke}other{Pogledajte preporuke}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Poduzeta je radnja}one{Poduzete su radnje}few{Poduzete su radnje}other{Poduzete su radnje}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Pregledajte postavke"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Provjera popisa postavki"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Pronađeni su potencijalni rizici"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Pronađeni su rizici"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Račun je možda ugrožen"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Račun je ugrožen"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Pogledajte upozorenje u nastavku}one{Pogledajte upozorenja u nastavku}few{Pogledajte upozorenja u nastavku}other{Pogledajte upozorenja u nastavku}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Račun je ugrožen"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Pogledajte upozorenje}one{Pogledajte upozorenja}few{Pogledajte upozorenja}other{Pogledajte upozorenja}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Otvaranje stranice nije uspjelo"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Razrješavanje upozorenja nije uspjelo"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nije bilo moglo osvježiti postavke"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nije moguće provjeriti postavku}one{Nije moguće provjeriti postavke}few{Nije moguće provjeriti postavke}other{Nije moguće provjeriti postavke}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Poslovni profil je pauziran"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Još nema podataka"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-hu/strings.xml b/SafetyCenter/Resources/shared_res/values-hu/strings.xml
index 48f6d2d60..b8a8540ef 100644
--- a/SafetyCenter/Resources/shared_res/values-hu/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-hu/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Ellenőrzés…"</string>
<string name="loading_summary" msgid="3740846439782713910">"Eszközbeállítások ellenőrzése…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Jónak tűnik"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nem találtunk problémát"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Rendelkezésre áll egy tipp}other{Rendelkezésre állnak tippek}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nem találtunk problémát"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Javaslat megtekintése}other{Javaslatok megtekintése}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Végrehajtott intézkedés}other{Végrehajtott intézkedések}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Beállítások áttekintése"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Ellenőrizze a beállításlistát"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Lehetséges veszélyeket észleltünk"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Veszélyeket észleltünk"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Fiókja veszélyben lehet"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Fiókja veszélyben van"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Tekintse meg az alábbi értesítést}other{Tekintse meg az alábbi értesítéseket}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Veszélyeztetett fiók"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Értesítés megtekintése}other{Értesítések megtekintése}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Nem sikerült megnyitni az oldalt"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Nem sikerült feloldani a figyelmeztetést"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nem sikerült a beállítások frissítése"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nem sikerült a beállítás ellenőrzése}other{Nem sikerült a beállítások ellenőrzése}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"A munkaprofil használata szünetel"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Még nincsenek adatok"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-hy/strings.xml b/SafetyCenter/Resources/shared_res/values-hy/strings.xml
index 8f4344a63..e6b05056b 100644
--- a/SafetyCenter/Resources/shared_res/values-hy/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-hy/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Որոնում"</string>
<string name="loading_summary" msgid="3740846439782713910">"Սարքի կարգավորումները ստուգվում են…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Ամեն ինչ կարգին է"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Որևէ խնդիր չի հայտնաբերվել"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Հասանելի խորհուրդ}one{Հասանելի խորհուրդ}other{Հասանելի խորհուրդներ}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Խնդիր չի գտնվել"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Տեսնել առաջարկը}one{Տեսնել առաջարկները}other{Տեսնել առաջարկները}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Ձեռնարկված միջոց}one{Ձեռնարկված միջոց}other{Ձեռնարկված միջոցներ}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Ստուգեք կարգավորումները"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Ստուգեք կարգավորումների ցանկը"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Հնարավոր ռիսկեր են հայտնաբերվել"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Ռիսկեր են հայտնաբերվել"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Հաշիվը կարող է վտանգված լինել"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Հաշիվը վտանգված է"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Ստորև տեսեք զգուշացումը}one{Ստորև տեսեք զգուշացումը}other{Ստորև տեսեք զգուշացումները}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Վտանգված հաշիվ"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Տեսնել ծանուցումը}one{Տեսնել ծանուցումները}other{Տեսնել ծանուցումները}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Չհաջողվեց բացել էջը"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Չհաջողվեց լուծել ծանուցումը"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Չհաջողվեց թարմացնել կարգավորումները"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Չհաջողվեց ստուգել կարգավորումը}one{Չհաջողվեց ստուգել կարգավորումը}other{Չհաջողվեց ստուգել կարգավորումները}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Աշխատանքային պրոֆիլը դադարեցված է"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Տեղեկություններ դեռ չկան"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-in/strings.xml b/SafetyCenter/Resources/shared_res/values-in/strings.xml
index 811bedb11..8d25d7340 100644
--- a/SafetyCenter/Resources/shared_res/values-in/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-in/strings.xml
@@ -19,9 +19,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="scanning_title" msgid="5424849039854311398">"Memindai"</string>
<string name="loading_summary" msgid="3740846439782713910">"Memeriksa setelan perangkat…"</string>
- <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Semua beres"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Tidak ditemukan masalah"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Tips yang tersedia}other{Tips yang tersedia}}"</string>
+ <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Sepertinya semua aman"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Tidak ditemukan masalah"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Lihat rekomendasi}other{Lihat rekomendasi}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Tindakan yang dilakukan}other{Tindakan yang dilakukan}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Tinjau setelan"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Periksa daftar setelan"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potensi risiko ditemukan"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risiko ditemukan"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Akun mungkin berisiko"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Akun berisiko"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Lihat peringatan di bawah ini}other{Lihat peringatan di bawah ini}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Akun berisiko"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Lihat peringatan}other{Lihat peringatan}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Tidak dapat membuka halaman"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Tidak dapat menyelesaikan peringatan"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Tidak dapat merefresh setelan"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Tidak dapat memeriksa setelan}other{Tidak dapat memeriksa setelan}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Profil kerja dijeda"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Belum ada info"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-is/strings.xml b/SafetyCenter/Resources/shared_res/values-is/strings.xml
index 4fc822d62..faa4c2e1f 100644
--- a/SafetyCenter/Resources/shared_res/values-is/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-is/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Öryggisleit"</string>
<string name="loading_summary" msgid="3740846439782713910">"Athugar stillingar tækis…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Lítur vel út"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Engin vandamál fundust"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Ábending í boði}one{Ábendingar í boði}other{Ábendingar í boði}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Engin vandamál fundust"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Sjá ráðleggingu}one{Sjá ráðleggingar}other{Sjá ráðleggingar}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Aðgerð sem gripið var til}one{Aðgerðir sem gripið var til}other{Aðgerðir sem gripið var til}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Yfirfara stillingar"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Athuga lista yfir stillingar"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Hugsanleg hætta greindist"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Hætta greindist"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Reikningurinn er hugsanlega í hættu"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Reikningurinn er í hættu"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Sjá viðvörun hér að neðan}one{Sjá viðvaranir hér að neðan}other{Sjá viðvaranir hér að neðan}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Reikningur er í hættu"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Sjá viðvörun}one{Sjá viðvaranir}other{Sjá viðvaranir}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Ekki tókst að opna síðuna"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Ekki tókst að leysa úr viðvöruninni"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Ekki tókst að endurnýja stillingar"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Ekki tókst að athuga stillingu}one{Ekki tókst að athuga stillingar}other{Ekki tókst að athuga stillingar}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Hlé gert á vinnusniði"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Engar upplýsingar ennþá"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-it/strings.xml b/SafetyCenter/Resources/shared_res/values-it/strings.xml
index 049d13632..b2661e84a 100644
--- a/SafetyCenter/Resources/shared_res/values-it/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-it/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Analisi in corso…"</string>
<string name="loading_summary" msgid="3740846439782713910">"Controllo delle impostazioni del dispositivo in corso…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Tutto a posto"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nessun problema rilevato"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Suggerimento disponibile}many{Suggerimenti disponibili}other{Suggerimenti disponibili}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nessun problema rilevato"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Visualizza il consiglio}many{Visualizza i consigli}other{Visualizza i consigli}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Azione intrapresa}many{Azioni intraprese}other{Azioni intraprese}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Verifica le impostazioni"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Controlla l\'elenco di impostazioni"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potenziali rischi rilevati"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Rischi rilevati"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"L\'account potrebbe essere a rischio"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"L\'account è a rischio"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Visualizza l\'avviso qui sotto}many{Visualizza gli avvisi qui sotto}other{Visualizza gli avvisi qui sotto}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Account a rischio"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Visualizza l\'avviso}many{Visualizza gli avvisi}other{Visualizza gli avvisi}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Impossibile aprire la pagina"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Impossibile risolvere l\'avviso"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Impossibile aggiornare le impostazioni"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Impossibile controllare l\'impostazione}many{Impossibile controllare le impostazioni}other{Impossibile controllare le impostazioni}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Profilo di lavoro in pausa"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ancora nessuna informazione"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-iw/strings.xml b/SafetyCenter/Resources/shared_res/values-iw/strings.xml
index 1a3805f1b..8a0794632 100644
--- a/SafetyCenter/Resources/shared_res/values-iw/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-iw/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"מתבצעת סריקה"</string>
<string name="loading_summary" msgid="3740846439782713910">"הגדרות המכשיר נבדקות…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"נראה טוב"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"לא נמצאו בעיות"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{טיפ זמין}one{טיפים זמינים}two{טיפים זמינים}other{טיפים זמינים}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"לא נמצאו בעיות"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{הצגת ההמלצה}one{הצגת ההמלצות}two{הצגת ההמלצות}other{הצגת ההמלצות}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{פעולה בוצעה}one{פעולות בוצעו}two{פעולות בוצעו}other{פעולות בוצעו}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"בדיקת ההגדרות"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"בדיקה של רשימת ההגדרות"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"נמצאו סכנות אפשריות"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"נמצאו סיכונים"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"החשבון עלול להיות בסיכון"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"החשבון בסיכון"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{הצגת ההתראה בהמשך}one{הצגת ההתראות בהמשך}two{הצגת ההתראות בהמשך}other{הצגת ההתראות בהמשך}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"החשבון בסיכון"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{הצגת ההתראה}one{הצגת ההתראות}two{הצגת ההתראות}other{הצגת ההתראות}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"לא ניתן היה לפתוח את הדף"</string>
<string name="resolving_action_error" msgid="371968886143262375">"לא ניתן היה לפתור את הבעיה בהתראה"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"לא ניתן היה לרענן את ההגדרות"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{לא ניתן היה לבדוק את ההגדרה}one{לא ניתן היה לבדוק את ההגדרות}two{לא ניתן היה לבדוק את ההגדרות}other{לא ניתן היה לבדוק את ההגדרות}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"פרופיל העבודה מושהה"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"אין עדיין פרטים"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ja/strings.xml b/SafetyCenter/Resources/shared_res/values-ja/strings.xml
index 9b3a9e708..c6d76eb2c 100644
--- a/SafetyCenter/Resources/shared_res/values-ja/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ja/strings.xml
@@ -20,13 +20,13 @@
<string name="scanning_title" msgid="5424849039854311398">"スキャン"</string>
<string name="loading_summary" msgid="3740846439782713910">"デバイスの設定を確認しています…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"問題はありません"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"問題は見つかりませんでした"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{ヒントをご覧いただけます}other{ヒントをご覧いただけます}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"問題は検出されませんでした"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{おすすめを見る}other{おすすめを見る}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{対処しました}other{対処しました}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"設定の確認"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"設定リストをご確認ください"</string>
- <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"デバイスが危険な可能性があります"</string>
- <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"デバイスが危険です"</string>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"デバイスが危険にさらされています"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"デバイスが危険な状態です"</string>
<string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"データが危険な可能性があります"</string>
<string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"データが危険です"</string>
<string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"古いパスワードの不正使用"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"危険にさらされています"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"潜在的なリスクが検出されました"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"リスクが検出されました"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"アカウントが危険な可能性があります"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"アカウントが危険です"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{下記のアラートをご確認ください}other{下記のアラートをご確認ください}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"アカウントが危険にさらされています"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"アカウントが危険です"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{アラートを確認してください}other{アラートを確認してください}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"ページを開けませんでした"</string>
<string name="resolving_action_error" msgid="371968886143262375">"アラートを解決できませんでした"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"設定を更新できませんでした"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{設定を確認できませんでした}other{設定を確認できませんでした}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"仕事用プロファイルが一時停止しています"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"まだ情報がありません"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ka/strings.xml b/SafetyCenter/Resources/shared_res/values-ka/strings.xml
index 7439de354..de8890dec 100644
--- a/SafetyCenter/Resources/shared_res/values-ka/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ka/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"სკანირება"</string>
<string name="loading_summary" msgid="3740846439782713910">"მოწმდება მოწყობილობის პარამეტრები…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ყველაფერი რიგზეა"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"პრობლემები არ მოიძებნა"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{მინიშნება ხელმისაწვდომია}other{მინიშნებები ხელმისაწვდომია}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"პრობლემები ვერ მოიძებნა"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{რეკომენდაციის ნახვა}other{რეკომენდაციების ნახვა}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{მიღებული ქმედება}other{მიღებული ქმედებები}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"პარამეტრების გადახედვა"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"პარამეტრების სიის შემოწმება"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"ნაპოვნია პოტენციური რისკები"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"აღმოჩენილი რისკები"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ანგარიშს შესაძლოა საფრთხე ემუქრება"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"ანგარიშს საფრთხე ემუქრება"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{იხილეთ გაფრთხილება ქვემოთ}other{იხილეთ გაფრთხილებები ქვემოთ}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"საფრთხის ქვეშ მყოფი ანგარიში"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{გაფრთხილების ნახვა}other{გაფრთხილებების ნახვა}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"გვერდის გახსნა ვერ მოხერხდა"</string>
<string name="resolving_action_error" msgid="371968886143262375">"გაფრთხილება ვერ გადაიჭრა"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"პარამეტრები ვერ განახლდა"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{პარამეტრის შემოწმება ვერ მოხერხდა}other{პარამეტრების Შემოწმება ვერ მოხერხდა}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"სამსახურის პროფილი დაპაუზებულია"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ინფო ჯერ არ არის"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-kk/strings.xml b/SafetyCenter/Resources/shared_res/values-kk/strings.xml
index c3420713b..9226d4fcb 100644
--- a/SafetyCenter/Resources/shared_res/values-kk/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-kk/strings.xml
@@ -20,11 +20,11 @@
<string name="scanning_title" msgid="5424849039854311398">"Тексеріліп жатыр"</string>
<string name="loading_summary" msgid="3740846439782713910">"Құрылғы параметрлері тексеріліп жатыр…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Бәрі дұрыс"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Ешқандай мәселе табылмады."</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Кеңес бар.}other{Кеңестер бар.}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Ешқандай мәселе табылмады."</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Ұсынысты көру}other{Ұсыныстарды көру}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Әрекет жасалды.}other{Әрекеттер жасалды.}}"</string>
- <string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Параметрлерді қарап шығу"</string>
- <string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Параметрлер тізімін тексеру"</string>
+ <string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Параметрлерді тексерy"</string>
+ <string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Параметрлер тізімін тексеріңіз."</string>
<string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Құрылғыға қауіп төнген болуы мүмкін"</string>
<string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Құрылғыға қауіп төніп тұр"</string>
<string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Деректерге қауіп төнген сияқты"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Қауіп төну мүмкіндігі бар"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Қауіп төніп тұрғаны белгілі болды"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Аккаунтқа қауіп төнген сияқты"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Аккаунтқа қауіп төніп тұр"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Төмендегі хабарландыруды көріңіз.}other{Төмендегі хабарландыруларды көріңіз.}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Аккаунтқа қауіп төніп тұр"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Хабарландыруды көру}other{Хабарландыруларды көру}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Бет ашылмады."</string>
<string name="resolving_action_error" msgid="371968886143262375">"Хабарландыруда көрсетілген мәселе шешілмеді."</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Параметрлер жаңартылмады."</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Параметрді тексеру мүмкін болмады.}other{Параметрлерді тексеру мүмкін болмады.}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Жұмыс профилі кідіртілді."</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Әзірге мәлімет жоқ."</string>
diff --git a/SafetyCenter/Resources/shared_res/values-km/strings.xml b/SafetyCenter/Resources/shared_res/values-km/strings.xml
index 6f0deb271..e1af9019d 100644
--- a/SafetyCenter/Resources/shared_res/values-km/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-km/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"កំពុងស្កេន"</string>
<string name="loading_summary" msgid="3740846439782713910">"កំពុងពិនិត្យមើលការកំណត់ឧបករណ៍…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"គ្មានបញ្ហា​អ្វីទេ"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"រក​មិន​ឃើញ​បញ្ហា​ទេ"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{មានគន្លឹះ}other{មានគន្លឹះ}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"រកមិន​ឃើញ​បញ្ហាទេ"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{មើលការណែនាំ}other{មើល​ការណែនាំ}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{សកម្មភាពដែលបានធ្វើឡើង}other{សកម្មភាពដែលបានធ្វើឡើង}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ពិនិត្យមើល​ការកំណត់"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ពិនិត្យបញ្ជីការកំណត់"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"រកឃើញហានិភ័យដែលអាចមាន"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"រកឃើញហានិភ័យ"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"គណនីអាចប្រឈមនឹងហានិភ័យ"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"គណនីប្រឈមនឹងហានិភ័យ"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{មើលការជូន​ដំណឹងខាងក្រោម}other{មើលការជូន​ដំណឹងខាងក្រោម}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"គណនីប្រឈមនឹងហានិភ័យ"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{មើលការជូន​ដំណឹង}other{មើលការជូនដំណឹង}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"មិនអាច​បើកទំព័រ​បានទេ"</string>
<string name="resolving_action_error" msgid="371968886143262375">"មិនអាច​ដោះស្រាយការជូនដំណឹងនេះ​បានទេ"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"មិនអាចផ្ទុកការកំណត់ឡើងវិញបានទេ"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{មិន​អាច​ពិនិត្យ​មើល​ការកំណត់​បាន​ទេ}other{មិន​អាច​ពិនិត្យ​មើល​ការកំណត់​បាន​ទេ}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"កម្រងព័ត៌មានការងារត្រូវបាន​ផ្អាក"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"មិន​ទាន់​មាន​ព័ត៌មាន​នៅ​ឡើយ​ទេ"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-kn/strings.xml b/SafetyCenter/Resources/shared_res/values-kn/strings.xml
index 6c6272759..46eedaac5 100644
--- a/SafetyCenter/Resources/shared_res/values-kn/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-kn/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="loading_summary" msgid="3740846439782713910">"ಸಾಧನ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ಸರಿಯಾಗಿದೆ"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"ಯಾವುದೇ ಸಮಸ್ಯೆಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{ಸಲಹೆ ಲಭ್ಯವಿದೆ}one{ಸಲಹೆಗಳು ಲಭ್ಯವಿವೆ}other{ಸಲಹೆಗಳು ಲಭ್ಯವಿವೆ}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"ಯಾವುದೇ ಸಮಸ್ಯೆಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{ಶಿಫಾರಸನ್ನು ನೋಡಿ}one{ಶಿಫಾರಸುಗಳನ್ನು ನೋಡಿ}other{ಶಿಫಾರಸುಗಳನ್ನು ನೋಡಿ}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{ಕ್ರಮ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ}one{ಕ್ರಮಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ}other{ಕ್ರಮಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಪಟ್ಟಿಯನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"ನೀವು ಅಪಾಯದಲ್ಲಿದ್ದೀರಿ"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"ಸಂಭವನೀಯ ಅಪಾಯಗಳು ಕಂಡುಬಂದಿವೆ"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"ಅಪಾಯಗಳು ಕಂಡುಬಂದಿವೆ"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ಖಾತೆಯು ಅಪಾಯಕ್ಕೀಡಾಗಬಹುದು"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"ಖಾತೆ ಅಪಾಯದಲ್ಲಿದೆ"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{ಕೆಳಗಿನ ಎಚ್ಚರಿಕೆಯನ್ನು ನೋಡಿ}one{ಕೆಳಗಿನ ಎಚ್ಚರಿಕೆಗಳನ್ನು ನೋಡಿ}other{ಕೆಳಗಿನ ಎಚ್ಚರಿಕೆಗಳನ್ನು ನೋಡಿ}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ಖಾತೆಯು ಅಪಾಯದಲ್ಲಿರಬಹುದು"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"ಖಾತೆಯು ಅಪಾಯದಲ್ಲಿದೆ"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{ಎಚ್ಚರಿಕೆಯನ್ನು ನೋಡಿ}one{ಎಚ್ಚರಿಕೆಗಳನ್ನು ನೋಡಿ}other{ಎಚ್ಚರಿಕೆಗಳನ್ನು ನೋಡಿ}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"ಪುಟವನ್ನು ತೆರೆಯಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="resolving_action_error" msgid="371968886143262375">"ಅಲರ್ಟ್ ಅನ್ನು ಬಗೆಹರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ರಿಫ್ರೆಶ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ಪರಿಶೀಲಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ}one{ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ}other{ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ಇನ್ನೂ ಯಾವುದೇ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲ"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ko/strings.xml b/SafetyCenter/Resources/shared_res/values-ko/strings.xml
index e92299496..1a5938c9a 100644
--- a/SafetyCenter/Resources/shared_res/values-ko/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ko/strings.xml
@@ -20,13 +20,13 @@
<string name="scanning_title" msgid="5424849039854311398">"검사 중"</string>
<string name="loading_summary" msgid="3740846439782713910">"기기 설정을 확인하는 중…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"양호"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"문제가 발견되지 않음"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{사용 가능한 팁}other{사용 가능한 팁}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"발견된 문제 없음"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{권장사항 보기}other{권장사항 보기}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{조치를 취함}other{조치를 취함}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"설정 검토"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"설정 목록 확인"</string>
<string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"기기에 잠재적 위험 발생"</string>
- <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"기기 위험 발생"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"기기에 위험 발생"</string>
<string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"데이터에 보안 위험이 있을 수 있음"</string>
<string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"데이터에 보안 위험이 있음"</string>
<string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"기존 비밀번호 손상됨"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"위험에 노출됨"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"잠재적 위험 발견됨"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"위험 발견됨"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"계정에 보안 위험이 있을 수 있음"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"계정에 보안 위험이 있음"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{아래 알림 참고}other{아래 알림 참고}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"계정이 잠재적 위험에 노출됨"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"계정이 위험에 노출됨"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{알림 보기}other{알림 보기}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"페이지를 열 수 없습니다."</string>
<string name="resolving_action_error" msgid="371968886143262375">"알림을 해결할 수 없습니다."</string>
- <string name="refresh_timeout" msgid="251734999692581852">"설정을 새로고침할 수 없습니다."</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{설정을 확인할 수 없습니다.}other{설정을 확인할 수 없습니다.}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"직장 프로필이 일시중지됨"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"아직 정보 없음"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ky/strings.xml b/SafetyCenter/Resources/shared_res/values-ky/strings.xml
index 6f39c7b06..474377b87 100644
--- a/SafetyCenter/Resources/shared_res/values-ky/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ky/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Текшерилүүдө"</string>
<string name="loading_summary" msgid="3740846439782713910">"Түзмөктүн параметрлери текшерилүүдө…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Жакшы эле окшойт"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Баары жайында!"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Кеңеш бар}other{Кеңештер бар}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Маселелер жок"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Сунушту көрүү}other{Сунуштарды көрүү}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Аткарылган аракет}other{Аткарылган аракеттер}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Параметрлерди карап чыгуу"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Параметрлердин тизмесин текшерүү"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Мүмкүн болгон коркунучтар табылды"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Коркунучтар табылды"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Аккаунт коркунучта болушу мүмкүн"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Аккаунттун коопсуздугу коркунучта"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Төмөнкү эскертүүнү көрүү}other{Төмөнкү эскертүүлөрдү көрүү}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Аккаунт коркунучта"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Эскетүүнү көрүү}other{Эскертүүлөрдү көрүү}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Барак ачылган жок"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Эскертүү чечилген жок"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Параметрлер жаңыртылган жок"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Параметр текшерилген жок}other{Параметрлер текшерилген жок}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Жумуш профили тындырылды"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Азырынча маалымат жок"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-lo/strings.xml b/SafetyCenter/Resources/shared_res/values-lo/strings.xml
index 3da550e9a..0abf76b30 100644
--- a/SafetyCenter/Resources/shared_res/values-lo/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-lo/strings.xml
@@ -19,9 +19,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="scanning_title" msgid="5424849039854311398">"ການສະແກນ"</string>
<string name="loading_summary" msgid="3740846439782713910">"ກໍາລັງກວດການຕັ້ງຄ່າອຸປະກອນ…"</string>
- <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ເບິ່ງໃຊ້ໄດ້"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"ບໍ່ພົບບັນຫາໃດໆ"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{ເຄັດລັບທີ່ພ້ອມໃຫ້ນຳໃຊ້}other{ເຄັດລັບທີ່ພ້ອມໃຫ້ນຳໃຊ້}}"</string>
+ <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ດີແລ້ວ"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"ບໍ່ພົບບັນຫາ"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{ເບິ່ງຄຳແນະນຳ}other{ເບິ່ງຄຳແນະນຳ}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{ດຳເນີນການແລ້ວ}other{ດຳເນີນການແລ້ວ}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ກວດເບິ່ງການຕັ້ງຄ່າ"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ກວດລາຍການການຕັ້ງຄ່າ"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"ພົບຄວາມສ່ຽງທີ່ອາດເກີດຂຶ້ນ"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"ພົບຄວາມສ່ຽງ"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ບັນຊີອາດຕົກຢູ່ໃນຄວາມສ່ຽງ"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"ບັນຊີຕົກຢູ່ໃນຄວາມສ່ຽງ"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{ເບິ່ງການແຈ້ງເຕືອນລຸ່ມນີ້}other{ເບິ່ງການແຈ້ງເຕືອນລຸ່ມນີ້}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"ບັນຊີຕົກຢູ່ໃນຄວາມສ່ຽງ"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{ເບິ່ງແຈ້ງເຕືອນ}other{ເບິ່ງແຈ້ງເຕືອນ}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"ບໍ່ສາມາດເປີດໜ້າໄດ້"</string>
<string name="resolving_action_error" msgid="371968886143262375">"ບໍ່ສາມາດແກ້ໄຂແຈ້ງເຕືອນໄດ້"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ບໍ່ສາມາດໂຫຼດການຕັ້ງຄ່າຄືນໃໝ່"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ກວດສອບການຕັ້ງຄ່າບໍ່ໄດ້}other{ກວດສອບການຕັ້ງຄ່າບໍ່ໄດ້}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"ຢຸດໂປຣໄຟລ໌ວຽກໄວ້ຊົ່ວຄາວແລ້ວ"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ບໍ່ມີຂໍ້ມູນເທື່ອ"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-lt/strings.xml b/SafetyCenter/Resources/shared_res/values-lt/strings.xml
index bdfe7600d..832ef32f1 100644
--- a/SafetyCenter/Resources/shared_res/values-lt/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-lt/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Nuskaitoma"</string>
<string name="loading_summary" msgid="3740846439782713910">"Tikrinami įrenginio nustatymai…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Viskas gerai"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nerasta jokių problemų"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Yra patarimas}one{Yra patarimų}few{Yra patarimų}many{Yra patarimų}other{Yra patarimų}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Problemų neaptikta"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Žr. rekomendaciją}one{Žr. rekomendacijas}few{Žr. rekomendacijas}many{Žr. rekomendacijas}other{Žr. rekomendacijas}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Veiksmas atliktas}one{Veiksmai atlikti}few{Veiksmai atlikti}many{Veiksmai atlikti}other{Veiksmai atlikti}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Žr. nustatymus"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Tikrinti nustatymų sąrašą"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Aptikta potencialių pavojų"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Aptikta pavojų"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Paskyrai galėjo kilti pavojus"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Paskyrai kilo pavojus"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Žr. toliau pateiktą įspėjimą}one{Žr. toliau pateiktus įspėjimus}few{Žr. toliau pateiktus įspėjimus}many{Žr. toliau pateiktus įspėjimus}other{Žr. toliau pateiktus įspėjimus}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Paskyrai iškilo pavojus"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Žr. įspėjimą}one{Žr. įspėjimus}few{Žr. įspėjimus}many{Žr. įspėjimus}other{Žr. įspėjimus}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Nepavyko atidaryti puslapio"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Nepavyko pašalinti įspėjimo"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nepavyko atnaujinti nustatymų"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nepavyko patikrinti nustatymo}one{Nepavyko patikrinti nustatymų}few{Nepavyko patikrinti nustatymų}many{Nepavyko patikrinti nustatymų}other{Nepavyko patikrinti nustatymų}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Darbo profilis pristabdytas"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Kol kas informacijos nėra"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-lv/strings.xml b/SafetyCenter/Resources/shared_res/values-lv/strings.xml
index 3563a1b22..eb544b15f 100644
--- a/SafetyCenter/Resources/shared_res/values-lv/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-lv/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Notiek pārbaude"</string>
<string name="loading_summary" msgid="3740846439782713910">"Notiek ierīces iestatījumu pārbaude…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Viss kārtībā"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Netika atrasta neviena problēma"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Pieejams padoms}zero{Pieejami padomi}one{Pieejami padomi}other{Pieejami padomi}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Problēmas netika atrastas"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Skatiet ieteikumu}zero{Skatiet ieteikumus}one{Skatiet ieteikumus}other{Skatiet ieteikumus}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Veikta darbība}zero{Veiktas darbības}one{Veiktas darbības}other{Veiktas darbības}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Pārskatiet iestatījumus"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Pārbaudiet iestatījumu sarakstu"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Konstatēts iespējams risks"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Konstatēts risks"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Konts var būt apdraudēts"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Konts ir apdraudēts"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Skatiet tālāk norādīto brīdinājumu}zero{Skatiet tālāk norādītos brīdinājumus}one{Skatiet tālāk norādītos brīdinājumus}other{Skatiet tālāk norādītos brīdinājumus}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Konts ir apdraudēts"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Skatiet brīdinājumu}zero{Skatiet brīdinājumus}one{Skatiet brīdinājumus}other{Skatiet brīdinājumus}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Nevarēja atvērt lapu"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Nevarēja atrisināt ieteikumu vai brīdinājumu"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nevarēja atsvaidzināt iestatījumus"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nevarēja pārbaudīt iestatījumu.}zero{Nevarēja pārbaudīt iestatījumus.}one{Nevarēja pārbaudīt iestatījumus.}other{Nevarēja pārbaudīt iestatījumus.}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Darba profila darbība ir apturēta"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Vēl nav informācijas"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-mk/strings.xml b/SafetyCenter/Resources/shared_res/values-mk/strings.xml
index 9bced888c..30b405c67 100644
--- a/SafetyCenter/Resources/shared_res/values-mk/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-mk/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Скенирање"</string>
<string name="loading_summary" msgid="3740846439782713910">"Се проверуваат поставките за уредот…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Изгледа добро"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Не се најдени проблеми"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Достапен е совет}one{Достапни се совети}other{Достапни се совети}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Не се најдени проблеми"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Видете ја препораката}one{Видете ги препораките}other{Видете ги препораките}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Преземено дејство}one{Преземени дејства}other{Преземени дејства}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Прегледајте ги поставките"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Проверете го списокот со поставки"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Под ризик сте"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Најдени се потенцијални ризици"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Најдени се ризици"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Сметката можеби е под ризик"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Сметката е под ризик"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Видете го предупредувањето подолу}one{Видете ги предупредувањата подолу}other{Видете ги предупредувањата подолу}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Сметката можеби е изложена на ризик"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Сметката е изложена на ризик"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Видете го предупредувањето}one{Видете ги предупредувањата}other{Видете ги предупредувањата}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Не можеше да се отвори страницата"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Не можеше да се реши предупредувањето"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Не можеше да се освежат поставките"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Не може да се провери поставката}one{Не може да се проверат поставките}other{Не може да се проверат поставките}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Работниот профил е паузиран"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Сѐ уште нема податоци"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ml/strings.xml b/SafetyCenter/Resources/shared_res/values-ml/strings.xml
index 6e666ec16..4a77469da 100644
--- a/SafetyCenter/Resources/shared_res/values-ml/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ml/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"സ്‌കാൻ ചെയ്യുന്നു"</string>
<string name="loading_summary" msgid="3740846439782713910">"ഉപകരണ ക്രമീകരണം പരിശോധിക്കുന്നു…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"കൊള്ളാം"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"പ്രശ്‌നങ്ങളൊന്നും കണ്ടെത്തിയില്ല"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{നുറുങ്ങ് ലഭ്യമാണ്}other{നുറുങ്ങുകൾ ലഭ്യമാണ്}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"പ്രശ്‌നങ്ങളൊന്നും കണ്ടെത്തിയില്ല"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{നിർദ്ദേശം കാണുക}other{നിർദ്ദേശങ്ങൾ കാണുക}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{എടുത്ത നടപടി}other{എടുത്ത നടപടികൾ}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ക്രമീകരണം അവലോകനം ചെയ്യുക"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ക്രമീകരണ ലിസ്റ്റ് പരിശോധിക്കുക"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"സാധ്യതയുള്ള അപകടസാധ്യതകൾ കണ്ടെത്തി"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"അപകടസാധ്യതകൾ കണ്ടെത്തി"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"അക്കൗണ്ട് അപകടത്തിലായേക്കാം"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"അക്കൗണ്ട് അപകടത്തിലാണ്"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{താഴെയുള്ള മുന്നറിയിപ്പ് കാണുക}other{താഴെയുള്ള മുന്നറിയിപ്പുകൾ കാണുക}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"അക്കൗണ്ട് അപകടത്തിലാണ്"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{മുന്നറിയിപ്പ് കാണുക}other{മുന്നറിയിപ്പുകൾ കാണുക}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"പേജ് തുറക്കാനായില്ല"</string>
<string name="resolving_action_error" msgid="371968886143262375">"മുന്നറിയിപ്പ് പരിഹരിക്കാനായില്ല"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ക്രമീകരണം റീഫ്രഷ് ചെയ്യാനായില്ല"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ക്രമീകരണം പരിശോധിക്കാനായില്ല}other{ക്രമീകരണം പരിശോധിക്കാനായില്ല}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"ഔദ്യോഗിക പ്രൊഫൈൽ തൽക്കാലം നിർത്തിയിരിക്കുന്നു"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ഇതുവരെ വിവരങ്ങളൊന്നുമില്ല"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-mn/strings.xml b/SafetyCenter/Resources/shared_res/values-mn/strings.xml
index 76be45d32..88f75f648 100644
--- a/SafetyCenter/Resources/shared_res/values-mn/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-mn/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Скан хийж байна"</string>
<string name="loading_summary" msgid="3740846439782713910">"Төхөөрөмжийн тохиргоог шалгаж байна…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Сайн байна"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Асуудал олдсонгүй"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Зөвлөгөө боломжтой}other{Зөвлөгөөнүүд боломжтой}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Ямар ч асуудал олдсонгүй"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Зөвлөмжийг харах}other{Зөвлөмжүүдийг харах}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Арга хэмжээ авсан}other{Арга хэмжээнүүд авсан}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Тохиргоог шалгах"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Тохиргооны жагсаалтыг шалгах"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Боломжит эрсдэл илэрсэн"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Эрсдэл илэрсэн"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Бүртгэл эрсдэлд байж магадгүй"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Бүртгэл эрсдэлд байна"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Доорх сэрэмжлүүлгийг харна уу}other{Доорх сэрэмжлүүлгүүдийг харна уу}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Бүртгэл эрсдэлд байна"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Сэрэмжлүүлгийг харах}other{Сэрэмжлүүлгүүдийг харах}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Хуудсыг нээж чадсангүй"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Сэрэмжлүүлгийг шийдвэрлэж чадсангүй"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Тохиргоог сэргээж чадсангүй"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Тохиргоог шалгаж чадсангүй}other{Тохиргоог шалгаж чадсангүй}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Ажлын профайлыг түр зогсоосон"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Мэдээлэл хараахан алга"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-mr/strings.xml b/SafetyCenter/Resources/shared_res/values-mr/strings.xml
index ec145d0f4..0b47053cd 100644
--- a/SafetyCenter/Resources/shared_res/values-mr/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-mr/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"स्कॅन करत आहे"</string>
<string name="loading_summary" msgid="3740846439782713910">"डिव्हाइस सेटिंग्ज तपासत आहे…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"चांगले दिसते आहे"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"कोणत्‍याही समस्‍या आढळल्‍या नाहीत"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{टीप उपलब्ध}other{टीपा उपलब्ध}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"कोणत्याही समस्या आढळल्या नाहीत"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{शिफारस पहा}other{शिफारशी पहा}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{कृती केली}other{कृती केल्या}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"सेटिंग्जचे पुनरावलोकन करा"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"सेटिंग्जची सूची तपासा"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"संभाव्य धोके आढळले"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"धोके आढळले"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"खाते धोक्यात असू शकते"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"खाते धोक्यात आहे"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{सूचना खाली पहा}other{सूचना खाली पहा}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"खाते धोक्यात आहे"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{सूचना पहा}other{सूचना पहा}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"पेज उघडता आले नाही"</string>
<string name="resolving_action_error" msgid="371968886143262375">"इशाऱ्याचे निराकरण करता आले नाही"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"सेटिंग्ज रिफ्रेश करता आली नाही"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{सेटिंग तपासता आले नाही}other{सेटिंग्ज तपासता आली नाहीत}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"कार्य प्रोफाइल थांबवली आहे"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"अद्याप कोणतीही माहिती नाही"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ms/strings.xml b/SafetyCenter/Resources/shared_res/values-ms/strings.xml
index 4af3570d8..f8c3e2c32 100644
--- a/SafetyCenter/Resources/shared_res/values-ms/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ms/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Mengimbas"</string>
<string name="loading_summary" msgid="3740846439782713910">"Menyemak tetapan peranti…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Semuanya baik"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Tiada masalah ditemukan"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Petua tersedia}other{Petua tersedia}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Tiada isu ditemukan"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Lihat syor}other{Lihat syor}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Tindakan diambil}other{Tindakan diambil}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Semak tetapan"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Semak senarai tetapan"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Risiko berpotensi ditemukan"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risiko ditemukan"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Akaun mungkin berisiko"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Akaun berisiko"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Lihat makluman di bawah}other{Lihat makluman di bawah}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Akaun berisiko"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Lihat makluman}other{Lihat makluman}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Tidak dapat membuka halaman"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Tidak dapat menyelesaikan amaran"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Tidak dapat menyegar semula tetapan"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Tidak dapat menyemak tetapan}other{Tidak dapat menyemak tetapan}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Profil kerja dijeda"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Belum ada maklumat lagi"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-my/strings.xml b/SafetyCenter/Resources/shared_res/values-my/strings.xml
index 1169ab0c2..76e53c8dc 100644
--- a/SafetyCenter/Resources/shared_res/values-my/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-my/strings.xml
@@ -20,13 +20,13 @@
<string name="scanning_title" msgid="5424849039854311398">"စကင်ဖတ်ခြင်း"</string>
<string name="loading_summary" msgid="3740846439782713910">"စက်၏ဆက်တင်များကို စစ်ဆေးနေသည်…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"အဆင်ပြေပါသည်"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"ပြဿနာမတွေ့ပါ"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{အကြံပြုချက် ရှိသည်}other{အကြံပြုချက်များ ရှိသည်}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"ပြဿနာ မတွေ့ပါ"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{အကြံပြုချက် ကြည့်ရန်}other{အကြံပြုချက်များ ကြည့်ရန်}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{လုပ်ဆောင်မှု ရှိသည်}other{လုပ်ဆောင်မှုများ ရှိသည်}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ဆက်တင်များကို စိစစ်ပါ"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ဆက်တင်များစာရင်းကို စစ်ဆေးပါ"</string>
- <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"စက်တွင် အန္တရာယ်ရှိနိုင်သည်"</string>
- <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"စက်တွင် အန္တရာယ်ရှိနေသည်"</string>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"စက်အတွက် အန္တရာယ်ရှိနိုင်သည်"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"စက်အတွက် အန္တရာယ်ရှိနေသည်"</string>
<string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"သင့်ဒေတာတွင် အန္တရာယ်ရှိနိုင်သည်"</string>
<string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"သင့်ဒေတာတွင် အန္တရာယ်ရှိသည်"</string>
<string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"စကားဝှက် ကျိုးပေါက်နေသည် (အဟောင်း)"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"သင့်တွင် အန္တရာယ်ရှိနေသည်"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"အန္တရာယ်ဖြစ်နိုင်ခြေ တွေ့သည်"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"အန္တရာယ် တွေ့ထားသည်"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"အကောင့်တွင် အန္တရာယ်ရှိနိုင်သည်"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"အကောင့်တွင် အန္တရာယ်ရှိသည်"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{အောက်ပါ သတိပေးချက်ကို ကြည့်ပါ}other{အောက်ပါ သတိပေးချက်များကို ကြည့်ပါ}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"အကောင့်အတွက် အန္တရာယ်ရှိနိုင်သည်"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"အကောင့်အတွက် အန္တရာယ်ရှိသည်"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{သတိပေးချက် ကြည့်ရန်}other{သတိပေးချက်များ ကြည့်ရန်}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"စာမျက်နှာကို ဖွင့်၍မရပါ"</string>
<string name="resolving_action_error" msgid="371968886143262375">"သတိပေးချက်ကို ဖြေရှင်း၍မရပါ"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ဆက်တင်များကို ပြန်လည် စတင်၍မရပါ"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ဆက်တင်ကြည့်၍မရပါ}other{ဆက်တင်များ ကြည့်၍မရပါ}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"အလုပ်ပရိုဖိုင် ခဏရပ်ထားသည်"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"အချက်အလက် မရှိသေးပါ"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-nb/strings.xml b/SafetyCenter/Resources/shared_res/values-nb/strings.xml
index 02da7c32c..61338a390 100644
--- a/SafetyCenter/Resources/shared_res/values-nb/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-nb/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Skanner"</string>
<string name="loading_summary" msgid="3740846439782713910">"Sjekker enhetsinnstillingene …"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Dette ser bra ut"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Fant ingen problemer"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Et tips er tilgjengelig}other{Noen tips er tilgjengelige}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Fant ingen problemer"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Se anbefalingen}other{Se anbefalingene}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Handlingen er iverksatt}other{Handlingene er iverksatt}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Gå gjennom innstillingene"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Sjekk innstillingslisten"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potensielle risikoer er registrert"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risikoer er registrert"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Kontoen kan være i faresonen"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Kontoen er i faresonen"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Se varselet nedenfor}other{Se varslene nedenfor}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Kontoen er i faresonen"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Se varselet}other{Se varslene}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Kunne ikke åpne siden"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Kunne ikke løse varselet"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Kunne ikke laste inn innstillingene på nytt"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Kunne ikke sjekke innstillingen}other{Kunne ikke sjekke innstillingene}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Jobbprofilen er satt på pause"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ingen informasjon ennå"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ne/strings.xml b/SafetyCenter/Resources/shared_res/values-ne/strings.xml
index 7358af100..e7c392a3b 100644
--- a/SafetyCenter/Resources/shared_res/values-ne/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ne/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"स्क्यान गरिँदै छ"</string>
<string name="loading_summary" msgid="3740846439782713910">"डिभाइसका सेटिङ जाँचिदै छ…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"सबै कुरा ठिकै देखिन्छ"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"कुनै पनि समस्या भेटिएन"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{सुझाव उपलब्ध छ}other{सुझावहरू उपलब्ध छन्}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"कुनै पनि समस्या भेटिएन"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{सिफारिस हेर्नुहोस्}other{सिफारिसहरू हेर्नुहोस्}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{कारबाही गरिएको छ}other{कारबाहीहरू गरिएका छन्}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"सेटिङको समीक्षा गर्नुहोस्"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"सेटिङको सूची जाँच्नुहोस्"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"सम्भावित जोखिम फेला परे"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"जोखिम फेला परे"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"खाता जोखिममा हुन सक्छ"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"खाता जोखिममा छ"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{तल दिइएको अलर्ट हेर्नुहोस्}other{तल दिइएका अलर्टहरू हेर्नुहोस्}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"खाता जोखिममा छ"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{अलर्ट हेर्नुहोस्}other{अलर्टहरू हेर्नुहोस्}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"पेज खोल्न सकिएन"</string>
<string name="resolving_action_error" msgid="371968886143262375">"अलर्ट समाधान गर्न सकिएन"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"सेटिङ रिफ्रेस गर्न सकिएन"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{सेटिङ जाँच गर्न सकिएन}other{सेटिङहरू जाँच गर्न सकिएन}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"कार्य प्रोफाइल पज गरिएको छ"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"कुनै जानकारी उपलब्ध छैन"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-nl/strings.xml b/SafetyCenter/Resources/shared_res/values-nl/strings.xml
index fbde4bf79..ab8edda5d 100644
--- a/SafetyCenter/Resources/shared_res/values-nl/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-nl/strings.xml
@@ -18,10 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="scanning_title" msgid="5424849039854311398">"Scannen"</string>
- <string name="loading_summary" msgid="3740846439782713910">"Apparaat-instellingen&amp;#173checken…"</string>
+ <string name="loading_summary" msgid="3740846439782713910">"Apparaat­instellingen­ checken…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Dat ziet er goed uit"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Geen problemen gevonden"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Beschikbare tip}other{Beschikbare tips}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Geen problemen gevonden"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Aanbeveling bekijken}other{Aanbevelingen bekijken}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Ondernomen actie}other{Ondernomen acties}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Instellingen checken"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Check de lijst met instellingen"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potentiële risico\'s gevonden"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risico\'s gevonden"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Account loopt misschien gevaar"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Account loopt risico"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Zie onderstaande melding}other{Zie onderstaande meldingen}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Account loopt gevaar"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Melding bekijken}other{Meldingen bekijken}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Kan de pagina niet openen"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Kan melding niet oplossen"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Kan instellingen niet vernieuwen"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Kan instelling niet checken}other{Kan instellingen niet checken}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Werkprofiel is onderbroken"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Nog geen informatie"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-or/strings.xml b/SafetyCenter/Resources/shared_res/values-or/strings.xml
index 5760e83a3..341149120 100644
--- a/SafetyCenter/Resources/shared_res/values-or/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-or/strings.xml
@@ -19,9 +19,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="scanning_title" msgid="5424849039854311398">"ସ୍କାନ କରାଯାଉଛି"</string>
<string name="loading_summary" msgid="3740846439782713910">"ଡିଭାଇସ ସେଟିଂସ ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
- <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ଠିକ୍ ଥିବା ପରି ଜଣାପଡ଼ୁଛି"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"କୌଣସି ସମସ୍ୟା ମିଳିଲା ନାହିଁ"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{ଉପଲବ୍ଧ ଟିପ}other{ଉପଲବ୍ଧ ଟିପ୍ସ}}"</string>
+ <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ଠିକ ଥିବା ପରି ଲାଗୁଛି"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"କୌଣସି ସମସ୍ୟା ମିଳିଲା ନାହିଁ"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{ସୁପାରିଶ ଦେଖନ୍ତୁ}other{ସୁପାରିଶଗୁଡ଼ିକ ଦେଖନ୍ତୁ}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{ନିଆଯାଇଥିବା ପଦକ୍ଷେପ}other{ନିଆଯାଇଥିବା ପଦକ୍ଷେପଗୁଡ଼ିକ}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ସେଟିଂସର ସମୀକ୍ଷା କରନ୍ତୁ"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ସେଟିଂସ ତାଲିକା ଯାଞ୍ଚ କରନ୍ତୁ"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"ଆପଣ ବିପଦରେ ଅଛନ୍ତି"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"ସମ୍ଭାବ୍ୟ ବିପଦ ମିଳିଛି"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"ବିପଦ ମିଳିଛି"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ଆକାଉଣ୍ଟ ବିପଦରେ ଥାଇପାରେ"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"ଆକାଉଣ୍ଟ ବିପଦରେ ଅଛି"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{ନିମ୍ନରେ ଆଲର୍ଟ ଦେଖନ୍ତୁ}other{ନିମ୍ନରେ ଆଲର୍ଟଗୁଡ଼ିକ ଦେଖନ୍ତୁ}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ଆକାଉଣ୍ଟଟି ରିସ୍କରେ ଥାଇପାରେ"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"ଆକାଉଣ୍ଟଟି ରିସ୍କରେ ଅଛି"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{ଆଲର୍ଟ ଦେଖନ୍ତୁ}other{ଆଲର୍ଟଗୁଡ଼ିକ ଦେଖନ୍ତୁ}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"ପୃଷ୍ଠାକୁ ଖୋଲା ଯାଇପାରିଲା ନାହିଁ"</string>
<string name="resolving_action_error" msgid="371968886143262375">"ଆଲର୍ଟର ସମାଧାନ କରାଯାଇପାରିଲା ନାହିଁ"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ସେଟିଂସ ରିଫ୍ରେସ କରାଯାଇପାରିଲା ନାହିଁ"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ସେଟିଂ ଯାଞ୍ଚ କରାଯାଇପାରିଲା ନାହିଁ}other{ସେଟିଂସ ଯାଞ୍ଚ କରାଯାଇପାରିଲା ନାହିଁ}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"ୱାର୍କ ପ୍ରୋଫାଇଲକୁ ବିରତ କରାଯାଇଛି"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ଏପର୍ଯ୍ୟନ୍ତ କୌଣସି ସୂଚନା ନାହିଁ"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-pa/strings.xml b/SafetyCenter/Resources/shared_res/values-pa/strings.xml
index 022353905..8b17156df 100644
--- a/SafetyCenter/Resources/shared_res/values-pa/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-pa/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"ਸਕੈਨ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="loading_summary" msgid="3740846439782713910">"ਡੀਵਾਈਸ ਸੈਟਿੰਗਾਂ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ਸਭ ਕੁਝ ਠੀਕ ਲੱਗ ਰਿਹਾ ਹੈ"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਮਿਲੀ"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{ਨੁਕਤਾ ਉਪਲਬਧ ਹੈ}one{ਨੁਕਤਾ ਉਪਲਬਧ ਹੈ}other{ਨੁਕਤੇ ਉਪਲਬਧ ਹਨ}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਮਿਲੀ"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{ਸਿਫ਼ਾਰਸ਼ ਦੇਖੋ}one{ਸਿਫ਼ਾਰਸ਼ ਦੇਖੋ}other{ਸਿਫ਼ਾਰਸ਼ਾਂ ਦੇਖੋ}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{ਕੀਤੀ ਗਈ ਕਾਰਵਾਈ}one{ਕੀਤੀ ਗਈ ਕਾਰਵਾਈ}other{ਕੀਤੀਆਂ ਗਈਆਂ ਕਾਰਵਾਈਆਂ}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ਸੈਟਿੰਗਾਂ ਦੀ ਸਮੀਖਿਆ ਕਰੋ"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ਸੈਟਿੰਗਾਂ ਸੂਚੀ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"ਸੰਭਾਵੀ ਜੋਖਮਾਂ ਦਾ ਪਤਾ ਲੱਗਿਆ"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"ਜੋਖਮਾਂ ਦਾ ਪਤਾ ਲੱਗਿਆ"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ਖਾਤਾ ਜੋਖਮ ਵਿੱਚ ਹੋ ਸਕਦਾ ਹੈ"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"ਖਾਤਾ ਜੋਖਮ ਵਿੱਚ ਹੈ"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{ਹੇਠਾਂ ਸੁਚੇਤਨਾ ਦੇਖੋ}one{ਹੇਠਾਂ ਸੁਚੇਤਨਾ ਦੇਖੋ}other{ਹੇਠਾਂ ਸੁਚੇਤਨਾਵਾਂ ਦੇਖੋ}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"ਖਾਤਾ ਜੋਖਮ ਵਿੱਚ ਹੈ"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{ਅਲਰਟ ਦੇਖੋ}one{ਅਲਰਟ ਦੇਖੋ}other{ਅਲਰਟ ਦੇਖੋ}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"ਪੰਨਾ ਖੋਲ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ"</string>
- <string name="resolving_action_error" msgid="371968886143262375">"ਸੁਚੇਤਨਾ ਦਾ ਹੱਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ਸੈਟਿੰਗਾਂ ਨੂੰ ਰਿਫ੍ਰੈਸ਼ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
+ <string name="resolving_action_error" msgid="371968886143262375">"ਅਲਰਟ ਦਾ ਹੱਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ਸੈਟਿੰਗ ਦੀ ਜਾਂਚ ਨਹੀਂ ਕਰ ਸਕੇ}one{ਸੈਟਿੰਗ ਦੀ ਜਾਂਚ ਨਹੀਂ ਕਰ ਸਕੇ}other{ਸੈਟਿੰਗਾਂ ਦੀ ਜਾਂਚ ਨਹੀਂ ਕਰ ਸਕੇ}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ਅਜੇ ਕੋਈ ਜਾਣਕਾਰੀ ਨਹੀਂ ਹੈ"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-pl/strings.xml b/SafetyCenter/Resources/shared_res/values-pl/strings.xml
index 23717053e..89a242e7f 100644
--- a/SafetyCenter/Resources/shared_res/values-pl/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-pl/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Skanowanie"</string>
<string name="loading_summary" msgid="3740846439782713910">"Sprawdzam ustawienia urządzenia…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"OK"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nie znaleziono problemów"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Dostępna wskazówka}few{Dostępne wskazówki}many{Dostępne wskazówki}other{Dostępne wskazówki}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nie znaleziono problemów"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Zobacz rekomendację}few{Zobacz rekomendacje}many{Zobacz rekomendacje}other{Zobacz rekomendacje}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Podjęliśmy działanie}few{Podjęliśmy działania}many{Podjęliśmy działania}other{Podjęliśmy działania}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Sprawdź ustawienia"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Sprawdź listę ustawień"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Wykryte potencjalne zagrożenia"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Wykryte zagrożenia"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Konto może być zagrożone"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Konto jest zagrożone"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Zobacz alert poniżej}few{Zobacz alerty poniżej}many{Zobacz alerty poniżej}other{Zobacz alerty poniżej}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Konto jest zagrożone"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Zobacz alert}few{Zobacz alerty}many{Zobacz alerty}other{Zobacz alerty}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Nie udało się otworzyć strony"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Nie udało się rozwiązać problemu z alertu"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nie udało się odświeżyć ustawień"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nie udało się sprawdzić ustawienia}few{Nie udało się sprawdzić ustawień}many{Nie udało się sprawdzić ustawień}other{Nie udało się sprawdzić ustawień}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Wstrzymano profil służbowy"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Nie ma jeszcze informacji"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml b/SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml
index c2a8b53ad..0599f1c24 100644
--- a/SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml
@@ -17,11 +17,11 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="scanning_title" msgid="5424849039854311398">"Verifican­‐do"</string>
+ <string name="scanning_title" msgid="5424849039854311398">"Verifican­do"</string>
<string name="loading_summary" msgid="3740846439782713910">"Verificando configurações do dispositivo…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Tudo certo"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nenhum problema encontrado"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Dica disponível}one{Dica disponível}many{Dicas disponíveis}other{Dicas disponíveis}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nenhum problema foi encontrado"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Mostrar recomendação}one{Mostrar recomendação}many{Mostrar recomendações}other{Mostrar recomendações}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Ação realizada}one{Ação realizada}many{Ações realizadas}other{Ações realizadas}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Revisar configurações"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Verificar lista de configurações"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Possíveis riscos encontrados"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Riscos encontrados"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"A conta pode estar em risco"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"A conta está em risco"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Conferir alerta abaixo}one{Conferir alerta abaixo}many{Conferir alertas abaixo}other{Conferir alertas abaixo}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Conta em risco"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Mostrar alerta}one{Mostrar alerta}many{Mostrar alertas}other{Mostrar alertas}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Não foi possível abrir a página"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Não foi possível resolver o alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Não foi possível atualizar as configurações"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Não foi possível verificar a configuração}one{Não foi possível verificar a configuração}many{Não foi possível verificar as configurações}other{Não foi possível verificar as configurações}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"O perfil de trabalho está pausado"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ainda não há informações"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml b/SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml
index e7ccb1281..835b8a14f 100644
--- a/SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml
@@ -20,10 +20,10 @@
<string name="scanning_title" msgid="5424849039854311398">"A analisar"</string>
<string name="loading_summary" msgid="3740846439782713910">"A verificar as definições do dispositivo…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Parece estar tudo bem"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nenhum problema encontrado"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Sugestão disponível}many{Sugestões disponíveis}other{Sugestões disponíveis}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nenhum problema encontrado"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Veja a recomendação}many{Veja as recomendações}other{Veja as recomendações}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Medida tomada}many{Medidas tomadas}other{Medidas tomadas}}"</string>
- <string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Reveja as definições"</string>
+ <string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Rever definições"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Verifique a lista de definições"</string>
<string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"O dispositivo pode estar em risco"</string>
<string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"O dispositivo está em risco"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potenciais riscos encontrados"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Riscos encontrados"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"A conta pode estar em risco"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"A conta está em risco"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Veja o alerta abaixo}many{Veja os alertas abaixo}other{Veja os alertas abaixo}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Conta em risco"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Veja o alerta}many{Veja os alertas}other{Veja os alertas}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Não foi possível abrir a página"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Não foi possível resolver o alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Não foi possível atualizar as definições"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Não foi possível verificar a definição}many{Não foi possível verificar as definições}other{Não foi possível verificar as definições}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Perfil de trabalho em pausa"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ainda sem informações"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-pt/strings.xml b/SafetyCenter/Resources/shared_res/values-pt/strings.xml
index c2a8b53ad..0599f1c24 100644
--- a/SafetyCenter/Resources/shared_res/values-pt/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-pt/strings.xml
@@ -17,11 +17,11 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="scanning_title" msgid="5424849039854311398">"Verifican­‐do"</string>
+ <string name="scanning_title" msgid="5424849039854311398">"Verifican­do"</string>
<string name="loading_summary" msgid="3740846439782713910">"Verificando configurações do dispositivo…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Tudo certo"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nenhum problema encontrado"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Dica disponível}one{Dica disponível}many{Dicas disponíveis}other{Dicas disponíveis}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nenhum problema foi encontrado"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Mostrar recomendação}one{Mostrar recomendação}many{Mostrar recomendações}other{Mostrar recomendações}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Ação realizada}one{Ação realizada}many{Ações realizadas}other{Ações realizadas}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Revisar configurações"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Verificar lista de configurações"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Possíveis riscos encontrados"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Riscos encontrados"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"A conta pode estar em risco"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"A conta está em risco"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Conferir alerta abaixo}one{Conferir alerta abaixo}many{Conferir alertas abaixo}other{Conferir alertas abaixo}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Conta em risco"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Mostrar alerta}one{Mostrar alerta}many{Mostrar alertas}other{Mostrar alertas}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Não foi possível abrir a página"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Não foi possível resolver o alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Não foi possível atualizar as configurações"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Não foi possível verificar a configuração}one{Não foi possível verificar a configuração}many{Não foi possível verificar as configurações}other{Não foi possível verificar as configurações}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"O perfil de trabalho está pausado"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ainda não há informações"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ro/strings.xml b/SafetyCenter/Resources/shared_res/values-ro/strings.xml
index 9ce4e29c2..8fa57dcb4 100644
--- a/SafetyCenter/Resources/shared_res/values-ro/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ro/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Se scanează"</string>
<string name="loading_summary" msgid="3740846439782713910">"Se verifică setările dispozitivului…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Pare în regulă"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nu s-au găsit probleme"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Sfat disponibil}few{Sfaturi disponibile}other{Sfaturi disponibile}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nu s-au găsit probleme"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Vezi recomandarea}few{Vezi recomandările}other{Vezi recomandările}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Măsură luată}few{Măsuri luate}other{Măsuri luate}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Verifică setările"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Verifică lista de setări"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"S-au găsit riscuri potențiale"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Riscuri descoperite"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Contul poate fi în pericol"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Contul este în pericol"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Vezi alerta mai jos}few{Vezi alertele mai jos}other{Vezi alertele mai jos}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Cont în pericol"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Vezi alerta}few{Vezi alertele}other{Vezi alertele}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Pagina nu s-a putut deschide"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Nu s-a putut rezolva alerta"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nu s-au putut actualiza setările"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nu s-a putut verifica setarea}few{Nu s-au putut verifica setările}other{Nu s-au putut verifica setările}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Profilul de serviciu este întrerupt"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Nu există informații încă"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ru/strings.xml b/SafetyCenter/Resources/shared_res/values-ru/strings.xml
index 9e3906a15..b72d9b0f0 100644
--- a/SafetyCenter/Resources/shared_res/values-ru/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ru/strings.xml
@@ -20,11 +20,11 @@
<string name="scanning_title" msgid="5424849039854311398">"Поиск"</string>
<string name="loading_summary" msgid="3740846439782713910">"Проверка настроек устройства…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Всё в порядке"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Угроз не обнаружено"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Доступен совет}one{Доступны советы}few{Доступны советы}many{Доступны советы}other{Доступны советы}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Проблем не найдено"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Посмотрите рекомендацию}one{Посмотрите рекомендации}few{Посмотрите рекомендации}many{Посмотрите рекомендации}other{Посмотрите рекомендации}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Выполнено действие}one{Выполнены действия}few{Выполнены действия}many{Выполнены действия}other{Выполнены действия}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Проверьте настройки"</string>
- <string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Изучите список настроек"</string>
+ <string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Просмотрите список настроек"</string>
<string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Устройство может быть под угрозой"</string>
<string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Устройство под угрозой"</string>
<string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Ваши данные могут быть под угрозой"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Обнаружены потенциальные риски"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Обнаружены риски"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Аккаунт может быть под угрозой"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Аккаунт под угрозой"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Ознакомьтесь с оповещением ниже}one{Ознакомьтесь с оповещениями ниже}few{Ознакомьтесь с оповещениями ниже}many{Ознакомьтесь с оповещениями ниже}other{Ознакомьтесь с оповещениями ниже}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Аккаунт под угрозой"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Посмотрите оповещение}one{Посмотрите оповещения}few{Посмотрите оповещения}many{Посмотрите оповещения}other{Посмотрите оповещения}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Не удалось открыть страницу."</string>
<string name="resolving_action_error" msgid="371968886143262375">"Не удалось устранить проблему."</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Не удалось обновить настройки"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Не удалось проверить параметр}one{Не удалось проверить параметры}few{Не удалось проверить параметры}many{Не удалось проверить параметры}other{Не удалось проверить параметры}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Действие рабочего профиля приостановлено."</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Данных пока нет"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-si/strings.xml b/SafetyCenter/Resources/shared_res/values-si/strings.xml
index f023a038b..1ee63199f 100644
--- a/SafetyCenter/Resources/shared_res/values-si/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-si/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"ස්කෑන් කෙරේ"</string>
<string name="loading_summary" msgid="3740846439782713910">"උපාංග සැකසීම් පරීක්ෂා කරමින්…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"හොඳ බව පෙනේ"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"ගැටලු හමු වූයේ නැත"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{ඉඟිය තිබේ}one{ඉඟි තිබේ}other{ඉඟි තිබේ}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"ගැටලු හමු නොවිණි"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{නිර්දේශය බලන්න}one{නිර්දේශ බලන්න}other{නිර්දේශ බලන්න}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{ගත් ක්‍රියාමාර්ගය}one{ගත් ක්‍රියාමාර්ග}other{ගත් ක්‍රියාමාර්ග}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"සැකසීම් සමාලෝචනය කරන්න"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"සැකසීම් ලැයිස්තුව පරීක්ෂා කරන්න"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"විය හැකි අවදානම් හමු විය"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"අවදානම් හමු විය"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ගිණුම අවදානමේ තිබිය හැක"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"ගිණුම අවදානමේ පවතී"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{පහත ඇඟවීම බලන්න}one{පහත ඇඟවීම් බලන්න}other{පහත ඇඟවීම් බලන්න}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"ගිණුම අවදානමේ ඇත"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{ඇඟවීම බලන්න}one{ඇඟවීම් බලන්න}other{ඇඟවීම් බලන්න}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"පිටුව විවෘත කළ නොහැකි විය"</string>
<string name="resolving_action_error" msgid="371968886143262375">"ඇඟවීම විසඳිය නොහැකි විය"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"සැකසීම් නැවුම් කිරීමට නොහැකි විය"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{සැකසීම පරීක්ෂා කිරීමට නොහැකි විය}one{සැකසීම් පරීක්ෂා කිරීමට නොහැකි විය}other{සැකසීම් පරීක්ෂා කිරීමට නොහැකි විය}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"කාර්යාල පැතිකඩ විරාම කර ඇත"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"තවම තතු නැත"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-sk/strings.xml b/SafetyCenter/Resources/shared_res/values-sk/strings.xml
index 83dfc416a..905c3ffe5 100644
--- a/SafetyCenter/Resources/shared_res/values-sk/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-sk/strings.xml
@@ -19,9 +19,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="scanning_title" msgid="5424849039854311398">"Kontroluje sa"</string>
<string name="loading_summary" msgid="3740846439782713910">"Kontrolujú sa nastavenia zariadenia…"</string>
- <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Je to v poriadku"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nenašli sa žiadne problémy"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{K dispozícii je tip}few{K dispozícii sú tipy}many{Tips available}other{K dispozícii sú tipy}}"</string>
+ <string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Všetko v poriadku"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nenašli sa žiadne problémy"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Zobraziť odporúčanie}few{Zobraziť odporúčania}many{See recommendations}other{Zobraziť odporúčania}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Bola vykonaná akcia}few{Boli vykonané akcie}many{Actions taken}other{Boli vykonané akcie}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Kontrola nastavení"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Kontrolný zoznam nastavení"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Boli nájdené potenciálne riziká"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Boli nájdené riziká"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Účet môže byť ohrozený"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Účet je ohrozený"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Prečítajte si upozornenie nižšie}few{Prečítajte si upozornenia nižšie}many{See alerts below}other{Prečítajte si upozornenia nižšie}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Účet je ohrozený"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Zobraziť upozornenie}few{Zobraziť upozornenia}many{See alerts}other{Zobraziť upozornenia}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Stránku sa nepodarilo otvoriť"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Upozornenie sa nepodarilo vyriešiť"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nastavenia sa nepodarilo obnoviť"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nastavenie sa nepodarilo skontrolovať}few{Nastavenia sa nepodarilo skontrolovať}many{Nastavenia sa nepodarilo skontrolovať}other{Nastavenia sa nepodarilo skontrolovať}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Pracovný profil je pozastavený"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Zatiaľ žiadne informácie"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-sl/strings.xml b/SafetyCenter/Resources/shared_res/values-sl/strings.xml
index c66bfa02b..4502b63fd 100644
--- a/SafetyCenter/Resources/shared_res/values-sl/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-sl/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Pregledovanje"</string>
<string name="loading_summary" msgid="3740846439782713910">"Preverjanje nastavitev naprave …"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Videti je v redu"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Ni težav."</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Na voljo je nasvet.}one{Na voljo so nasveti.}two{Na voljo so nasveti.}few{Na voljo so nasveti.}other{Na voljo so nasveti.}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Najdena ni bila nobena težava."</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Ogled priporočila}one{Ogled priporočil}two{Ogled priporočil}few{Ogled priporočil}other{Ogled priporočil}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Dejanje je bilo izvršeno.}one{Dejanja so bila izvršena.}two{Dejanja so bila izvršena.}few{Dejanja so bila izvršena.}other{Dejanja so bila izvršena.}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Pregled nastavitev"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Seznam za preverjanje nastavitev"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Najdena so morebitna tveganja"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Najdena so tveganja"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Račun je morda ogrožen"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Račun je ogrožen"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Oglejte si spodnje opozorilo.}one{Oglejte si spodnja opozorila.}two{Oglejte si spodnja opozorila.}few{Oglejte si spodnja opozorila.}other{Oglejte si spodnja opozorila.}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Račun je ogrožen"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Ogled opozorila}one{Ogled opozoril}two{Ogled opozoril}few{Ogled opozoril}other{Ogled opozoril}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Strani ni bilo mogoče odpreti."</string>
<string name="resolving_action_error" msgid="371968886143262375">"Opozorila ni bilo mogoče odpraviti."</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Nastavitev ni bilo mogoče osvežiti."</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Nastavitve ni bilo mogoče preveriti.}one{Nastavitve ni bilo mogoče preveriti.}two{Nastavitev ni bilo mogoče preveriti.}few{Nastavitev ni bilo mogoče preveriti.}other{Nastavitev ni bilo mogoče preveriti.}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Delovni profil je začasno zaustavljen."</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ni še nobenega podatka."</string>
diff --git a/SafetyCenter/Resources/shared_res/values-sq/strings.xml b/SafetyCenter/Resources/shared_res/values-sq/strings.xml
index 99336807a..0e4981d2f 100644
--- a/SafetyCenter/Resources/shared_res/values-sq/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-sq/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Po skanohet"</string>
<string name="loading_summary" msgid="3740846439782713910">"Po kontrollohen cilësimet pajisjes…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Duket mirë"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Nuk u gjetën probleme"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Ofrohet këshillë}other{Ofrohen këshilla}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Nuk u gjet asnjë problem"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Shiko rekomandimin}other{Shiko rekomandimet}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Masa e marrë}other{Masat e marra}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Rishiko cilësimet"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Kontrollo listën e cilësimeve"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"U gjetën rreziqe të mundshme"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"U gjetën rreziqe"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Llogaria mund të jetë në rrezik"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Llogaria është në rrezik"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Shiko sinjalizimin më poshtë}other{Shiko sinjalizimet më poshtë}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Llogaria në rrezik"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Shiko sinjalizimin}other{Shiko sinjalizimet}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Faqja nuk mund të hapej"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Sinjalizimi nuk mund të zgjidhej"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Cilësimet nuk mund të rifreskoheshin"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Cilësimi nuk mund të kontrollohej}other{Cilësimet nuk mund të kontrolloheshin}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Profili i punës është në pauzë"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Nuk ka ende informacione"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-sr/strings.xml b/SafetyCenter/Resources/shared_res/values-sr/strings.xml
index bf82a6785..e7a5db675 100644
--- a/SafetyCenter/Resources/shared_res/values-sr/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-sr/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Скенира се"</string>
<string name="loading_summary" msgid="3740846439782713910">"Проверавамо подешавања уређаја…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Све је у реду"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Није пронађен ниједан проблем"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Доступан је савет}one{Доступни су савети}few{Доступни су савети}other{Доступни су савети}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Није пронађен ниједан проблем"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Прикажи препоруку}one{Прикажи препоруке}few{Прикажи препоруке}other{Прикажи препоруке}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Предузета радња}one{Предузете радње}few{Предузете радње}other{Предузете радње}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Прегледајте подешавања"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Проверите листу подешавања"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Пронађени су потенцијални ризици"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Пронађени су ризици"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Налог је можда угрожен"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Налог је угрожен"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Погледајте упозорење испод}one{Погледајте упозорења испод}few{Погледајте упозорења испод}other{Погледајте упозорења испод}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Налог је угрожен"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Прикажи обавештење}one{Прикажи обавештења}few{Прикажи обавештења}other{Прикажи обавештења}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Отварање странице није успело"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Решавање обавештења није успело"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Освежавање подешавања није успело"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Провера подешавања није успела}one{Провера подешавања није успела}few{Провера подешавања није успела}other{Провера подешавања није успела}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Пословни профил је паузиран"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Још нема информација"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-sv/strings.xml b/SafetyCenter/Resources/shared_res/values-sv/strings.xml
index f31413a2d..e7773a565 100644
--- a/SafetyCenter/Resources/shared_res/values-sv/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-sv/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Genomsöker"</string>
<string name="loading_summary" msgid="3740846439782713910">"Kontrollerar enhetsinställningarna …"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Det ser bra ut"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Inga problem hittades"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Det finns ett tips}other{Det finns tips}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Inga problem hittades"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Se rekommendation}other{Se rekommendationer}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Åtgärd har vidtagits}other{Åtgärder har vidtagits}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Granska inställningarna"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Kontrollera listan med inställningar"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potentiella risker har upptäckts"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risker har upptäckts"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Kontot kan vara i fara"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Kontot är i fara"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Se avisering nedan}other{Se aviseringar nedan}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Kontot är i fara"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Se varning}other{Se varningar}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Det gick inte att öppna sidan"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Det gick inte att åtgärda varningen"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Det gick inte att uppdatera inställningarna"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Det gick inte att kontrollera inställningen}other{Det gick inte att kontrollera inställningarna}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Jobbprofilen är pausad"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Ingen information än"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-sw/strings.xml b/SafetyCenter/Resources/shared_res/values-sw/strings.xml
index 49310ca55..b78abb739 100644
--- a/SafetyCenter/Resources/shared_res/values-sw/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-sw/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Inakagua"</string>
<string name="loading_summary" msgid="3740846439782713910">"Inakagua mipangilio ya kifaa…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Kila kitu ki shwari"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Haikupata hitilafu yoyote"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Kidokezo kinapatikana}other{Vidokezo vinapatikana}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Hakuna hitilafu iliyopatikana"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Angalia pendekezo}other{Angalia mapendekezo}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Hatua imechukuliwa}other{Hatua zimechukuliwa}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Kagua mipangilio"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Kagua orodha ya mipangilio"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Tumegundua hatari zinazoweza kutokea"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Tumegundua hatari"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Huenda akaunti iko hatarini"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Akaunti iko hatarini"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Angalia arifa hapo chini}other{Angalia arifa hapo chini}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Akaunti iko hatarini"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Angalia tahadhari}other{Angalia tahadhari}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Imeshindwa kufungua ukurasa"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Imeshindwa kutia alama kuwa arifa imeshughulikiwa"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Tumeshindwa kuonyesha upya mipangilio"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Imeshindwa kukagua mipangilio}other{Imeshindwa kukagua mipangilio}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Wasifu wa kazini umesimamishwa"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Bado hakuna maelezo"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ta/strings.xml b/SafetyCenter/Resources/shared_res/values-ta/strings.xml
index d0081c004..3acc13e92 100644
--- a/SafetyCenter/Resources/shared_res/values-ta/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ta/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"ஸ்கேன் செய்தல்"</string>
<string name="loading_summary" msgid="3740846439782713910">"சாதன அமைப்புகளைச் சரிபார்க்கிறது…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"எல்லாம் சரியாக உள்ளன"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"சிக்கல்கள் எதுவுமில்லை"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{உதவிக்குறிப்பு உள்ளது}other{உதவிக்குறிப்புகள் உள்ளன}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"சிக்கல்கள் எதுவுமில்லை"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{பரிந்துரையைப் பாருங்கள்}other{பரிந்துரைகளைப் பாருங்கள்}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{எடுக்கப்பட்ட நடவடிக்கை}other{எடுக்கப்பட்ட நடவடிக்கைகள்}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"அமைப்புகளைச் சரிபார்த்தல்"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"அமைப்புகள் பட்டியலைச் சரிபாருங்கள்"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"சாத்தியமுள்ள ஆபத்து கண்டறியப்பட்டன"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"ஆபத்துகள் கண்டறியப்பட்டுள்ளன"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"கணக்கு ஆபத்தில் இருக்கலாம்"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"கணக்கு ஆபத்தில் உள்ளது"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{கீழுள்ள விழிப்பூட்டலைப் பாருங்கள்}other{கீழுள்ள விழிப்பூட்டல்களைப் பாருங்கள்}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"கணக்கு ஆபத்தில் உள்ளது"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{விழிப்பூட்டலைப் பாருங்கள்}other{விழிப்பூட்டல்களைப் பாருங்கள்}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"பக்கத்தைத் திறக்க முடியவில்லை"</string>
<string name="resolving_action_error" msgid="371968886143262375">"எச்சரிக்கையைத் தீர்க்க முடியவில்லை"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"அமைப்புகளைப் புதுப்பிக்க முடியவில்லை"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{அமைப்பைச் சரிபார்க்க முடியவில்லை}other{அமைப்புகளைச் சரிபார்க்க முடியவில்லை}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"பணிக் கணக்கு இடைநிறுத்தப்பட்டது"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"தகவல்கள் எதுவுமில்லை"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-te/strings.xml b/SafetyCenter/Resources/shared_res/values-te/strings.xml
index 5dc26fb81..c9ecc0f23 100644
--- a/SafetyCenter/Resources/shared_res/values-te/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-te/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"స్కానింగ్"</string>
<string name="loading_summary" msgid="3740846439782713910">"పరికర సెట్టింగ్‌లను చెక్ చేస్తోంది…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"అంతా బాగానే ఉంది"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"సమస్యలు ఏవీ కనుగొనబడలేదు"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{చిట్కా అందుబాటులో ఉంది}other{చిట్కాలు అందుబాటులో ఉన్నాయి}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"ఎటువంటి సమస్యలూ కనుగొనబడలేదు"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{సిఫార్సును చూడండి}other{సిఫార్సులను చూడండి}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{చర్య తీసుకోబడింది}other{చర్యలు తీసుకొనబడ్డాయి}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"సెట్టింగ్‌లను రివ్యూ చేయండి"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"సెట్టింగ్‌ల లిస్ట్‌ను చెక్ చేయండి"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"అవకాశం ఉన్న రిస్క్‌లు కనుగొనబడ్డాయి"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"రిస్క్‌లు కనుగొనబడ్డాయి"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"ఖాతా ప్రమాదంలో ఉండవచ్చు"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"ఖాతా ప్రమాదంలో ఉంది"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{కింద అలర్ట్‌ను చూడండి}other{కింద అలర్ట్‌లను చూడండి}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"ఖాతా ప్రమాదంలో ఉంది"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{అలర్ట్‌ను చూడండి}other{అలర్ట్‌లను చూడండి}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"పేజీని తెరవడం సాధ్యపడలేదు"</string>
<string name="resolving_action_error" msgid="371968886143262375">"అలర్ట్‌ను పరిష్కరించడం సాధ్యపడలేదు"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"సెట్టింగ్‌లను రిఫ్రెష్ చేయడం సాధ్యపడలేదు"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{సెట్టింగ్‌ను చెక్ చేయడం సాధ్యపడలేదు}other{సెట్టింగ్‌లను చెక్ చేయడం సాధ్యపడలేదు}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"వర్క్ ప్రొఫైల్ పాజ్ చేయబడింది"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ఇంకా ఏ సమాచారం లేదు"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-th/strings.xml b/SafetyCenter/Resources/shared_res/values-th/strings.xml
index 5ac8eac2f..f879c3ae4 100644
--- a/SafetyCenter/Resources/shared_res/values-th/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-th/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"การสแกน"</string>
<string name="loading_summary" msgid="3740846439782713910">"กำลังตรวจสอบการตั้งค่าอุปกรณ์…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ดูดีแล้ว"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"ไม่พบปัญหา"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{เคล็ดลับที่นำไปใช้ได้}other{เคล็ดลับที่นำไปใช้ได้}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"ไม่พบปัญหา"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{ดูคำแนะนำ}other{ดูคำแนะนำ}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{ดำเนินการแล้ว}other{ดำเนินการแล้ว}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ตรวจสอบการตั้งค่า"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ตรวจสอบรายการการตั้งค่า"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"พบความเสี่ยงที่อาจเกิดขึ้น"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"พบความเสี่ยง"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"บัญชีอาจมีความเสี่ยง"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"บัญชีมีความเสี่ยง"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{ดูการแจ้งเตือนด้านล่าง}other{ดูการแจ้งเตือนด้านล่าง}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"บัญชีมีความเสี่ยง"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{ดูการแจ้งเตือน}other{ดูการแจ้งเตือน}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"เปิดหน้าไม่ได้"</string>
<string name="resolving_action_error" msgid="371968886143262375">"แก้ไขการแจ้งเตือนไม่ได้"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"รีเฟรชการตั้งค่าไม่ได้"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ไม่สามารถตรวจสอบการตั้งค่า}other{ไม่สามารถตรวจสอบการตั้งค่า}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"โปรไฟล์งานหยุดชั่วคราว"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ยังไม่มีข้อมูล"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-tl/strings.xml b/SafetyCenter/Resources/shared_res/values-tl/strings.xml
index 9426dd435..d2449116f 100644
--- a/SafetyCenter/Resources/shared_res/values-tl/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-tl/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Pag-scan"</string>
<string name="loading_summary" msgid="3740846439782713910">"Tinitingnan ang mga setting ng device…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Mukhang ayos"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Walang nakitang problema"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{May available na tip}one{May mga available na tip}other{May mga available na tip}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Walang nakitang isyu"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Tingnan ang rekomendasyon}one{Tingnan ang mga rekomendasyon}other{Tingnan ang mga rekomendasyon}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Ginawang pagkilos}one{Mga ginawang pagkilos}other{Mga ginawang pagkilos}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Suriin ang mga setting"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Tingnan ang listahan ng mga setting"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"May nakitang potensyal na panganib"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"May nakitang mga panganib"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Posibleng nanganganib ang account"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Nanganganib ang account"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Tingnan ang alerto sa ibaba}one{Tingnan ang mga alerto sa ibaba}other{Tingnan ang mga alerto sa ibaba}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Nanganganib ang account"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Tingnan ang alerto}one{Tingnan ang mga alerto}other{Tingnan ang mga alerto}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Hindi mabuksan ang page"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Hindi ma-resolve ang alerto"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Hindi ma-refresh ang mga setting"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Hindi masuri ang setting}one{Hindi masuri ang mga setting}other{Hindi masuri ang mga setting}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Naka-pause ang profile sa trabaho"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Wala pang impormasyon"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-tr/strings.xml b/SafetyCenter/Resources/shared_res/values-tr/strings.xml
index 55693a94b..69bf874dd 100644
--- a/SafetyCenter/Resources/shared_res/values-tr/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-tr/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Tarama"</string>
<string name="loading_summary" msgid="3740846439782713910">"Cihaz ayarları kontrol ediliyor…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"İyi görünüyor"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Sorun bulunmadı"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{İpucu mevcut}other{İpuçları mevcut}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Sorun bulunmadı"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Öneriye göz atın}other{Önerilere göz atın}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Gerçekleştirilen işlem}other{Gerçekleştirilen işlemler}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Ayarları inceleyin"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Ayarlar listesini kontrol edin"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Olası riskler bulundu"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Risk bulundu"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Hesap risk altında olabilir"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Hesap risk altında"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Aşağıdaki uyarıya bakın}other{Aşağıdaki uyarılara bakın}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Hesap risk altında"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Uyarıya göz atın}other{Uyarılara göz atın}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Sayfa açılamadı"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Uyarı sonlandırılamadı"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Ayarlar yenilenemedi"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Ayar kontrol edilemedi}other{Ayarlar kontrol edilemedi}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"İş profili duraklatıldı"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Henüz bilgi yok"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-uk/strings.xml b/SafetyCenter/Resources/shared_res/values-uk/strings.xml
index 8a9ef7221..44b304f80 100644
--- a/SafetyCenter/Resources/shared_res/values-uk/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-uk/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Пошук"</string>
<string name="loading_summary" msgid="3740846439782713910">"Перевіряємо налаштування пристрою…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Усе добре"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Проблем не знайдено"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Є порада}one{Є поради}few{Є поради}many{Є поради}other{Є поради}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Проблем не виявлено"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Перегляньте рекомендацію}one{Перегляньте рекомендації}few{Перегляньте рекомендації}many{Перегляньте рекомендації}other{Перегляньте рекомендації}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Вжито захід}one{Вжито заходів}few{Вжито заходів}many{Вжито заходів}other{Вжито заходів}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Перевірте налаштування"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Перегляньте список налаштувань"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Виявлено потенційні загрози безпеці"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Виявлено загрози безпеці"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Можлива загроза обліковому запису"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Обліковий запис під загрозою"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Перегляньте сповіщення нижче}one{Перегляньте сповіщення нижче}few{Перегляньте сповіщення нижче}many{Перегляньте сповіщення нижче}other{Перегляньте сповіщення нижче}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Обліковий запис під загрозою"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Перегляньте сповіщення}one{Перегляньте сповіщення}few{Перегляньте сповіщення}many{Перегляньте сповіщення}other{Перегляньте сповіщення}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Не вдалося відкрити сторінку"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Не вдалося закрити сповіщення"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Не вдалось оновити налаштування"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Не вдалося перевірити налаштування}one{Не вдалося перевірити налаштування}few{Не вдалося перевірити налаштування}many{Не вдалося перевірити налаштування}other{Не вдалося перевірити налаштування}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Робочий профіль призупинено"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Поки немає інформації"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-ur/strings.xml b/SafetyCenter/Resources/shared_res/values-ur/strings.xml
index 3ad7b8631..f0d791f1e 100644
--- a/SafetyCenter/Resources/shared_res/values-ur/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-ur/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"اسکین ہو رہا ہے"</string>
<string name="loading_summary" msgid="3740846439782713910">"آلے کی ترتیبات چیک کی جا رہی ہیں…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"ٹھیک لگ رہا ہے"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"کوئی مسئلہ نہیں پایا گيا"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{تجویز دستیاب ہے}other{تجاویز دستیاب ہیں}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"کوئی مسئلہ نہیں ملا"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{تجویز دیکھیں}other{تجاویز دیکھیں}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{کیا گیا اقدام}other{کیے گئے اقدامات}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"ترتیبات کا جائزہ لیں"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"ترتیبات کی فہرست چیک کریں"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"ممکنہ خطرات پائے گئے"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"خطرات پائے گئے"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"اکاؤنٹ خطرے میں ہو سکتا ہے"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"اکاؤنٹ خطرے میں ہے"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{ذیل میں الرٹ دیکھیں}other{ذیل میں الرٹس دیکھیں}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"اکاؤنٹ خطرے میں ہے"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{الرٹ دیکھیں}other{الرٹس دیکھیں}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"صفحہ نہیں کھل سکا"</string>
<string name="resolving_action_error" msgid="371968886143262375">"الرٹ حل نہیں ہو سکا"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"ترتیبات ریفریش نہیں کی جا سکی"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{ترتیب کی جانچ نہیں کی جا سکی}other{ترتیبات کی جانچ نہیں کی جا سکی}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"دفتری پروفائل روک دی گئی ہے"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"ابھی تک کوئی معلومات نہیں ہے"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-uz/strings.xml b/SafetyCenter/Resources/shared_res/values-uz/strings.xml
index d01559ead..a4b933eb9 100644
--- a/SafetyCenter/Resources/shared_res/values-uz/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-uz/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Tekshiruv"</string>
<string name="loading_summary" msgid="3740846439782713910">"Qurilma sozlamalari tekshirilmoqda…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Hammasi joyida"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Hech qanday muammo topilmadi"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Tavsiya bor}other{Tavsiyalar bor}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Hech qanday muammo topilmadi"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Tavsiya}other{Tavsiyalar}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Bajarilgan amal}other{Bajarilgan amallar}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Sozlamalarni tekshirish"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Sozlamalar roʻyxatini tekshirish"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Xavf ostidasiz"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Potentsial xavflar topildi"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Xavflar topildi"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Hisob xavf ostida shekilli"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Hisob xavf ostida"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Ogohlantiruvni ochish}other{Ogohlantiruvlarni ochish}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Hisob xavf ostida boʻlishi mumkin"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Hisob xavf ostida"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Ogohlantirish}other{Ogohlantirishlar}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Sahifa ochilmadi"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Ogohlantirish hal qilinmadi"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Sozlamalar yangilanmadi"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Sozlama tekshirilmadi}other{Sozlamalar tekshirilmadi}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Ish profili pauzada"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Hali axborot olinmadi"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-vi/strings.xml b/SafetyCenter/Resources/shared_res/values-vi/strings.xml
index 6aa24cbaf..8bbffeb1b 100644
--- a/SafetyCenter/Resources/shared_res/values-vi/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-vi/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Quét"</string>
<string name="loading_summary" msgid="3740846439782713910">"Đang kiểm tra chế độ cài đặt của thiết bị…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Có vẻ ổn"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Không tìm thấy vấn đề nào"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Có mẹo cho bạn}other{Có mẹo cho bạn}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Không phát hiện thấy sự cố nào"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Xem đề xuất}other{Xem các đề xuất}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Hành động đã thực hiện}other{Hành động đã thực hiện}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Xem lại các chế độ cài đặt"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Kiểm tra danh sách cài đặt"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Đã phát hiện rủi ro tiềm ẩn"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Đã phát hiện rủi ro"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"Tài khoản có thể gặp rủi ro"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"Tài khoản đang gặp rủi ro"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Xem cảnh báo bên dưới}other{Xem cảnh báo bên dưới}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"Tài khoản đang gặp rủi ro"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Xem cảnh báo}other{Xem cảnh báo}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Không thể mở trang"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Không thể giải quyết vấn đề cảnh báo"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Không thể làm mới cài đặt"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Không kiểm tra được chế độ cài đặt}other{Không kiểm tra được các chế độ cài đặt}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Hồ sơ công việc của bạn đã bị tạm dừng"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Chưa có thông tin"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml b/SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml
index 4f0805d5f..bc59150b4 100644
--- a/SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"正在扫描"</string>
<string name="loading_summary" msgid="3740846439782713910">"正在检查设备设置…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"没问题"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"未发现问题"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{有可用的提示}other{有可用的提示}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"未发现任何问题"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{查看建议}other{查看建议}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{已采取措施}other{已采取措施}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"检查设置"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"请检查设置列表"</string>
@@ -35,12 +35,11 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"您目前有风险"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"发现潜在风险"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"发现风险"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"帐号可能存在风险"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"帐号存在风险"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{请查看下方提醒}other{请查看下方提醒}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"账号可能存在风险"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"账号存在风险"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{查看提醒}other{查看提醒}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"无法打开页面"</string>
<string name="resolving_action_error" msgid="371968886143262375">"无法解决提醒事项"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"无法刷新设置"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{无法检查设置}other{无法检查设置}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"工作资料已被暂停"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"尚无任何信息"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml b/SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml
index 35db195f7..a2f8f75a8 100644
--- a/SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml
@@ -20,27 +20,26 @@
<string name="scanning_title" msgid="5424849039854311398">"正在掃瞄"</string>
<string name="loading_summary" msgid="3740846439782713910">"正在檢查裝置設定…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"沒有問題"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"未發現問題"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{有可用的提示}other{有可用的提示}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"未發現任何問題"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{查看建議}other{查看建議}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{已採取行動}other{已採取行動}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"檢查設定"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"查看設定清單"</string>
<string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"裝置可能存在風險"</string>
<string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"裝置存在風險"</string>
- <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"您的資料可能面臨風險"</string>
- <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"您的資料正面臨風險"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"你的資料可能面臨風險"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"你的資料正面臨風險"</string>
<string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"被盜用的密碼 (舊)"</string>
<string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"被盜用的密碼 (新)"</string>
- <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"您可能面臨風險"</string>
- <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"您正面臨風險"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"你可能面臨風險"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"你正面臨風險"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"系統發現潛在風險"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"系統發現風險"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"帳戶可能面臨風險"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"裝置正面臨風險"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{查看下方的警示}other{查看下方的警示}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"帳戶可能存在風險"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"帳戶存在風險"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{查看警示}other{查看警示}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"無法開啟頁面"</string>
<string name="resolving_action_error" msgid="371968886143262375">"無法解除警示"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"無法重新整理設定"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{無法檢查設定}other{無法檢查設定}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"工作設定檔已暫停"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"暫時沒有資料"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml b/SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml
index 500a9d4a3..beb5af4a2 100644
--- a/SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"掃描"</string>
<string name="loading_summary" msgid="3740846439782713910">"正在檢查裝置設定…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"沒有問題"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"未發現問題"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{有可用的提示}other{有可用的提示}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"未發現任何問題"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{查看建議}other{查看建議}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{已採取行動}other{已採取行動}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"查看設定"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"檢查設定清單"</string>
@@ -35,16 +35,15 @@
<string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"你的帳戶有風險"</string>
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"發現潛在風險"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"發現風險"</string>
- <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"帳戶可能面臨風險"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"帳戶目前有風險"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{請查看下方警示}other{請查看下方警示}}"</string>
+ <string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"帳戶可能有風險"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"帳戶有風險"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{查看警示}other{查看警示}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"無法開啟網頁"</string>
<string name="resolving_action_error" msgid="371968886143262375">"無法解決警示"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"無法重新整理設定"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{無法檢查設定}other{無法檢查設定}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"工作資料夾已暫停"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"目前還沒有任何資訊"</string>
- <string name="notification_channel_group_name" msgid="7155072032524876859">"安全性與隱私"</string>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"安全性與隱私權"</string>
<string name="notification_channel_name_information" msgid="2966444432152990166">"建議"</string>
<string name="notification_channel_name_recommendation" msgid="7847408286580217922">"警告"</string>
<string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"嚴重警告"</string>
diff --git a/SafetyCenter/Resources/shared_res/values-zu/strings.xml b/SafetyCenter/Resources/shared_res/values-zu/strings.xml
index 55588c363..21c358f15 100644
--- a/SafetyCenter/Resources/shared_res/values-zu/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values-zu/strings.xml
@@ -20,8 +20,8 @@
<string name="scanning_title" msgid="5424849039854311398">"Iyaskena"</string>
<string name="loading_summary" msgid="3740846439782713910">"Ihlola amasethingi edivayisi…"</string>
<string name="overall_severity_level_ok_title" msgid="2041250138727564565">"Kubukeka kukuhle"</string>
- <string name="overall_severity_level_ok_summary" msgid="7219520381757200598">"Azikho izinkinga ezitholiwe"</string>
- <string name="overall_severity_level_tip_summary" msgid="5582440812368113766">"{count,plural, =1{Ithiphu liyatholakala}one{Amathiphu ayatholakala}other{Amathiphu ayatholakala}}"</string>
+ <string name="overall_severity_level_ok_summary" msgid="383626536912856690">"Ayikho inkinga etholiwe"</string>
+ <string name="overall_severity_level_tip_summary" msgid="1935765582243024999">"{count,plural, =1{Bona isincomo}one{Bona izincomo}other{Bona izincomo}}"</string>
<string name="overall_severity_level_action_taken_summary" msgid="8064091657855656545">"{count,plural, =1{Isinyathelo sithathiwe}one{Izinyathelo zithathiwe}other{Izinyathelo zithathiwe}}"</string>
<string name="overall_severity_level_ok_review_title" msgid="1494321117696765360">"Buyekeza amasethingi"</string>
<string name="overall_severity_level_ok_review_summary" msgid="7743619617413076275">"Hlola uhlu lwamasethingi"</string>
@@ -36,11 +36,10 @@
<string name="overall_severity_level_safety_recommendation_title" msgid="4291797434760242793">"Izingozi ezingaba khona zitholakele"</string>
<string name="overall_severity_level_critical_safety_warning_title" msgid="6666640109779586868">"Izingozi ezitholakele"</string>
<string name="overall_severity_level_account_recommendation_title" msgid="2267542168734275090">"I-akhawunti ingaba sengozini"</string>
- <string name="overall_severity_level_critical_account_warning_title" msgid="4402278408972158353">"I-akhawunti isengcupheni"</string>
- <string name="overall_severity_n_alerts_summary" msgid="6527386677095695234">"{count,plural, =1{Bona isexwayiso ngezansi}one{Bona izexwayiso ngezansi}other{Bona izexwayiso ngezansi}}"</string>
+ <string name="overall_severity_level_critical_account_warning_title" msgid="1913235490583842004">"I-akhawunti isengozini"</string>
+ <string name="overall_severity_n_alerts_summary" msgid="3262010942295408403">"{count,plural, =1{Bona isixwayiso}one{Bona izixwayiso}other{Bona izixwayiso}}"</string>
<string name="redirecting_error" msgid="8146983632878233202">"Ayikwazanga ukuvula ikhasi"</string>
<string name="resolving_action_error" msgid="371968886143262375">"Ayikwazanga ukuxazulula isexwayiso"</string>
- <string name="refresh_timeout" msgid="251734999692581852">"Ayikwazanga ukuvuselela amasethingi"</string>
<string name="refresh_error" msgid="656062128422446177">"{count,plural, =1{Ayikwazanga ukuhlola isethingi}one{Ayikwazanga ukuhlola amasethingi}other{Ayikwazanga ukuhlola amasethingi}}"</string>
<string name="work_profile_paused" msgid="7037400224040869079">"Iphrofayela yomsebenzi iphunyuziwe"</string>
<string name="group_unknown_summary" msgid="6951386960814105641">"Alukho ulwazi okwamanje"</string>
diff --git a/SafetyCenter/Resources/shared_res/values/strings.xml b/SafetyCenter/Resources/shared_res/values/strings.xml
index f4f1b0201..2b231b55f 100644
--- a/SafetyCenter/Resources/shared_res/values/strings.xml
+++ b/SafetyCenter/Resources/shared_res/values/strings.xml
@@ -94,9 +94,6 @@
<!-- An error shown to the user when we failed to resolve an alert that they attempted to resolve directly from the Safety Center screen [CHAR LIMIT=50] -->
<string name="resolving_action_error">Couldn\’t resolve alert</string>
- <!-- An error shown to the user when we failed to refresh the overall Safety Center status. This happens when at least one safety signal did not get back to Safety Center within an arbitrary timeout [CHAR LIMIT=50] -->
- <string name="refresh_timeout">Couldn\’t refresh settings</string>
-
<!-- An error shown to the user when we failed to refresh the status of one or more Safety Center entries. The number of entries is used as a parameter to format the error [CHAR LIMIT=60] -->
<string name="refresh_error">{count, plural,
=1 {Couldn\’t check setting}
diff --git a/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesApk.java b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesApk.java
new file mode 100644
index 000000000..fe0908ea0
--- /dev/null
+++ b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesApk.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.safetycenter.resources;
+
+import static java.util.Objects.requireNonNull;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.util.Log;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.annotation.VisibleForTesting;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * A class to access Safety Center resources that need to be fetched from a dedicated APK.
+ *
+ * <p>You must check whether Safety Center is enabled or the value returned by {@link #init()} prior
+ * to interacting with this class. Failure to do so may cause an {@link IllegalStateException} if
+ * the resources APK cannot be accessed.
+ *
+ * <p>This class isn't thread safe. Thread safety must be handled by the caller, or this may cause
+ * the resources APK {@link Context} to be initialized multiple times.
+ */
+public final class SafetyCenterResourcesApk {
+
+ private static final String TAG = "SafetyCenterResApk";
+
+ /** Intent action that is used to identify the Safety Center resources APK */
+ private static final String RESOURCES_APK_ACTION =
+ "com.android.safetycenter.intent.action.SAFETY_CENTER_RESOURCES_APK";
+
+ /** Permission APEX name */
+ private static final String APEX_MODULE_NAME = "com.android.permission";
+
+ /**
+ * The path where the Permission apex is mounted. Current value = "/apex/com.android.permission"
+ */
+ private static final String APEX_MODULE_PATH =
+ new File("/apex", APEX_MODULE_NAME).getAbsolutePath();
+
+ /** Raw XML config resource name */
+ private static final String CONFIG_NAME = "safety_center_config";
+
+ private final Context mContext;
+
+ /** Intent action that is used to identify the Safety Center resources APK */
+ private final String mResourcesApkAction;
+
+ /** The path where the Safety Center resources APK is expected to be installed */
+ private final String mResourcesApkPath;
+
+ /** Specific flags used for retrieving resolve info. */
+ private final int mFlags;
+
+ /**
+ * Whether we should fallback with an empty string / null values when calling the methods of
+ * this class for a resource that does not exist.
+ */
+ private final boolean mShouldFallbackIfNamedResourceNotFound;
+
+ // Cached context from the resources APK.
+ @Nullable private Context mResourcesApkContext;
+
+ public SafetyCenterResourcesApk(Context context) {
+ this(context, /* shouldFallbackIfNamedResourceNotFound */ true);
+ }
+
+ private SafetyCenterResourcesApk(
+ Context context, boolean shouldFallbackIfNamedResourceNotFound) {
+ this(
+ context,
+ RESOURCES_APK_ACTION,
+ APEX_MODULE_PATH,
+ PackageManager.MATCH_SYSTEM_ONLY,
+ shouldFallbackIfNamedResourceNotFound);
+ }
+
+ @VisibleForTesting
+ SafetyCenterResourcesApk(
+ Context context,
+ String resourcesApkAction,
+ String resourcesApkPath,
+ int flags,
+ boolean shouldFallbackIfNamedResourceNotFound) {
+ mContext = requireNonNull(context);
+ mResourcesApkAction = requireNonNull(resourcesApkAction);
+ mResourcesApkPath = requireNonNull(resourcesApkPath);
+ mFlags = flags;
+ mShouldFallbackIfNamedResourceNotFound = shouldFallbackIfNamedResourceNotFound;
+ }
+
+ /** Creates a new {@link SafetyCenterResourcesApk} for testing. */
+ @VisibleForTesting
+ public static SafetyCenterResourcesApk forTests(Context context) {
+ return new SafetyCenterResourcesApk(
+ context, /* shouldFallbackIfNamedResourceNotFound */ false);
+ }
+
+ /**
+ * Initializes the resources APK {@link Context}, and returns whether this was successful.
+ *
+ * <p>This call is optional as this can also be lazily instantiated. It can be used to ensure
+ * that the resources APK context is loaded prior to interacting with this class. This
+ * initialization code needs to run in the same user as the provided base {@link Context}. This
+ * may not be the case with a binder call, which is why it can be more appropriate to do this
+ * explicitly.
+ */
+ public boolean init() {
+ mResourcesApkContext = loadResourcesApkContext();
+ return mResourcesApkContext != null;
+ }
+
+ /**
+ * Returns the {@link Context} of the Safety Center resources APK.
+ *
+ * <p>Throws an {@link IllegalStateException} if the resources APK is not available
+ */
+ public Context getContext() {
+ if (mResourcesApkContext != null) {
+ return mResourcesApkContext;
+ }
+
+ mResourcesApkContext = loadResourcesApkContext();
+ if (mResourcesApkContext == null) {
+ throw new IllegalStateException("Resources APK context not found");
+ }
+
+ return mResourcesApkContext;
+ }
+
+ @Nullable
+ private Context loadResourcesApkContext() {
+ List<ResolveInfo> resolveInfos =
+ mContext.getPackageManager()
+ .queryIntentActivities(new Intent(mResourcesApkAction), mFlags);
+
+ if (resolveInfos.size() > 1) {
+ // multiple apps found, log a warning, but continue
+ Log.w(TAG, "Found > 1 APK that can resolve Safety Center resources APK intent:");
+ final int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+ Log.w(
+ TAG,
+ String.format(
+ "- pkg:%s at:%s",
+ resolveInfo.activityInfo.applicationInfo.packageName,
+ resolveInfo.activityInfo.applicationInfo.sourceDir));
+ }
+ }
+
+ ResolveInfo info = null;
+ // Assume the first good ResolveInfo is the one we're looking for
+ final int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+ if (!resolveInfo.activityInfo.applicationInfo.sourceDir.startsWith(mResourcesApkPath)) {
+ // skip apps that don't live in the Permission apex
+ continue;
+ }
+ info = resolveInfo;
+ break;
+ }
+
+ if (info == null) {
+ // Resource APK not loaded yet, print a stack trace to see where this is called from
+ Log.e(TAG, "Could not find Safety Center resources APK", new IllegalStateException());
+ return null;
+ }
+
+ String resourcesApkPkgName = info.activityInfo.applicationInfo.packageName;
+ Log.i(TAG, "Found Safety Center resources APK at: " + resourcesApkPkgName);
+ return getPackageContext(resourcesApkPkgName);
+ }
+
+ @Nullable
+ private Context getPackageContext(String packageName) {
+ try {
+ return mContext.createPackageContext(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Failed to load package context for: " + packageName, e);
+ }
+ return null;
+ }
+
+ /** Calls {@link Context#getResources()} for the resources APK {@link Context}. */
+ public Resources getResources() {
+ return getContext().getResources();
+ }
+
+ /**
+ * Returns the raw XML resource representing the Safety Center configuration file from the
+ * Safety Center resources APK.
+ */
+ @Nullable
+ public InputStream getSafetyCenterConfig() {
+ return getSafetyCenterConfig(CONFIG_NAME);
+ }
+
+ @VisibleForTesting
+ @Nullable
+ InputStream getSafetyCenterConfig(String configName) {
+ int resId = getResIdAndMaybeThrowIfNull(configName, "raw");
+ if (resId == Resources.ID_NULL) {
+ return null;
+ }
+ return getResources().openRawResource(resId);
+ }
+
+ /** Calls {@link Context#getString(int)} for the resources APK {@link Context}. */
+ public String getString(@StringRes int stringId) {
+ return getContext().getString(stringId);
+ }
+
+ /** Same as {@link #getString(int)} but with the given {@code formatArgs}. */
+ public String getString(@StringRes int stringId, Object... formatArgs) {
+ return getContext().getString(stringId, formatArgs);
+ }
+
+ /**
+ * Returns the {@link String} with the given resource name.
+ *
+ * <p>If the {@link String} cannot be accessed, returns {@code ""} or throws {@link
+ * Resources.NotFoundException} depending on {@link #mShouldFallbackIfNamedResourceNotFound}.
+ */
+ public String getStringByName(String name) {
+ int resId = getResIdAndMaybeThrowIfNull(name, "string");
+ if (resId == Resources.ID_NULL) {
+ return "";
+ }
+ return getString(resId);
+ }
+
+ /** Same as {@link #getStringByName(String)} but with the given {@code formatArgs}. */
+ public String getStringByName(String name, Object... formatArgs) {
+ int resId = getResIdAndMaybeThrowIfNull(name, "string");
+ if (resId == Resources.ID_NULL) {
+ return "";
+ }
+ return getString(resId, formatArgs);
+ }
+
+ /**
+ * Returns an optional {@link String} resource with the given {@code stringId}.
+ *
+ * <p>Returns {@code null} if {@code stringId} is equal to {@link Resources#ID_NULL}. Otherwise,
+ * throws a {@link Resources.NotFoundException}.
+ */
+ @Nullable
+ public String getOptionalString(@StringRes int stringId) {
+ if (stringId == Resources.ID_NULL) {
+ return null;
+ }
+ return getString(stringId);
+ }
+
+ /** Same as {@link #getOptionalString(int)} but with the given resource name rather than ID. */
+ @Nullable
+ public String getOptionalStringByName(String name) {
+ return getOptionalString(getResId(name, "string"));
+ }
+
+ /**
+ * Returns the {@link Drawable} with the given resource name.
+ *
+ * <p>If the {@link Drawable} cannot be accessed, returns {@code null} or throws {@link
+ * Resources.NotFoundException} depending on {@link #mShouldFallbackIfNamedResourceNotFound}.
+ *
+ * @param theme the theme used to style the drawable attributes, may be {@code null}
+ */
+ @Nullable
+ public Drawable getDrawableByName(String name, @Nullable Resources.Theme theme) {
+ int resId = getResIdAndMaybeThrowIfNull(name, "drawable");
+ if (resId == Resources.ID_NULL) {
+ return null;
+ }
+ return getResources().getDrawable(resId, theme);
+ }
+
+ /**
+ * Returns an {@link Icon} containing the {@link Drawable} with the given resource name.
+ *
+ * <p>If the {@link Drawable} cannot be accessed, returns {@code null} or throws {@link
+ * Resources.NotFoundException} depending on {@link #mShouldFallbackIfNamedResourceNotFound}.
+ */
+ @Nullable
+ public Icon getIconByDrawableName(String name) {
+ int resId = getResIdAndMaybeThrowIfNull(name, "drawable");
+ if (resId == Resources.ID_NULL) {
+ return null;
+ }
+ return Icon.createWithResource(getContext().getPackageName(), resId);
+ }
+
+ /**
+ * Returns the {@link ColorInt} with the given resource name.
+ *
+ * <p>If the {@link ColorInt} cannot be accessed, returns {@code null} or throws {@link
+ * Resources.NotFoundException} depending on {@link #mShouldFallbackIfNamedResourceNotFound}.
+ */
+ @ColorInt
+ @Nullable
+ public Integer getColorByName(String name) {
+ int resId = getResIdAndMaybeThrowIfNull(name, "color");
+ if (resId == Resources.ID_NULL) {
+ return null;
+ }
+ return getResources().getColor(resId, getContext().getTheme());
+ }
+
+ private int getResIdAndMaybeThrowIfNull(String name, String type) {
+ int resId = getResId(name, type);
+ if (resId != Resources.ID_NULL) {
+ return resId;
+ }
+ if (!mShouldFallbackIfNamedResourceNotFound) {
+ throw new Resources.NotFoundException();
+ }
+ Log.w(TAG, "Named " + type + " resource: " + name + " not found");
+ return resId;
+ }
+
+ private int getResId(String name, String type) {
+ // TODO(b/227738283): profile the performance of this operation and consider adding caching
+ // or finding some alternative solution.
+ return getResources().getIdentifier(name, type, getContext().getPackageName());
+ }
+}
diff --git a/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java
deleted file mode 100644
index 9a77296e2..000000000
--- a/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.safetycenter.resources;
-
-import static java.util.Objects.requireNonNull;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.util.Log;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-import androidx.annotation.VisibleForTesting;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.List;
-
-/**
- * Wrapper for context to override getResources method. Resources for the Safety Center that need to
- * be fetched from the dedicated resources APK.
- */
-public class SafetyCenterResourcesContext extends ContextWrapper {
- private static final String TAG = "SafetyCenterResContext";
-
- /** Intent action that is used to identify the Safety Center resources APK */
- private static final String RESOURCES_APK_ACTION =
- "com.android.safetycenter.intent.action.SAFETY_CENTER_RESOURCES_APK";
-
- /** Permission APEX name */
- private static final String APEX_MODULE_NAME = "com.android.permission";
-
- /**
- * The path where the Permission apex is mounted. Current value = "/apex/com.android.permission"
- */
- private static final String APEX_MODULE_PATH =
- new File("/apex", APEX_MODULE_NAME).getAbsolutePath();
-
- /** Raw XML config resource name */
- private static final String CONFIG_NAME = "safety_center_config";
-
- /** Intent action that is used to identify the Safety Center resources APK */
- private final String mResourcesApkAction;
-
- /** The path where the Safety Center resources APK is expected to be installed */
- @Nullable private final String mResourcesApkPath;
-
- /** Raw XML config resource name */
- private final String mConfigName;
-
- /** Specific flags used for retrieving resolve info */
- private final int mFlags;
-
- /**
- * Whether we should fallback with an empty string when calling {@link #getStringByName} for a
- * string resource that does not exist.
- */
- private final boolean mShouldFallbackIfNamedResourceNotFound;
-
- // Cached package name and resources from the resources APK
- @Nullable private String mResourcesApkPkgName;
- @Nullable private AssetManager mAssetsFromApk;
- @Nullable private Resources mResourcesFromApk;
- @Nullable private Resources.Theme mThemeFromApk;
-
- public SafetyCenterResourcesContext(Context contextBase) {
- this(contextBase, /* shouldFallbackIfNamedResourceNotFound */ true);
- }
-
- private SafetyCenterResourcesContext(
- Context contextBase, boolean shouldFallbackIfNamedResourceNotFound) {
- this(
- contextBase,
- RESOURCES_APK_ACTION,
- APEX_MODULE_PATH,
- CONFIG_NAME,
- PackageManager.MATCH_SYSTEM_ONLY,
- shouldFallbackIfNamedResourceNotFound);
- }
-
- @VisibleForTesting
- SafetyCenterResourcesContext(
- Context contextBase,
- String resourcesApkAction,
- @Nullable String resourcesApkPath,
- String configName,
- int flags,
- boolean shouldFallbackIfNamedResourceNotFound) {
- super(contextBase);
- mResourcesApkAction = requireNonNull(resourcesApkAction);
- mResourcesApkPath = resourcesApkPath;
- mConfigName = requireNonNull(configName);
- mFlags = flags;
- mShouldFallbackIfNamedResourceNotFound = shouldFallbackIfNamedResourceNotFound;
- }
-
- /** Creates a new {@link SafetyCenterResourcesContext} for testing. */
- @VisibleForTesting
- public static SafetyCenterResourcesContext forTests(Context contextBase) {
- return new SafetyCenterResourcesContext(
- contextBase, /* shouldFallbackIfNamedResourceNotFound */ false);
- }
-
- /**
- * Initializes the {@link Context}'s {@link AssetManager}, {@link Resources} and {@link
- * Resources.Theme}.
- *
- * <p>This call is optional as this can also be lazily instantiated. This is useful to ensure
- * that resources are loaded prior to interacting with the {@link SafetyCenterResourcesContext},
- * as this code needs to run for the same user as the provided base {@link Context}; which may
- * not be the case with a binder call.
- */
- public void init() {
- mAssetsFromApk = getAssets();
- mResourcesFromApk = getResources();
- mThemeFromApk = getTheme();
- }
-
- /** Get the package name of the Safety Center resources APK. */
- @VisibleForTesting
- @Nullable
- String getResourcesApkPkgName() {
- if (mResourcesApkPkgName != null) {
- return mResourcesApkPkgName;
- }
-
- List<ResolveInfo> resolveInfos =
- getPackageManager().queryIntentActivities(new Intent(mResourcesApkAction), mFlags);
-
- if (resolveInfos.size() > 1) {
- // multiple apps found, log a warning, but continue
- Log.w(TAG, "Found > 1 APK that can resolve Safety Center resources APK intent:");
- final int resolveInfosSize = resolveInfos.size();
- for (int i = 0; i < resolveInfosSize; i++) {
- ResolveInfo resolveInfo = resolveInfos.get(i);
- Log.w(
- TAG,
- String.format(
- "- pkg:%s at:%s",
- resolveInfo.activityInfo.applicationInfo.packageName,
- resolveInfo.activityInfo.applicationInfo.sourceDir));
- }
- }
-
- ResolveInfo info = null;
- // Assume the first good ResolveInfo is the one we're looking for
- final int resolveInfosSize = resolveInfos.size();
- for (int i = 0; i < resolveInfosSize; i++) {
- ResolveInfo resolveInfo = resolveInfos.get(i);
- if (mResourcesApkPath != null
- && !resolveInfo.activityInfo.applicationInfo.sourceDir.startsWith(
- mResourcesApkPath)) {
- // skip apps that don't live in the Permission apex
- continue;
- }
- info = resolveInfo;
- break;
- }
-
- if (info == null) {
- // Resource APK not loaded yet, print a stack trace to see where this is called from
- Log.e(
- TAG,
- "Attempted to fetch resources before Safety Center resources APK is loaded!",
- new IllegalStateException());
- return null;
- }
-
- mResourcesApkPkgName = info.activityInfo.applicationInfo.packageName;
- Log.i(TAG, "Found Safety Center resources APK at: " + mResourcesApkPkgName);
- return mResourcesApkPkgName;
- }
-
- /**
- * Gets the raw XML resource representing the Safety Center configuration from the Safety Center
- * resources APK.
- */
- @Nullable
- public InputStream getSafetyCenterConfig() {
- String resourcePkgName = getResourcesApkPkgName();
- if (resourcePkgName == null) {
- return null;
- }
- Resources resources = getResources();
- if (resources == null) {
- return null;
- }
- int id = resources.getIdentifier(mConfigName, "raw", resourcePkgName);
- if (id == Resources.ID_NULL) {
- return null;
- }
- return resources.openRawResource(id);
- }
-
- /**
- * Returns an optional {@link String} resource from the given {@code stringId}.
- *
- * <p>Returns {@code null} if {@code stringId} is equal to {@link Resources#ID_NULL}. Otherwise,
- * throws a {@link Resources.NotFoundException} if the resource cannot be accessed.
- */
- @Nullable
- public String getOptionalString(@StringRes int stringId) {
- if (stringId == Resources.ID_NULL) {
- return null;
- }
- return getString(stringId);
- }
-
- /** Same as {@link #getOptionalString(int)} but with the given {@code formatArgs}. */
- @Nullable
- public String getOptionalString(@StringRes int stringId, Object... formatArgs) {
- if (stringId == Resources.ID_NULL) {
- return null;
- }
- return getString(stringId, formatArgs);
- }
-
- /** Same as {@link #getOptionalString(int)} but using the string name rather than ID. */
- @Nullable
- public String getOptionalStringByName(String name) {
- return getOptionalString(getStringRes(name));
- }
-
- /**
- * Gets a string resource by name from the Safety Center resources APK, and returns an empty
- * string if the resource does not exist (or throws a {@link Resources.NotFoundException} if
- * {@link #mShouldFallbackIfNamedResourceNotFound} is {@code false}).
- */
- public String getStringByName(String name) {
- int id = getStringRes(name);
- return maybeFallbackIfNamedResourceIsNull(name, getOptionalString(id));
- }
-
- /** Same as {@link #getStringByName(String)} but with the given {@code formatArgs}. */
- public String getStringByName(String name, Object... formatArgs) {
- int id = getStringRes(name);
- return maybeFallbackIfNamedResourceIsNull(name, getOptionalString(id, formatArgs));
- }
-
- private String maybeFallbackIfNamedResourceIsNull(String name, @Nullable String value) {
- if (value != null) {
- return value;
- }
- if (!mShouldFallbackIfNamedResourceNotFound) {
- throw new Resources.NotFoundException();
- }
- Log.w(TAG, "String resource " + name + " not found");
- return "";
- }
-
- @StringRes
- private int getStringRes(String name) {
- return getResId(name, "string");
- }
-
- private int getResId(String name, String type) {
- String resourcePkgName = getResourcesApkPkgName();
- if (resourcePkgName == null) {
- return Resources.ID_NULL;
- }
- Resources resources = getResources();
- if (resources == null) {
- return Resources.ID_NULL;
- }
- // TODO(b/227738283): profile the performance of this operation and consider adding caching
- // or finding some alternative solution.
- return resources.getIdentifier(name, type, resourcePkgName);
- }
-
- @Nullable
- private Context getResourcesApkContext() {
- String name = getResourcesApkPkgName();
- if (name == null) {
- return null;
- }
- try {
- return createPackageContext(name, 0);
- } catch (PackageManager.NameNotFoundException e) {
- Log.wtf(TAG, "Failed to load resources", e);
- }
- return null;
- }
-
- /** Retrieve assets held in the Safety Center resources APK. */
- @Override
- @Nullable
- public AssetManager getAssets() {
- if (mAssetsFromApk == null) {
- Context resourcesApkContext = getResourcesApkContext();
- if (resourcesApkContext != null) {
- mAssetsFromApk = resourcesApkContext.getAssets();
- }
- }
- return mAssetsFromApk;
- }
-
- /** Retrieve resources held in the Safety Center resources APK. */
- @Override
- @Nullable
- public Resources getResources() {
- if (mResourcesFromApk == null) {
- Context resourcesApkContext = getResourcesApkContext();
- if (resourcesApkContext != null) {
- mResourcesFromApk = resourcesApkContext.getResources();
- }
- }
- return mResourcesFromApk;
- }
-
- /** Retrieve theme held in the Safety Center resources APK. */
- @Override
- @Nullable
- public Resources.Theme getTheme() {
- if (mThemeFromApk == null) {
- Context resourcesApkContext = getResourcesApkContext();
- if (resourcesApkContext != null) {
- mThemeFromApk = resourcesApkContext.getTheme();
- }
- }
- return mThemeFromApk;
- }
-
- /**
- * Gets a drawable resource by name from the Safety Center resources APK. Returns a null
- * drawable if the resource does not exist (or throws a {@link Resources.NotFoundException} if
- * {@link #mShouldFallbackIfNamedResourceNotFound} is {@code false}).
- *
- * @param name the identifier for this drawable resource
- * @param theme the theme used to style the drawable attributes, may be {@code null}
- */
- @Nullable
- public Drawable getDrawableByName(String name, @Nullable Resources.Theme theme) {
- int resId = getResId(name, "drawable");
- if (resId != Resources.ID_NULL) {
- return getResources().getDrawable(resId, theme);
- }
-
- if (!mShouldFallbackIfNamedResourceNotFound) {
- throw new Resources.NotFoundException();
- }
-
- Log.w(TAG, "Drawable resource " + name + " not found");
- return null;
- }
-
- /**
- * Returns an {@link Icon} instance containing a drawable with the given name. If no such
- * drawable exists, returns {@code null} or throws {@link Resources.NotFoundException}.
- */
- @Nullable
- public Icon getIconByDrawableName(String drawableResName) {
- int resId = getResId(drawableResName, "drawable");
- if (resId != Resources.ID_NULL) {
- return Icon.createWithResource(getResourcesApkPkgName(), resId);
- }
-
- if (!mShouldFallbackIfNamedResourceNotFound) {
- throw new Resources.NotFoundException();
- }
-
- Log.w(TAG, "Drawable resource " + drawableResName + " not found");
- return null;
- }
-
- /** Gets a color by resource name */
- @ColorInt
- @Nullable
- public Integer getColorByName(String name) {
- int resId = getResId(name, "color");
- if (resId != Resources.ID_NULL) {
- return getResources().getColor(resId, getTheme());
- }
-
- if (!mShouldFallbackIfNamedResourceNotFound) {
- throw new Resources.NotFoundException();
- }
-
- Log.w(TAG, "Color resource " + name + " not found");
- return null;
- }
-}
diff --git a/SafetyCenter/ResourcesLib/tests/AndroidTest.xml b/SafetyCenter/ResourcesLib/tests/AndroidTest.xml
index 6dcfb0362..e15ecf22a 100644
--- a/SafetyCenter/ResourcesLib/tests/AndroidTest.xml
+++ b/SafetyCenter/ResourcesLib/tests/AndroidTest.xml
@@ -19,7 +19,7 @@
<configuration description="Runs unit tests for the Safety Center ResourcesLib library.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
- <option name="test-tag" value="SafetyCenterConfigTests" />
+ <option name="test-tag" value="SafetyCenterResourcesLibTests" />
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" />
<option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
diff --git a/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/raw/safety_center_config.txt b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/raw/safety_center_config.txt
new file mode 100644
index 000000000..3b1246497
--- /dev/null
+++ b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/raw/safety_center_config.txt
@@ -0,0 +1 @@
+TEST \ No newline at end of file
diff --git a/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesApkTest.kt b/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesApkTest.kt
new file mode 100644
index 000000000..b52595b13
--- /dev/null
+++ b/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesApkTest.kt
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.safetycenter.resources
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import java.lang.IllegalStateException
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SafetyCenterResourcesApkTest {
+ private val context: Context = getApplicationContext()
+
+ @Test
+ fun init_withValidInputs_returnsTrue() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val initialized = resourcesApk.init()
+
+ assertThat(initialized).isTrue()
+ }
+
+ @Test
+ fun init_withWrongAction_returnsFalse() {
+ val resourcesApk = newSafetyCenterResourcesApk(resourcesApkAction = "wrong")
+
+ val initialized = resourcesApk.init()
+
+ assertThat(initialized).isFalse()
+ }
+
+ @Test
+ fun init_withWrongPath_returnsFalse() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkPath = "/apex/com.android.permission")
+
+ val initialized = resourcesApk.init()
+
+ assertThat(initialized).isFalse()
+ }
+
+ @Test
+ fun init_withWrongFlags_returnsFalse() {
+ val resourcesApk = newSafetyCenterResourcesApk(flags = PackageManager.MATCH_SYSTEM_ONLY)
+
+ val initialized = resourcesApk.init()
+
+ assertThat(initialized).isFalse()
+ }
+
+ @Test
+ fun getContext_withValidInputs_returnsResourcesApkContext() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val resourcesApkContext = resourcesApk.context
+
+ assertThat(resourcesApkContext.packageName).isEqualTo(RESOURCES_APK_PKG_NAME)
+ }
+
+ @Test
+ fun getContext_withWrongAction_throws() {
+ val resourcesApk = newSafetyCenterResourcesApk(resourcesApkAction = "wrong")
+
+ assertFailsWith(IllegalStateException::class) { resourcesApk.context }
+ }
+
+ @Test
+ fun getContext_withWrongPath_throws() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkPath = "/apex/com.android.permission")
+
+ assertFailsWith(IllegalStateException::class) { resourcesApk.context }
+ }
+
+ @Test
+ fun getContext_withWrongFlags_throws() {
+ val resourcesApk = newSafetyCenterResourcesApk(flags = PackageManager.MATCH_SYSTEM_ONLY)
+
+ assertFailsWith(IllegalStateException::class) { resourcesApk.context }
+ }
+
+ @Test
+ fun getResources_withValidInputs_returnsResourcesApkContextResources() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val resources = resourcesApk.resources
+
+ assertThat(resources).isEqualTo(resourcesApk.context.resources)
+ }
+
+ @Test
+ fun getResources_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) { resourcesApk.resources }
+ }
+
+ @Test
+ fun getSafetyCenterConfig_withValidInputs_returnsConfigContent() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val config = resourcesApk.safetyCenterConfig
+ val configContent = config?.bufferedReader().use { it?.readText() }
+
+ assertThat(config).isNotNull()
+ assertThat(configContent).isEqualTo(CONFIG_CONTENT)
+ }
+
+ @Test
+ fun getSafetyCenterConfig_anotherValidConfigName_returnsConfigContent() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val config = resourcesApk.getSafetyCenterConfig(CONFIG_NAME)
+ val configContent = config?.bufferedReader().use { it?.readText() }
+
+ assertThat(config).isNotNull()
+ assertThat(configContent).isEqualTo(CONFIG_CONTENT)
+ }
+
+ @Test
+ fun getSafetyCenterConfig_invalidConfigNameWithFallback_returnsNull() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = true)
+
+ assertThat(resourcesApk.getSafetyCenterConfig("wrong")).isNull()
+ }
+
+ @Test
+ fun getSafetyCenterConfig_invalidConfigNameWithoutFallback_throws() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = false)
+
+ assertFailsWith(Resources.NotFoundException::class) {
+ resourcesApk.getSafetyCenterConfig("wrong")
+ }
+ }
+
+ @Test
+ fun getSafetyCenterConfig_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) { resourcesApk.safetyCenterConfig }
+ }
+
+ @Test
+ fun getString_validString_returnsString() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val ok = resourcesApk.getString(android.R.string.ok)
+
+ assertThat(ok).isEqualTo("OK")
+ }
+
+ @Test
+ fun getString_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) {
+ resourcesApk.getString(android.R.string.ok)
+ }
+ }
+
+ @Test
+ fun getStringWithFormatArgs_validString_returnsString() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val ok = resourcesApk.getString(android.R.string.ok, "")
+
+ assertThat(ok).isEqualTo("OK")
+ }
+
+ @Test
+ fun getStringWithFormatArgs_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) {
+ resourcesApk.getString(android.R.string.ok, "")
+ }
+ }
+
+ @Test
+ fun getStringByName_validString_returnsString() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ assertThat(resourcesApk.getStringByName("valid_string")).isEqualTo("I exist!")
+ }
+
+ @Test
+ fun getStringByName_invalidStringWithFallback_returnsEmptyString() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = true)
+
+ assertThat(resourcesApk.getStringByName("invalid_string")).isEqualTo("")
+ }
+
+ @Test
+ fun getStringByName_invalidStringWithoutFallback_throws() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = false)
+
+ assertFailsWith(Resources.NotFoundException::class) {
+ resourcesApk.getStringByName("invalid_string")
+ }
+ }
+
+ @Test
+ fun getStringByName_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) {
+ resourcesApk.getStringByName("valid_string")
+ }
+ }
+
+ @Test
+ fun getStringByNameWithFormatArgs_validString_returnsString() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ assertThat(resourcesApk.getStringByName("valid_string", "")).isEqualTo("I exist!")
+ }
+
+ @Test
+ fun getStringByNameWithFormatArgs_invalidStringWithFallback_returnsEmptyString() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = true)
+
+ assertThat(resourcesApk.getStringByName("invalid_string", "")).isEqualTo("")
+ }
+
+ @Test
+ fun getStringByNameWithFormatArgs_invalidStringWithoutFallback_throws() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = false)
+
+ assertFailsWith(Resources.NotFoundException::class) {
+ resourcesApk.getStringByName("invalid_string", "")
+ }
+ }
+
+ @Test
+ fun getStringByNameWithFormatArgs_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) {
+ resourcesApk.getStringByName("valid_string", "")
+ }
+ }
+
+ @Test
+ fun getOptionalString_validString_returnsString() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val ok = resourcesApk.getOptionalString(android.R.string.ok)
+
+ assertThat(ok).isEqualTo("OK")
+ }
+
+ @Test
+ fun getOptionalString_resourceIdNull_returnsNull() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ val string = resourcesApk.getOptionalString(Resources.ID_NULL)
+
+ assertThat(string).isNull()
+ }
+
+ @Test
+ fun getOptionalString_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) {
+ resourcesApk.getOptionalString(android.R.string.ok)
+ }
+ }
+
+ @Test
+ fun getOptionalStringByName_validString_returnsString() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ assertThat(resourcesApk.getOptionalStringByName("valid_string")).isEqualTo("I exist!")
+ }
+
+ @Test
+ fun getOptionalStringByName_invalidStringWithFallback_returnsNull() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = true)
+
+ assertThat(resourcesApk.getOptionalStringByName("invalid_string")).isNull()
+ }
+
+ @Test
+ fun getOptionalStringByName_invalidStringWithoutFallback_returnsNull() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = false)
+
+ assertThat(resourcesApk.getOptionalStringByName("invalid_string")).isNull()
+ }
+
+ @Test
+ fun getOptionalStringByName_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) {
+ resourcesApk.getOptionalStringByName("valid_string")
+ }
+ }
+
+ @Test
+ fun getDrawableByName_validDrawable_returnsDrawable() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ assertThat(resourcesApk.getDrawableByName("valid_drawable", context.theme)).isNotNull()
+ }
+
+ @Test
+ fun getDrawableByName_invalidDrawableWithFallback_returnsNull() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = true)
+
+ assertThat(resourcesApk.getDrawableByName("invalid_drawable", context.theme)).isNull()
+ }
+
+ @Test
+ fun getDrawableByName_invalidDrawableWithoutFallback_throws() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = false)
+
+ assertFailsWith(Resources.NotFoundException::class) {
+ resourcesApk.getDrawableByName("invalid_drawable", context.theme)
+ }
+ }
+
+ @Test
+ fun getDrawableByName_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) {
+ resourcesApk.getDrawableByName("valid_drawable", context.theme)
+ }
+ }
+
+ @Test
+ fun getIconByDrawableName_validDrawable_returnsIcon() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ assertThat(resourcesApk.getIconByDrawableName("valid_drawable")).isNotNull()
+ }
+
+ @Test
+ fun getIconByDrawableName_invalidDrawableWithFallback_returnsNull() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = true)
+
+ assertThat(resourcesApk.getIconByDrawableName("invalid_drawable")).isNull()
+ }
+
+ @Test
+ fun getIconByDrawableName_invalidDrawableWithoutFallback_throws() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = false)
+
+ assertFailsWith(Resources.NotFoundException::class) {
+ resourcesApk.getIconByDrawableName("invalid_drawable")
+ }
+ }
+
+ @Test
+ fun getIconByDrawableByName_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) {
+ resourcesApk.getIconByDrawableName("valid_drawable")
+ }
+ }
+
+ @Test
+ fun getColorByName_validColor_returnsColor() {
+ val resourcesApk = newSafetyCenterResourcesApk()
+
+ assertThat(resourcesApk.getColorByName("valid_color")).isNotNull()
+ }
+
+ @Test
+ fun getColorByName_invalidColorWithFallback_returnsNull() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = true)
+
+ assertThat(resourcesApk.getColorByName("invalid_color")).isNull()
+ }
+
+ @Test
+ fun getColorByName_invalidColorWithoutFallback_throws() {
+ val resourcesApk = newSafetyCenterResourcesApk(fallback = false)
+
+ assertFailsWith(Resources.NotFoundException::class) {
+ resourcesApk.getColorByName("invalid_color")
+ }
+ }
+
+ @Test
+ fun getColorByName_nullContext_throwsRegardlessOfFallback() {
+ val resourcesApk =
+ newSafetyCenterResourcesApk(resourcesApkAction = "wrong", fallback = true)
+
+ assertFailsWith(IllegalStateException::class) { resourcesApk.getColorByName("valid_color") }
+ }
+
+ private fun newSafetyCenterResourcesApk(
+ resourcesApkAction: String = RESOURCES_APK_ACTION,
+ resourcesApkPath: String = "",
+ flags: Int = 0,
+ fallback: Boolean = false
+ ) = SafetyCenterResourcesApk(context, resourcesApkAction, resourcesApkPath, flags, fallback)
+
+ companion object {
+ const val RESOURCES_APK_ACTION =
+ "com.android.safetycenter.tests.intent.action.SAFETY_CENTER_TEST_RESOURCES_APK"
+ const val RESOURCES_APK_PKG_NAME =
+ "com.android.safetycenter.tests.config.safetycenterresourceslibtestresources"
+ const val CONFIG_NAME = "test"
+ const val CONFIG_CONTENT = "TEST"
+ }
+}
diff --git a/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt b/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt
deleted file mode 100644
index 1a82460d2..000000000
--- a/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.safetycenter.resources
-
-import android.content.Context
-import android.content.pm.PackageManager
-import android.content.res.Resources
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import kotlin.test.assertFailsWith
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class SafetyCenterResourcesContextTest {
- private val context: Context = getApplicationContext()
- private val theme: Resources.Theme? = context.theme
-
- @Test
- fun validDataWithValidInputs() {
- val resourcesContext =
- SafetyCenterResourcesContext(context, RESOURCES_APK_ACTION, null, CONFIG_NAME, 0, false)
-
- assertThat(resourcesContext.resourcesApkPkgName).isEqualTo(RESOURCES_APK_PKG_NAME)
-
- val configContent =
- resourcesContext.safetyCenterConfig?.bufferedReader().use { it?.readText() }
-
- assertThat(configContent).isEqualTo(CONFIG_CONTENT)
- assertThat(resourcesContext.assets).isNotNull()
- assertThat(resourcesContext.resources).isNotNull()
- assertThat(resourcesContext.theme).isNotNull()
- }
-
- @Test
- fun nullDataWithWrongAction() {
- val resourcesContext = createNewResourcesContext(resourcesApkAction = "wrong")
-
- assertThat(resourcesContext.resourcesApkPkgName).isNull()
- assertThat(resourcesContext.safetyCenterConfig).isNull()
- assertThat(resourcesContext.assets).isNull()
- assertThat(resourcesContext.resources).isNull()
- assertThat(resourcesContext.theme).isNull()
- }
-
- @Test
- fun nullDataWithWrongPath() {
- val resourcesContext =
- createNewResourcesContext(resourcesApkPath = "/apex/com.android.permission")
-
- assertThat(resourcesContext.resourcesApkPkgName).isNull()
- assertThat(resourcesContext.safetyCenterConfig).isNull()
- assertThat(resourcesContext.assets).isNull()
- assertThat(resourcesContext.resources).isNull()
- assertThat(resourcesContext.theme).isNull()
- }
-
- @Test
- fun nullDataWithWrongFlag() {
- val resourcesContext = createNewResourcesContext(flags = PackageManager.MATCH_SYSTEM_ONLY)
-
- assertThat(resourcesContext.resourcesApkPkgName).isNull()
- assertThat(resourcesContext.safetyCenterConfig).isNull()
- assertThat(resourcesContext.assets).isNull()
- assertThat(resourcesContext.resources).isNull()
- assertThat(resourcesContext.theme).isNull()
- }
-
- @Test
- fun nullConfigWithWrongConfigName() {
- val resourcesContext = createNewResourcesContext(configName = "wrong")
-
- assertThat(resourcesContext.resourcesApkPkgName).isNotNull()
- assertThat(resourcesContext.safetyCenterConfig).isNull()
- assertThat(resourcesContext.assets).isNotNull()
- assertThat(resourcesContext.resources).isNotNull()
- assertThat(resourcesContext.theme).isNotNull()
- }
-
- @Test
- fun getStringByName_validString_returnsString() {
- val resourcesContext = createNewResourcesContext()
-
- assertThat(resourcesContext.getStringByName("valid_string")).isEqualTo("I exist!")
- }
-
- @Test
- fun getStringByName_invalidStringWithFallback_returnsEmptyString() {
- val resourcesContext = createNewResourcesContext(fallback = true)
-
- assertThat(resourcesContext.getStringByName("invalid_string")).isEqualTo("")
- }
-
- @Test
- fun getStringByName_invalidStringWithoutFallback_throws() {
- val resourcesContext = createNewResourcesContext(fallback = false)
-
- assertFailsWith(Resources.NotFoundException::class) {
- resourcesContext.getStringByName("invalid_string")
- }
- }
-
- @Test
- fun getOptionalStringByName_validString_returnsString() {
- val resourcesContext = createNewResourcesContext()
-
- assertThat(resourcesContext.getOptionalStringByName("valid_string")).isEqualTo("I exist!")
- }
-
- @Test
- fun getOptionalStringByName_invalidStringWithFallback_returnsNull() {
- val resourcesContext = createNewResourcesContext(fallback = true)
-
- assertThat(resourcesContext.getOptionalStringByName("invalid_string")).isNull()
- }
-
- @Test
- fun getOptionalStringByName_invalidStringWithoutFallback_returnsNull() {
- val resourcesContext = createNewResourcesContext(fallback = false)
-
- assertThat(resourcesContext.getOptionalStringByName("invalid_string")).isNull()
- }
-
- @Test
- fun getDrawableByName_validDrawable_returnsDrawable() {
- val resourcesContext = createNewResourcesContext()
-
- assertThat(resourcesContext.getDrawableByName("valid_drawable", theme)).isNotNull()
- }
-
- @Test
- fun getDrawableByName_invalidDrawableWithFallback_returnsNull() {
- val resourcesContext = createNewResourcesContext(fallback = true)
-
- assertThat(resourcesContext.getDrawableByName("invalid_drawable", theme)).isNull()
- }
-
- @Test
- fun getDrawableByName_invalidDrawableWithoutFallback_throws() {
- val resourcesContext = createNewResourcesContext(fallback = false)
-
- assertFailsWith(Resources.NotFoundException::class) {
- resourcesContext.getDrawableByName("invalid_drawable", theme)
- }
- }
-
- @Test
- fun getIconByDrawableName_validDrawable_returnsIcon() {
- val resourcesContext = createNewResourcesContext()
-
- assertThat(resourcesContext.getIconByDrawableName("valid_drawable")).isNotNull()
- }
-
- @Test
- fun getIconByDrawableName_invalidDrawableWithFallback_returnsNull() {
- val resourcesContext = createNewResourcesContext(fallback = true)
-
- assertThat(resourcesContext.getIconByDrawableName("invalid_drawable")).isNull()
- }
-
- @Test
- fun getIconByDrawableName_invalidDrawableWithoutFallback_throws() {
- val resourcesContext = createNewResourcesContext(fallback = false)
-
- assertFailsWith(Resources.NotFoundException::class) {
- resourcesContext.getIconByDrawableName("invalid_drawable")
- }
- }
-
- @Test
- fun getColorByName_validColor_returnsColor() {
- val resourcesContext = createNewResourcesContext()
-
- assertThat(resourcesContext.getColorByName("valid_color")).isNotNull()
- }
-
- @Test
- fun getColorByName_invalidColorWithFallback_returnsNull() {
- val resourcesContext = createNewResourcesContext(fallback = true)
-
- assertThat(resourcesContext.getColorByName("invalid_color")).isNull()
- }
-
- @Test
- fun getColorByName_invalidColorWithoutFallback_throws() {
- val resourcesContext = createNewResourcesContext(fallback = false)
-
- assertFailsWith(Resources.NotFoundException::class) {
- resourcesContext.getColorByName("invalid_color")
- }
- }
-
- private fun createNewResourcesContext(
- resourcesApkAction: String = RESOURCES_APK_ACTION,
- resourcesApkPath: String? = null,
- configName: String = CONFIG_NAME,
- flags: Int = 0,
- fallback: Boolean = false
- ) =
- SafetyCenterResourcesContext(
- context, resourcesApkAction, resourcesApkPath, configName, flags, fallback)
-
- companion object {
- const val RESOURCES_APK_ACTION =
- "com.android.safetycenter.tests.intent.action.SAFETY_CENTER_TEST_RESOURCES_APK"
- const val RESOURCES_APK_PKG_NAME =
- "com.android.safetycenter.tests.config.safetycenterresourceslibtestresources"
- const val CONFIG_NAME = "test"
- const val CONFIG_CONTENT = "TEST"
- }
-}
diff --git a/SafetyCenter/TEST_MAPPING b/SafetyCenter/TEST_MAPPING
index 5bc6abbc7..92397fe71 100644
--- a/SafetyCenter/TEST_MAPPING
+++ b/SafetyCenter/TEST_MAPPING
@@ -10,7 +10,13 @@
"path": "packages/modules/Permission/tests/functional/safetycenter/safetycenteractivity/"
},
{
+ "path": "packages/modules/Permission/tests/functional/safetycenter/subpages/"
+ },
+ {
"path": "packages/modules/Permission/tests/functional/safetycenter/singleuser/"
+ },
+ {
+ "path": "packages/modules/Permission/tests/hostside/safetycenter/"
}
]
}
diff --git a/TEST_MAPPING b/TEST_MAPPING
index aa594e81e..689cd6865 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -6,7 +6,67 @@
],
"carpermission-presubmit" : [
{
- "name" : "CtsPermission3TestCases"
+ "name" : "CtsPermissionUiTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "carpermission-postsubmit" : [
+ {
+ "name" : "CtsPermissionUiTestCases",
+ "options": [
+ {
+ "include-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "alltests" : [
+ {
+ "name" : "PermissionControllerMockingTests"
+ },
+ {
+ "name" : "CtsPermissionTestCases"
+ },
+ {
+ "name" : "CtsPermissionUiTestCases"
+ },
+ {
+ "name" : "CtsPermissionPolicyTestCases"
+ },
+ {
+ "name" : "CtsAppOpsTestCases"
+ },
+ {
+ "name" : "CtsAppOps2TestCases"
+ },
+ {
+ "name": "PermissionControllerOutOfProcessTests"
+ },
+ {
+ "name" : "CtsRoleTestCases"
+ },
+ {
+ "name" : "CtsPermissionMultiUserTestCases"
+ },
+ {
+ "name": "CtsBackupTestCases",
+ "options": [
+ {
+ "include-filter": "android.backup.cts.PermissionTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsDevicePolicyManagerTestCases",
+ "options": [
+ {
+ "include-annotation": "com.android.cts.devicepolicy.annotations.PermissionsTest"
+ }
+ ]
}
]
}
diff --git a/flags/Android.bp b/flags/Android.bp
new file mode 100644
index 000000000..4f0241f91
--- /dev/null
+++ b/flags/Android.bp
@@ -0,0 +1,65 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aconfig_declarations {
+ name: "permissions-aconfig-flags",
+ package: "com.android.permission.flags",
+ srcs: ["flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "permissions-aconfig-flags-lib",
+ aconfig_declarations: "permissions-aconfig-flags",
+ sdk_version: "system_current",
+ min_sdk_version: "30",
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ ],
+}
+
+java_library {
+ name: "permissions-flags-lib",
+ sdk_version: "system_current",
+ min_sdk_version: "30",
+ target_sdk_version: "34",
+ srcs: [
+ "java/**/*.java",
+ ],
+ static_libs: [
+ "permissions-aconfig-flags-lib",
+ ],
+ libs: [
+ "androidx.annotation_annotation",
+ "framework-annotations-lib",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ ],
+} \ No newline at end of file
diff --git a/flags/flags.aconfig b/flags/flags.aconfig
new file mode 100644
index 000000000..49b086b2b
--- /dev/null
+++ b/flags/flags.aconfig
@@ -0,0 +1,29 @@
+package: "com.android.permission.flags"
+
+flag {
+ name: "voice_activation_op_enabled"
+ namespace: "permissions"
+ description: "This flag is used to support hotword activation events in privacy dashboard"
+ bug: "287264308"
+}
+
+flag {
+ name: "device_aware_permission_grant"
+ namespace: "permissions"
+ description: "Enables device aware grant permission flow"
+ bug: "292252664"
+}
+
+flag {
+ name: "wear_privacy_dashboard_enabled"
+ namespace: "wear_security"
+ description: "This flag is used to support Privacy dashboard for Wear"
+ bug: "309721061"
+}
+
+flag {
+ name: "archiving"
+ namespace: "permissions"
+ description: "Feature flag to enable the archiving feature."
+ bug: "278553670"
+} \ No newline at end of file
diff --git a/flags/java/com/android/permission/flags/PermissionsFlags.java b/flags/java/com/android/permission/flags/PermissionsFlags.java
new file mode 100644
index 000000000..afab3fae5
--- /dev/null
+++ b/flags/java/com/android/permission/flags/PermissionsFlags.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 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.permission.flags;
+
+/** Class used for flags that do not work with aconfig tooling */
+public final class PermissionsFlags {}
diff --git a/framework-s/Android.bp b/framework-s/Android.bp
index 893f000a8..961ae4425 100644
--- a/framework-s/Android.bp
+++ b/framework-s/Android.bp
@@ -59,6 +59,11 @@ java_library {
},
}
+platform_compat_config {
+ name: "framework-permission-s-compat-config",
+ src: ":framework-permission-s",
+}
+
java_sdk_library {
name: "framework-permission-s",
defaults: ["framework-module-defaults"],
@@ -67,11 +72,13 @@ java_sdk_library {
],
libs: [
"androidx.annotation_annotation",
+ "app-compat-annotations",
"framework-annotations-lib",
],
static_libs: [
"framework-permission-s-shared",
"modules-utils-build",
+ "android.permission.flags-aconfig-java",
],
apex_available: [
"com.android.permission",
@@ -87,12 +94,13 @@ java_sdk_library {
jarjar_rules: "jarjar-rules.txt",
lint: {
strict_updatability_linting: true,
- baseline_filename: "lint-baseline.xml",
+
},
min_sdk_version: "31",
permitted_packages: [
"android.permission",
"android.app.role",
+ "android.app.ecm",
"android.safetycenter",
"android.safetylabel",
],
diff --git a/framework-s/api/current.txt b/framework-s/api/current.txt
index d54af92f5..d943a03a1 100644
--- a/framework-s/api/current.txt
+++ b/framework-s/api/current.txt
@@ -14,6 +14,7 @@ package android.app.role {
field public static final String ROLE_HOME = "android.app.role.HOME";
field public static final String ROLE_NOTES = "android.app.role.NOTES";
field public static final String ROLE_SMS = "android.app.role.SMS";
+ field @FlaggedApi("android.permission.flags.wallet_role_enabled") public static final String ROLE_WALLET = "android.app.role.WALLET";
}
}
diff --git a/framework-s/api/module-lib-current.txt b/framework-s/api/module-lib-current.txt
index 80f1cde45..14f71782e 100644
--- a/framework-s/api/module-lib-current.txt
+++ b/framework-s/api/module-lib-current.txt
@@ -1,4 +1,12 @@
// Signature format: 2.0
+package android.app.ecm {
+
+ @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") public class EnhancedConfirmationFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ }
+
+}
+
package android.app.role {
public class RoleFrameworkInitializer {
diff --git a/framework-s/api/module-lib-lint-baseline.txt b/framework-s/api/module-lib-lint-baseline.txt
new file mode 100644
index 000000000..1445d9814
--- /dev/null
+++ b/framework-s/api/module-lib-lint-baseline.txt
@@ -0,0 +1,39 @@
+// Baseline format: 1.0
+BroadcastBehavior: android.safetycenter.SafetyCenterManager#ACTION_REFRESH_SAFETY_SOURCES:
+ Field 'ACTION_REFRESH_SAFETY_SOURCES' is missing @BroadcastBehavior
+BroadcastBehavior: android.safetycenter.SafetyCenterManager#ACTION_SAFETY_CENTER_ENABLED_CHANGED:
+ Field 'ACTION_SAFETY_CENTER_ENABLED_CHANGED' is missing @BroadcastBehavior
+
+
+MissingPermission: android.app.role.RoleManager#addRoleHolderFromController(String, String):
+ Permission PERMISSION_MANAGE_ROLES_FROM_CONTROLLER required by method android.app.role.RoleManager.addRoleHolderFromController(String, String) is hidden or removed
+MissingPermission: android.app.role.RoleManager#getHeldRolesFromController(String):
+ Permission PERMISSION_MANAGE_ROLES_FROM_CONTROLLER required by method android.app.role.RoleManager.getHeldRolesFromController(String) is hidden or removed
+MissingPermission: android.app.role.RoleManager#removeRoleHolderFromController(String, String):
+ Permission PERMISSION_MANAGE_ROLES_FROM_CONTROLLER required by method android.app.role.RoleManager.removeRoleHolderFromController(String, String) is hidden or removed
+MissingPermission: android.app.role.RoleManager#setRoleNamesFromController(java.util.List<java.lang.String>):
+ Permission PERMISSION_MANAGE_ROLES_FROM_CONTROLLER required by method android.app.role.RoleManager.setRoleNamesFromController(java.util.List<java.lang.String>) is hidden or removed
+
+
+RequiresPermission: android.app.role.RoleManager#addOnRoleHoldersChangedListenerAsUser(java.util.concurrent.Executor, android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+ Method 'addOnRoleHoldersChangedListenerAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#addRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+ Method 'addRoleHolderAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#addRoleHolderFromController(String, String):
+ Method 'addRoleHolderFromController' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#clearRoleHoldersAsUser(String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+ Method 'clearRoleHoldersAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#getRoleHolders(String):
+ Method 'getRoleHolders' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#getRoleHoldersAsUser(String, android.os.UserHandle):
+ Method 'getRoleHoldersAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#removeOnRoleHoldersChangedListenerAsUser(android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+ Method 'removeOnRoleHoldersChangedListenerAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+ Method 'removeRoleHolderAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#removeRoleHolderFromController(String, String):
+ Method 'removeRoleHolderFromController' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#setBrowserRoleHolder(String, int):
+ Method 'setBrowserRoleHolder' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#setRoleNamesFromController(java.util.List<java.lang.String>):
+ Method 'setRoleNamesFromController' documentation mentions permissions already declared by @RequiresPermission
diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt
index 9545356a4..e8d1b8992 100644
--- a/framework-s/api/system-current.txt
+++ b/framework-s/api/system-current.txt
@@ -1,4 +1,15 @@
// Signature format: 2.0
+package android.app.ecm {
+
+ @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") public final class EnhancedConfirmationManager {
+ method public void clearRestriction(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public android.app.PendingIntent getRestrictedSettingDialogIntent(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public boolean isClearRestrictionAllowed(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public boolean isRestricted(@NonNull String, @NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ }
+
+}
+
package android.app.role {
public interface OnRoleHoldersChangedListener {
@@ -10,6 +21,7 @@ package android.app.role {
method @Deprecated @WorkerThread public abstract boolean onAddRoleHolder(@NonNull String, @NonNull String, int);
method @Deprecated @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
method @Deprecated @WorkerThread public abstract boolean onClearRoleHolders(@NonNull String, int);
+ method @Deprecated @FlaggedApi("android.permission.flags.system_server_role_controller_enabled") @NonNull public java.util.List<java.lang.String> onGetLegacyFallbackDisabledRoles();
method @Deprecated @WorkerThread public abstract boolean onGrantDefaultRoles();
method @Deprecated public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String);
method @Deprecated public boolean onIsApplicationVisibleForRole(@NonNull String, @NonNull String);
@@ -29,12 +41,14 @@ package android.app.role {
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean isBypassingRoleQualification();
+ method @FlaggedApi("android.permission.flags.system_server_role_controller_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean isRoleFallbackEnabled(@NonNull String);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.BYPASS_ROLE_QUALIFICATION) public void setBypassingRoleQualification(boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_DEFAULT_APPLICATIONS) public void setDefaultApplication(@NonNull String, @Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @FlaggedApi("android.permission.flags.system_server_role_controller_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void setRoleFallbackEnabled(@NonNull String, boolean);
method @Deprecated @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
field public static final String ROLE_DEVICE_POLICY_MANAGEMENT = "android.app.role.DEVICE_POLICY_MANAGEMENT";
diff --git a/framework-s/api/system-lint-baseline.txt b/framework-s/api/system-lint-baseline.txt
new file mode 100644
index 000000000..5bf9a0a11
--- /dev/null
+++ b/framework-s/api/system-lint-baseline.txt
@@ -0,0 +1,37 @@
+// Baseline format: 1.0
+BroadcastBehavior: android.safetycenter.SafetyCenterManager#ACTION_REFRESH_SAFETY_SOURCES:
+ Field 'ACTION_REFRESH_SAFETY_SOURCES' is missing @BroadcastBehavior
+BroadcastBehavior: android.safetycenter.SafetyCenterManager#ACTION_SAFETY_CENTER_ENABLED_CHANGED:
+ Field 'ACTION_SAFETY_CENTER_ENABLED_CHANGED' is missing @BroadcastBehavior
+
+
+MissingPermission: android.app.role.RoleManager#addRoleHolderFromController(String, String):
+ Permission PERMISSION_MANAGE_ROLES_FROM_CONTROLLER required by method android.app.role.RoleManager.addRoleHolderFromController(String, String) is hidden or removed
+MissingPermission: android.app.role.RoleManager#getHeldRolesFromController(String):
+ Permission PERMISSION_MANAGE_ROLES_FROM_CONTROLLER required by method android.app.role.RoleManager.getHeldRolesFromController(String) is hidden or removed
+MissingPermission: android.app.role.RoleManager#removeRoleHolderFromController(String, String):
+ Permission PERMISSION_MANAGE_ROLES_FROM_CONTROLLER required by method android.app.role.RoleManager.removeRoleHolderFromController(String, String) is hidden or removed
+MissingPermission: android.app.role.RoleManager#setRoleNamesFromController(java.util.List<java.lang.String>):
+ Permission PERMISSION_MANAGE_ROLES_FROM_CONTROLLER required by method android.app.role.RoleManager.setRoleNamesFromController(java.util.List<java.lang.String>) is hidden or removed
+
+
+RequiresPermission: android.app.role.RoleManager#addOnRoleHoldersChangedListenerAsUser(java.util.concurrent.Executor, android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+ Method 'addOnRoleHoldersChangedListenerAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#addRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+ Method 'addRoleHolderAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#addRoleHolderFromController(String, String):
+ Method 'addRoleHolderFromController' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#clearRoleHoldersAsUser(String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+ Method 'clearRoleHoldersAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#getRoleHolders(String):
+ Method 'getRoleHolders' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#getRoleHoldersAsUser(String, android.os.UserHandle):
+ Method 'getRoleHoldersAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#removeOnRoleHoldersChangedListenerAsUser(android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+ Method 'removeOnRoleHoldersChangedListenerAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+ Method 'removeRoleHolderAsUser' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#removeRoleHolderFromController(String, String):
+ Method 'removeRoleHolderFromController' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.app.role.RoleManager#setRoleNamesFromController(java.util.List<java.lang.String>):
+ Method 'setRoleNamesFromController' documentation mentions permissions already declared by @RequiresPermission
diff --git a/framework-s/jarjar-rules.txt b/framework-s/jarjar-rules.txt
index 3b888fe99..39f2ad3b7 100644
--- a/framework-s/jarjar-rules.txt
+++ b/framework-s/jarjar-rules.txt
@@ -1,4 +1,5 @@
rule android.os.HandlerExecutor android.permission.jarjar.@0
+rule android.permission.flags.** android.permission.jarjar.@0
rule android.util.IndentingPrintWriter android.permission.jarjar.@0
rule com.android.internal.** android.permission.jarjar.@0
rule com.android.modules.** android.permission.jarjar.@0
diff --git a/framework-s/java/android/app/ecm/EnhancedConfirmationFrameworkInitializer.java b/framework-s/java/android/app/ecm/EnhancedConfirmationFrameworkInitializer.java
new file mode 100644
index 000000000..b4c18573a
--- /dev/null
+++ b/framework-s/java/android/app/ecm/EnhancedConfirmationFrameworkInitializer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.ecm;
+
+import android.annotation.FlaggedApi;
+import android.annotation.SystemApi;
+import android.annotation.TargetApi;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+import android.os.Build;
+import android.permission.flags.Flags;
+
+/**
+ * Class holding initialization code for enhanced confirmation code in the permission module.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED)
+@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public class EnhancedConfirmationFrameworkInitializer {
+ private EnhancedConfirmationFrameworkInitializer() {}
+
+ /**
+ * Called by {@link SystemServiceRegistry}'s static initializer and registers
+ * {@link EnhancedConfirmationManager} to {@link Context}, so that
+ * {@link Context#getSystemService} can return it.
+ *
+ * <p>If this is called from other places, it throws a {@link IllegalStateException}.
+ */
+ public static void registerServiceWrappers() {
+ SystemServiceRegistry.registerContextAwareService(Context.ECM_ENHANCED_CONFIRMATION_SERVICE,
+ EnhancedConfirmationManager.class,
+ (context) -> new EnhancedConfirmationManager(context));
+ }
+}
diff --git a/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java b/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java
new file mode 100644
index 000000000..23dc10c71
--- /dev/null
+++ b/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.ecm;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.annotation.TargetApi;
+import android.app.AppOpsManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.InstallSourceInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.os.UserHandle;
+import android.permission.flags.Flags;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+
+/**
+ * This class provides the core API for ECM (Enhanced Confirmation Mode). ECM is a feature that
+ * restricts access to protected **settings** (i.e., sensitive resources) by restricted **apps**
+ * (apps from from dangerous sources, such as sideloaded packages or packages downloaded from a web
+ * browser).
+ *
+ * <p>Specifically, this class provides the ability to:
+ *
+ * <ol>
+ * <li>Check whether a setting is restricted from an app ({@link #isRestricted})
+ * <li>Get an intent that will open the "Restricted setting" dialog ({@link
+ * #getRestrictedSettingDialogIntent}) (a dialog that informs the user that the operation
+ * they've attempted to perform is restricted)
+ * <li>Check whether an app is eligible to have its restriction status cleared ({@link
+ * #isClearRestrictionAllowed})
+ * <li>Clear an app's restriction status (i.e., un-restrict it). ({@link #clearRestriction})
+ * </ol>
+ *
+ * <p>Methods of this class will generally accept an app (identified by a packageName and a user)
+ * and a "setting" (a string representing the "sensitive resource") as arguments. ECM's exact
+ * behavior will generally depend on what restriction state ECM considers each setting and app. For
+ * example:
+ *
+ * <ol>
+ * <li>A setting may be considered by ECM to be either **protected** or **not protected**. In
+ * general, this should be considered hardcoded into ECM's implementation: nothing can
+ * "protect" or "unprotect" a setting.
+ * <li>An app may be considered as being **not restricted** or **restricted**. A restricted app
+ * will be restricted from accessing all protected settings. Whether ECM considers any
+ * particular app restricted is an implementation detail of ECM. However, the user is able to
+ * clear any restricted app's restriction status (i.e, un-restrict it), after which ECM will
+ * consider the app **not restricted**.
+ * </ol>
+ *
+ * Why is ECM needed? Consider the following (pre-ECM) scenario:
+ *
+ * <ol>
+ * <li>The user downloads and installs an apk file from a browser.
+ * <li>The user opens Settings -> Accessibility
+ * <li>The user tries to register the app as an accessibility service.
+ * <li>The user is shown a permission prompt "Allow _ to have full control of your device?"
+ * <li>The user clicks "Allow"
+ * <li>The downloaded app now has full control of the device.
+ * </ol>
+ *
+ * The purpose of ECM is to add more friction to this scenario.
+ *
+ * <p>With ECM, this scenario becomes:
+ *
+ * <ol>
+ * <li>The user downloads and installs an apk file from a browser.
+ * <li>The user goes into Settings -> Accessibility.
+ * <li>The user tries to register the app as an accessibility service.
+ * <li>The user is presented with a "Restricted setting" dialog explaining that the attempted
+ * action has been restricted. (No "allow" button is shown, but a link is given to a screen
+ * with intentionally-obscure instructions on how to proceed.)
+ * <li>The user must now navigate to Settings -> Apps -> [app]
+ * <li>The user then must click on "..." (top-right corner hamburger menu), then click "Allow
+ * restricted settings"
+ * <li>The user goes (again) into Settings -> Accessibility and (again) tries to register the app
+ * as an accessibility service.
+ * <li>The user is shown a permission prompt "Allow _ to have full control of your device?"
+ * <li>The user clicks "Allow"
+ * <li>The downloaded app now has full control of the device.
+ * </ol>
+ *
+ * And, expanding on the above scenario, the role that this class plays is as follows:
+ *
+ * <ol>
+ * <li>The user downloads and installs an apk file from a browser.
+ * <li>The user goes into Settings -> Accessibility.
+ * <p>**This screen then calls {@link #isRestricted}, which checks whether each app listed
+ * on-screen is restricted from the accessibility service setting. It uses this to visually
+ * "gray out" restricted apps.**
+ * <li>The user tries to register the app as an accessibility service.
+ * <p>**This screen then calls {@link #getRestrictedSettingDialogIntent} and starts the
+ * intent. This opens the "Restricted setting" dialog.**
+ * <li>The user is presented with a "Restricted setting" dialog explaining that the attempted
+ * action is restricted. (No "allow" button is shown, but a link is given to a screen with
+ * intentionally-obscure instructions on how to proceed.)
+ * <p>**Upon opening, this dialog marks the app as eligible to have its restriction status
+ * cleared.**
+ * <li>The user must now navigate to Settings -> Apps -> [app].
+ * <p>**This screen calls {@link #isClearRestrictionAllowed} to check whether the app is
+ * eligible to have its restriction status cleared. If this returns {@code true}, this screen
+ * should then show a "Allow restricted setting" button inside the top-right hamburger menu.**
+ * <li>The user then must click on "..." (top-right corner hamburger menu), then click "Allow
+ * restricted settings".
+ * <p>**In response, this screen should now call {@link #clearRestriction}.**
+ * <li>The user goes (again) into Settings -> Accessibility and (again) tries to register the app
+ * as an accessibility service.
+ * <li>The user is shown a permission prompt "Allow _ to have full control of your device?"
+ * <li>The user clicks "Allow"
+ * <li>The downloaded app now has full control of the device.
+ * </ol>
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED)
+@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SystemService(Context.ECM_ENHANCED_CONFIRMATION_SERVICE)
+public final class EnhancedConfirmationManager {
+ /*
+ * At the API level, we use the following terminology:
+ *
+ * - The capability of an app to access a setting may be considered (by ECM) to be *restricted*
+ * or *not restricted*.
+ * - A setting may be considered (by ECM) to be *protected* or *not protected*.
+ * - The state of an app may be considered (by ECM) to be *restricted* or *not restricted*
+ *
+ * In this implementation, however, the state of an app is considered either **guarded** or
+ * **not guarded**; these terms can generally be considered synonymous with **restricted** and
+ * **not restricted**. (Keeping in mind that, the capability of any app to access any
+ * non-protected setting will always be considered "not restricted", even if the state of the
+ * app is considered "restricted".). An app can also be in a third state: **guarded and
+ * acknowledged**, which corresponds with an app that is restricted and is eligible to have its
+ * restriction status cleared.
+ *
+ * Currently, the ECM state of any given app is stored in the OP_ACCESS_RESTRICTED_SETTINGS
+ * appop (though this may change in the future):
+ *
+ * - MODE_ALLOWED means the app is explicitly **not guarded**. (U- default)
+ * - MODE_ERRORED means the app is explicitly **guarded**. (Only settable in U-.)
+ * - MODE_IGNORED means the app is explicitly **guarded and acknowledged**. (An app enters this
+ * state as soon as the "Restricted setting" dialog has been shown to the user. If an app is
+ * in this state, Settings is now allowed to provide the user with the option to clear the
+ * restriction.)
+ * - MODE_DEFAULT means the app's ECM state should be decided lazily. (V+ default) (That is,
+ * each time a caller checks whether or not an app is considered guarded by ECM, we'll run an
+ * heuristic to determine this.)
+ *
+ * Some notes on compatibility:
+ *
+ * - On U-, MODE_ALLOWED is the default mode of OP_ACCESS_RESTRICTED_SETTINGS. On both U- and
+ * V+, this is also the mode after the app's restriction has been cleared.
+ * - In U-, the mode needed to be explicitly set (for example, by a browser that allows a
+ * dangerous app to be installed) to MODE_ERRORED to indicate that an app is guarded. In V+,
+ * we no longer allow an app to be placed into MODE_ERRORED, but for compatibility, we still
+ * recognize MODE_ERRORED to indicate that an app is explicitly guarded.
+ * - In V+, the default mode is MODE_DEFAULT. Unlike U-, this potentially affects *all* apps,
+ * not just the ones which have been explicitly marked as **guarded**.
+ *
+ * Regarding ECM "setting"s: a setting may be any abstract resource identified by a string. ECM
+ * may consider any particular setting **protected** or **not protected**. For now, the set of
+ * protected settings is hardcoded, but this may evolve in the future.
+ *
+ * TODO(b/320512579): These methods currently enforce UPDATE_APP_OPS_STATS,
+ * UPDATE_APP_OPS_STATS, and, for setter methods, MANAGE_APP_OPS_MODES. We should add
+ * RequiresPermission annotations, but we can't, because some of these permissions are hidden
+ * API. Either upgrade these to SystemApi or enforce a different permission, then add the
+ * appropriate RequiresPermission annotation.
+ */
+
+ /** A map of ECM states to their corresponding app op states */
+ @Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"ECM_STATE_"}, value = {EcmState.ECM_STATE_NOT_GUARDED,
+ EcmState.ECM_STATE_GUARDED, EcmState.ECM_STATE_GUARDED_AND_ACKNOWLEDGED,
+ EcmState.ECM_STATE_IMPLICIT})
+ private @interface EcmState {
+ int ECM_STATE_NOT_GUARDED = AppOpsManager.MODE_ALLOWED;
+ int ECM_STATE_GUARDED = AppOpsManager.MODE_ERRORED;
+ int ECM_STATE_GUARDED_AND_ACKNOWLEDGED = AppOpsManager.MODE_IGNORED;
+ int ECM_STATE_IMPLICIT = AppOpsManager.MODE_DEFAULT;
+ }
+
+ private static final String LOG_TAG = EnhancedConfirmationManager.class.getSimpleName();
+
+ private static final ArraySet<String> PROTECTED_SETTINGS = new ArraySet<>();
+
+ static {
+ PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE);
+ // TODO(b/310654015): Add other explicitly protected settings
+ }
+
+ private final @NonNull Context mContext;
+ private final String mAttributionTag;
+ private final @NonNull UserHandle mUser;
+ private final AppOpsManager mAppOpsManager;
+ private final PackageManager mPackageManager;
+
+ /**
+ * @hide
+ */
+ public EnhancedConfirmationManager(@NonNull Context context) {
+ mContext = context;
+ mAttributionTag = context.getAttributionTag();
+ mUser = context.getUser();
+ mAppOpsManager = context.getSystemService(AppOpsManager.class);
+ mPackageManager = context.getPackageManager();
+ }
+
+ /**
+ * Check whether a setting is restricted from an app.
+ *
+ * <p>This is {@code true} when the setting is a protected setting (i.e., a sensitive resource),
+ * and the app is restricted (i.e., considered dangerous), and the user has not yet cleared the
+ * app's restriction status (i.e., by clicking "Allow restricted settings" for this app).
+ *
+ * @param packageName package name of the application to check for
+ * @param settingIdentifier identifier of the resource to check to check for
+ * @return {@code true} if the setting is restricted from the app
+ * @throws NameNotFoundException if the provided package was not found
+ */
+ public boolean isRestricted(@NonNull String packageName, @NonNull String settingIdentifier)
+ throws NameNotFoundException {
+ return isSettingEcmProtected(settingIdentifier) && isPackageEcmGuarded(packageName);
+ }
+
+ /**
+ * Clear an app's restriction status (i.e., un-restrict it).
+ *
+ * <p>After this is called, the app will no longer be restricted from accessing any protected
+ * setting by ECM. This method should be called when the user clicks "Allow restricted settings"
+ * for the app.
+ *
+ * @param packageName package name of the application to remove protection from
+ * @throws NameNotFoundException if the provided package was not found
+ */
+ public void clearRestriction(@NonNull String packageName) throws NameNotFoundException {
+ if (!isClearRestrictionAllowed(packageName)) {
+ throw new IllegalStateException("Clear restriction attempted but not allowed");
+ }
+ setAppEcmState(packageName, EcmState.ECM_STATE_NOT_GUARDED);
+ }
+
+ /**
+ * Check whether the provided app is eligible to have its restriction status cleared (i.e., the
+ * app is restricted, and the "Restricted setting" dialog has been presented to the user).
+ *
+ * <p>The Settings UI should use method this to check whether to present the user with the
+ * "Allow restricted settings" button.
+ *
+ * @param packageName package name of the application to check for
+ * @return {@code true} if the settings UI should present the user with the ability to clear
+ * restrictions from the provided app
+ * @throws NameNotFoundException if the provided package was not found
+ */
+ public boolean isClearRestrictionAllowed(@NonNull String packageName)
+ throws NameNotFoundException {
+ int state = getAppEcmState(packageName);
+ return state == EcmState.ECM_STATE_GUARDED_AND_ACKNOWLEDGED;
+ }
+
+ /**
+ * Mark the app as eligible to have its restriction status cleared.
+ *
+ * <p>This should be called from the "Restricted setting" dialog (which {@link
+ * #getRestrictedSettingDialogIntent} directs to) upon being presented to the user.
+ *
+ * @param packageName package name of the application which should be considered acknowledged
+ * @throws NameNotFoundException if the provided package was not found
+ *
+ * @hide
+ */
+ public void setClearRestrictionAllowed(@NonNull String packageName)
+ throws NameNotFoundException {
+ if (isPackageEcmGuarded(packageName)) {
+ setAppEcmState(packageName, EcmState.ECM_STATE_GUARDED_AND_ACKNOWLEDGED);
+ }
+ }
+
+ /**
+ * Gets an intent that will open the "Restricted setting" dialog for the specified app.
+ *
+ * <p>The "Restricted setting" dialog is a dialog that informs the user that the operation
+ * they've attempted to perform is restricted, and provides them with a link explaining how to
+ * proceed.
+ *
+ * @param packageName package name of the application to open the dialog for
+ * @throws NameNotFoundException if the provided package was not found
+ */
+ public @NonNull PendingIntent getRestrictedSettingDialogIntent(@NonNull String packageName)
+ throws NameNotFoundException {
+ Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(Intent.EXTRA_UID, getPackageUid(packageName));
+ return PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
+ }
+
+ private boolean isPackageEcmGuarded(@NonNull String packageName) throws NameNotFoundException {
+ // If this is a trusted installer or a pre-installed app, it is not ECM guarded
+ if (isAppTrustedInstaller(packageName) || isPackagePreinstalled(packageName)) {
+ return false;
+ }
+
+ // If the package already has an explicitly-set state, use that
+ @EcmState int ecmState = getAppEcmState(packageName);
+ if (ecmState == EcmState.ECM_STATE_GUARDED
+ || ecmState == EcmState.ECM_STATE_GUARDED_AND_ACKNOWLEDGED) {
+ return true;
+ }
+ if (ecmState == EcmState.ECM_STATE_NOT_GUARDED) {
+ return false;
+ }
+
+ // Otherwise, lazily decide whether the app is considered guarded.
+ InstallSourceInfo installSource;
+ try {
+ installSource = mPackageManager.getInstallSourceInfo(packageName);
+ } catch (NameNotFoundException e) {
+ Log.w(LOG_TAG, "Package not found: " + packageName);
+ return false;
+ }
+
+ // These install sources are always considered dangerous.
+ // PackageInstallers that are trusted can use these as a signal that the
+ // packages they've installed aren't as trusted as themselves.
+ int packageSource = installSource.getPackageSource();
+ if (packageSource == PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
+ || packageSource == PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE) {
+ return true;
+ }
+
+ // ECM doesn't consider a transitive chain of trust for install sources.
+ // If this package hasn't been explicitly handled by this point
+ // then it is exempt from ECM if the immediate parent is a trusted installer
+ return installSource.getInstallingPackageName() != null && isAppTrustedInstaller(
+ installSource.getInstallingPackageName());
+ }
+
+ /**
+ * A "trusted installer" is any app with the INSTALL_PACKAGES permission.
+ */
+ private boolean isAppTrustedInstaller(@NonNull String packageName)
+ throws NameNotFoundException {
+ int uid = getPackageUid(packageName);
+ // TODO(b/310654834): Support allow-list for OEM installer exemptions
+ return mContext.checkPermission(android.Manifest.permission.INSTALL_PACKAGES, 0, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private boolean isPackagePreinstalled(@NonNull String packageName) {
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = mPackageManager.getApplicationInfoAsUser(packageName, 0, mUser);
+ } catch (NameNotFoundException e) {
+ Log.w(LOG_TAG, "Package not found: " + packageName);
+ return false;
+ }
+ return ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ }
+
+ private void setAppEcmState(@NonNull String packageName, @EcmState int ecmState)
+ throws NameNotFoundException {
+ mAppOpsManager.setMode(AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS,
+ getPackageUid(packageName), packageName, ecmState);
+ }
+
+ private @EcmState int getAppEcmState(@NonNull String packageName) throws NameNotFoundException {
+ return mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS,
+ getPackageUid(packageName), packageName, mAttributionTag, /* message */
+ null);
+ }
+
+ private boolean isSettingEcmProtected(@NonNull String settingIdentifier) {
+ if (PROTECTED_SETTINGS.contains(settingIdentifier)) {
+ return true;
+ }
+ // TODO(b/310654818): If this is a permission, coerce it into a PermissionGroup.
+ // TODO(b/310218979): Add role selections as protected settings
+ return false;
+ }
+
+ private int getPackageUid(String packageName) throws NameNotFoundException {
+ return mPackageManager.getApplicationInfoAsUser(packageName, /* flags */ 0, mUser).uid;
+ }
+}
diff --git a/framework-s/java/android/app/role/IRoleController.aidl b/framework-s/java/android/app/role/IRoleController.aidl
index 8a43d7fa9..948915f8d 100644
--- a/framework-s/java/android/app/role/IRoleController.aidl
+++ b/framework-s/java/android/app/role/IRoleController.aidl
@@ -40,4 +40,6 @@ oneway interface IRoleController {
in RemoteCallback callback);
void isRoleVisible(in String roleName, in RemoteCallback callback);
+
+ void getLegacyFallbackDisabledRoles(in RemoteCallback callback);
}
diff --git a/framework-s/java/android/app/role/IRoleManager.aidl b/framework-s/java/android/app/role/IRoleManager.aidl
index 5f7cb1bf5..0aef871e6 100644
--- a/framework-s/java/android/app/role/IRoleManager.aidl
+++ b/framework-s/java/android/app/role/IRoleManager.aidl
@@ -25,9 +25,9 @@ import android.os.RemoteCallback;
*/
interface IRoleManager {
- boolean isRoleAvailable(in String roleName);
+ boolean isRoleAvailableAsUser(in String roleName, int userId);
- boolean isRoleHeld(in String roleName, in String packageName);
+ boolean isRoleHeldAsUser(in String roleName, in String packageName, int userId);
List<String> getRoleHoldersAsUser(in String roleName, int userId);
@@ -54,17 +54,28 @@ interface IRoleManager {
void setBypassingRoleQualification(boolean bypassRoleQualification);
- void setRoleNamesFromController(in List<String> roleNames);
+ boolean isRoleFallbackEnabledAsUser(in String roleName, int userId);
- boolean addRoleHolderFromController(in String roleName, in String packageName);
+ void setRoleFallbackEnabledAsUser(in String roleName, boolean fallbackEnabled, int userId);
- boolean removeRoleHolderFromController(in String roleName, in String packageName);
+ void setRoleNamesFromControllerAsUser(in List<String> roleNames, int userId);
- List<String> getHeldRolesFromController(in String packageName);
+ boolean addRoleHolderFromControllerAsUser(in String roleName, in String packageName,
+ int userId);
+
+ boolean removeRoleHolderFromControllerAsUser(in String roleName, in String packageName,
+ int userId);
+
+ List<String> getHeldRolesFromControllerAsUser(in String packageName, int userId);
String getBrowserRoleHolder(int userId);
boolean setBrowserRoleHolder(String packageName, int userId);
String getSmsRoleHolder(int userId);
+
+ boolean isRoleVisibleAsUser(in String roleName, int userId);
+
+ boolean isApplicationVisibleForRoleAsUser(in String roleName, in String packageName,
+ int userId);
}
diff --git a/framework-s/java/android/app/role/RoleControllerManager.java b/framework-s/java/android/app/role/RoleControllerManager.java
index 3b990b315..57da2ccd0 100644
--- a/framework-s/java/android/app/role/RoleControllerManager.java
+++ b/framework-s/java/android/app/role/RoleControllerManager.java
@@ -37,6 +37,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@@ -48,6 +49,12 @@ import java.util.function.Consumer;
*/
public class RoleControllerManager {
+ /**
+ * Bundle key for getting legacy fallback disabled roles
+ */
+ public static final String KEY_LEGACY_FALLBACK_DISABLED_ROLES =
+ "LEGACY_FALLBACK_DISABLED_ROLES";
+
private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
private static final long REQUEST_TIMEOUT_MILLIS = 15 * 1000;
@@ -187,8 +194,7 @@ public class RoleControllerManager {
@RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.onClearRoleHolders(roleName, flags,
- new RemoteCallback(future::complete));
+ service.onClearRoleHolders(roleName, flags, new RemoteCallback(future::complete));
return future;
});
propagateCallback(operation, "onClearRoleHolders", callback);
@@ -227,6 +233,35 @@ public class RoleControllerManager {
propagateCallback(operation, "isRoleVisible", executor, callback);
}
+ /**
+ * @see RoleControllerService#onGrantDefaultRoles()
+ *
+ * @hide
+ */
+ public void getLegacyFallbackDisabledRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<List<String>> callback) {
+ mRemoteService.postAsync(service -> {
+ AndroidFuture<Bundle> future = new AndroidFuture<>();
+ service.getLegacyFallbackDisabledRoles(new RemoteCallback(future::complete));
+ return future;
+ }).orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ .whenComplete((res, err) -> executor.execute(() -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (err != null) {
+ Log.e(LOG_TAG, "Error calling getLegacyFallbackDisabledRoles()",
+ err);
+ callback.accept(null);
+ } else {
+ callback.accept(res.getStringArrayList(
+ KEY_LEGACY_FALLBACK_DISABLED_ROLES));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }));
+ }
+
private void propagateCallback(AndroidFuture<Bundle> operation, String opName,
@CallbackExecutor @NonNull Executor executor,
Consumer<Boolean> destination) {
diff --git a/framework-s/java/android/app/role/RoleControllerService.java b/framework-s/java/android/app/role/RoleControllerService.java
index cf7872913..60a13f7ba 100644
--- a/framework-s/java/android/app/role/RoleControllerService.java
+++ b/framework-s/java/android/app/role/RoleControllerService.java
@@ -17,6 +17,7 @@
package android.app.role;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -31,9 +32,12 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.UserHandle;
+import android.permission.flags.Flags;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -175,6 +179,19 @@ public abstract class RoleControllerService extends Service {
boolean visible = onIsRoleVisible(roleName);
callback.sendResult(visible ? Bundle.EMPTY : null);
}
+
+ @Override
+ public void getLegacyFallbackDisabledRoles(RemoteCallback callback) {
+ enforceCallerSystemUid("getLegacyFallbackDisabledRoles");
+
+ Objects.requireNonNull(callback, "callback cannot be null");
+
+ List<String> legacyFallbackDisabledRoles = onGetLegacyFallbackDisabledRoles();
+ Bundle result = new Bundle();
+ result.putStringArrayList(RoleControllerManager.KEY_LEGACY_FALLBACK_DISABLED_ROLES,
+ new ArrayList<>(legacyFallbackDisabledRoles));
+ callback.sendResult(result);
+ }
};
}
@@ -301,4 +318,15 @@ public abstract class RoleControllerService extends Service {
* @return whether the role should be visible to user
*/
public abstract boolean onIsRoleVisible(@NonNull String roleName);
+
+ /**
+ * Get the legacy fallback disabled state.
+ *
+ * @return A list of role names with disabled fallback state.
+ */
+ @FlaggedApi(Flags.FLAG_SYSTEM_SERVER_ROLE_CONTROLLER_ENABLED)
+ @NonNull
+ public List<String> onGetLegacyFallbackDisabledRoles() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/framework-s/java/android/app/role/RoleManager.java b/framework-s/java/android/app/role/RoleManager.java
index de697f801..fe27d50f3 100644
--- a/framework-s/java/android/app/role/RoleManager.java
+++ b/framework-s/java/android/app/role/RoleManager.java
@@ -18,6 +18,7 @@ package android.app.role;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,6 +28,9 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -35,6 +39,7 @@ import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.permission.flags.Flags;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -42,7 +47,10 @@ import androidx.annotation.RequiresApi;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.build.SdkLevel;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -138,6 +146,15 @@ public final class RoleManager {
public static final String ROLE_NOTES = "android.app.role.NOTES";
/**
+ * The name of the Wallet role.
+ *
+ * @see android.nfc.cardemulation.CardEmulation
+ */
+ @FlaggedApi(Flags.FLAG_WALLET_ROLE_ENABLED)
+ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public static final String ROLE_WALLET = "android.app.role.WALLET";
+
+ /**
* The name of the system wellbeing role.
*
* @hide
@@ -197,6 +214,7 @@ public final class RoleManager {
* @hide
*/
@IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
+ @Retention(RetentionPolicy.SOURCE)
public @interface ManageHoldersFlags {}
/**
@@ -210,6 +228,17 @@ public final class RoleManager {
public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1;
/**
+ * For apps targeting Android V and above, several methods are now user-handle-aware, which
+ * means they use the user contained within the context. For apps targeting an SDK version
+ * <em>below</em> this, the user of the calling process will be used.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public static final long ROLE_MANAGER_USER_HANDLE_AWARE = 303742236L;
+
+ /**
* The action used to request user approval of a role for an application.
*
* @hide
@@ -284,10 +313,12 @@ public final class RoleManager {
*
* @return whether the role is available in the system
*/
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public boolean isRoleAvailable(@NonNull String roleName) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ UserHandle user = getContextUserIfAppropriate();
try {
- return mService.isRoleAvailable(roleName);
+ return mService.isRoleAvailableAsUser(roleName, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -300,10 +331,13 @@ public final class RoleManager {
*
* @return whether the calling application is holding the role
*/
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public boolean isRoleHeld(@NonNull String roleName) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ UserHandle user = getContextUserIfAppropriate();
try {
- return mService.isRoleHeld(roleName, mContext.getPackageName());
+ return mService.isRoleHeldAsUser(roleName, mContext.getPackageName(),
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -326,8 +360,9 @@ public final class RoleManager {
@NonNull
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
@SystemApi
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public List<String> getRoleHolders(@NonNull String roleName) {
- return getRoleHoldersAsUser(roleName, Process.myUserHandle());
+ return getRoleHoldersAsUser(roleName, getContextUserIfAppropriate());
}
/**
@@ -475,10 +510,10 @@ public final class RoleManager {
}
/**
- * Get package names of the applications holding the role for a default application.
+ * Get package name of the application holding the role for a default application.
* <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.MANAGE_DEFAULT_APPLICATIONS}.
+ * Only roles describing default applications can be used with this method. They can have
+ * at most one holder.
*
* @param roleName the name of the default application role to get
*
@@ -506,8 +541,8 @@ public final class RoleManager {
/**
* Set a specific application as the default application.
* <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.MANAGE_DEFAULT_APPLICATIONS}.
+ * Only roles describing default applications can be used with this method. They can have
+ * at most one holder.
*
* @param roleName the name of the default application role to set the role holder for
* @param packageName the package name of the application to set as the default application,
@@ -527,8 +562,8 @@ public final class RoleManager {
public void setDefaultApplication(@NonNull String roleName, @Nullable String packageName,
@ManageHoldersFlags int flags, @CallbackExecutor @NonNull Executor executor,
@NonNull Consumer<Boolean> callback) {
+ // Prior to Android V some devices might require the "packageName" to be non-null.
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
Objects.requireNonNull(executor, "executor cannot be null");
Objects.requireNonNull(callback, "callback cannot be null");
try {
@@ -690,6 +725,53 @@ public final class RoleManager {
}
/**
+ * Check whether role currently enables fallback to default holder.
+ * <p>
+ * This is based on the "None" holder being actively selected, in which case don't fallback.
+ *
+ * @param roleName the name of the role being queried
+ *
+ * @return whether fallback is enabled for the provided role
+ *
+ * @hide
+ */
+ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @FlaggedApi(Flags.FLAG_SYSTEM_SERVER_ROLE_CONTROLLER_ENABLED)
+ @UserHandleAware
+ @SystemApi
+ public boolean isRoleFallbackEnabled(@NonNull String roleName) {
+ try {
+ return mService.isRoleFallbackEnabledAsUser(roleName,
+ mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set whether role should fallback to a default role holder.
+ *
+ * @param roleName the name of the role being queried.
+ * @param fallbackEnabled whether to enable fallback holders for this role.
+ *
+ * @hide
+ */
+ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @FlaggedApi(Flags.FLAG_SYSTEM_SERVER_ROLE_CONTROLLER_ENABLED)
+ @UserHandleAware
+ @SystemApi
+ public void setRoleFallbackEnabled(@NonNull String roleName, boolean fallbackEnabled) {
+ try {
+ mService.setRoleFallbackEnabledAsUser(roleName, fallbackEnabled,
+ mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Set the names of all the available roles. Should only be called from
* {@link android.app.role.RoleControllerService}.
* <p>
@@ -706,10 +788,12 @@ public final class RoleManager {
@Deprecated
@RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
@SystemApi
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void setRoleNamesFromController(@NonNull List<String> roleNames) {
Objects.requireNonNull(roleNames, "roleNames cannot be null");
+ UserHandle user = getContextUserIfAppropriate();
try {
- mService.setRoleNamesFromController(roleNames);
+ mService.setRoleNamesFromControllerAsUser(roleNames, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -740,12 +824,15 @@ public final class RoleManager {
@Deprecated
@RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
@SystemApi
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public boolean addRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+ UserHandle user = getContextUserIfAppropriate();
try {
- return mService.addRoleHolderFromController(roleName, packageName);
+ return mService.addRoleHolderFromControllerAsUser(roleName, packageName,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -776,12 +863,15 @@ public final class RoleManager {
@Deprecated
@RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
@SystemApi
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public boolean removeRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+ UserHandle user = getContextUserIfAppropriate();
try {
- return mService.removeRoleHolderFromController(roleName, packageName);
+ return mService.removeRoleHolderFromControllerAsUser(roleName, packageName,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -802,15 +892,22 @@ public final class RoleManager {
@NonNull
@RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
@SystemApi
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public List<String> getHeldRolesFromController(@NonNull String packageName) {
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+ UserHandle user = getContextUserIfAppropriate();
try {
- return mService.getHeldRolesFromController(packageName);
+ return mService.getHeldRolesFromControllerAsUser(packageName, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ private UserHandle getContextUserIfAppropriate() {
+ return CompatChanges.isChangeEnabled(ROLE_MANAGER_USER_HANDLE_AWARE) ? mContext.getUser()
+ : Process.myUserHandle();
+ }
+
/**
* Get the role holder of {@link #ROLE_BROWSER} without requiring
* {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in
@@ -888,10 +985,29 @@ public final class RoleManager {
*/
@RequiresApi(Build.VERSION_CODES.S)
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SystemApi
public void isRoleVisible(@NonNull String roleName,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- getRoleControllerManager().isRoleVisible(roleName, executor, callback);
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ int userId = getContextUserIfAppropriate().getIdentifier();
+ boolean visible;
+ try {
+ visible = mService.isRoleVisibleAsUser(roleName, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ executor.execute(() -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ callback.accept(visible);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ });
+ } else {
+ getRoleControllerManager().isRoleVisible(roleName, executor, callback);
+ }
}
/**
@@ -910,11 +1026,30 @@ public final class RoleManager {
*/
@RequiresApi(Build.VERSION_CODES.S)
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SystemApi
public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- getRoleControllerManager().isApplicationVisibleForRole(roleName, packageName, executor,
- callback);
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ int userId = getContextUserIfAppropriate().getIdentifier();
+ boolean visible;
+ try {
+ visible = mService.isApplicationVisibleForRoleAsUser(roleName, packageName, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ executor.execute(() -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ callback.accept(visible);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ });
+ } else {
+ getRoleControllerManager().isApplicationVisibleForRole(roleName, packageName, executor,
+ callback);
+ }
}
@NonNull
diff --git a/framework-s/java/android/app/role/TEST_MAPPING b/framework-s/java/android/app/role/TEST_MAPPING
index ce53dca05..01d04bea0 100644
--- a/framework-s/java/android/app/role/TEST_MAPPING
+++ b/framework-s/java/android/app/role/TEST_MAPPING
@@ -25,5 +25,24 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsRoleTestCases"
+ }
+ ],
+ "mainline-postsubmit": [
+ {
+ "name": "CtsRoleTestCases[com.google.android.permission.apex]",
+ "options": [
+ // TODO(b/238677748): These two tests currently fails on R base image
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#openDefaultAppListThenIsNotDefaultAppInList"
+ },
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
+ }
+ ]
+ }
]
}
diff --git a/framework-s/java/android/safetycenter/SafetyCenter.md b/framework-s/java/android/safetycenter/SafetyCenter.md
index 9d3eb811f..ded7809a5 100644
--- a/framework-s/java/android/safetycenter/SafetyCenter.md
+++ b/framework-s/java/android/safetycenter/SafetyCenter.md
@@ -16,4 +16,5 @@
# Android safety for system developers
-TODO(b/203400159): Documentation
+See the [Android Preview docs](https://preview.source.android.com/docs/security/safety-center) for
+more information about Safety Center.
diff --git a/framework-s/java/android/safetycenter/SafetyCenterData.java b/framework-s/java/android/safetycenter/SafetyCenterData.java
index 720fb4997..7cae061a6 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterData.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterData.java
@@ -176,7 +176,8 @@ public final class SafetyCenterData implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public List<SafetyCenterIssue> getDismissedIssues() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mDismissedIssues;
}
@@ -191,7 +192,8 @@ public final class SafetyCenterData implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Bundle getExtras() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mExtras;
}
@@ -371,7 +373,8 @@ public final class SafetyCenterData implements Parcelable {
public Builder(@NonNull SafetyCenterStatus status) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mStatus = requireNonNull(status);
}
@@ -379,7 +382,8 @@ public final class SafetyCenterData implements Parcelable {
/** Creates a {@link Builder} with the values from the given {@link SafetyCenterData}. */
public Builder(@NonNull SafetyCenterData safetyCenterData) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(safetyCenterData);
mStatus = safetyCenterData.mStatus;
diff --git a/framework-s/java/android/safetycenter/SafetyCenterIssue.java b/framework-s/java/android/safetycenter/SafetyCenterIssue.java
index cee872a3a..f10b56b83 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterIssue.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterIssue.java
@@ -190,7 +190,7 @@ public final class SafetyCenterIssue implements Parcelable {
public CharSequence getAttributionTitle() {
if (!SdkLevel.isAtLeastU()) {
throw new UnsupportedOperationException(
- "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mAttributionTitle;
}
@@ -237,7 +237,7 @@ public final class SafetyCenterIssue implements Parcelable {
public String getGroupId() {
if (!SdkLevel.isAtLeastU()) {
throw new UnsupportedOperationException(
- "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mGroupId;
}
@@ -404,7 +404,7 @@ public final class SafetyCenterIssue implements Parcelable {
public Builder setAttributionTitle(@Nullable CharSequence attributionTitle) {
if (!SdkLevel.isAtLeastU()) {
throw new UnsupportedOperationException(
- "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mAttributionTitle = attributionTitle;
return this;
@@ -461,7 +461,7 @@ public final class SafetyCenterIssue implements Parcelable {
public Builder setGroupId(@Nullable String groupId) {
if (!SdkLevel.isAtLeastU()) {
throw new UnsupportedOperationException(
- "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mGroupId = groupId;
return this;
@@ -599,7 +599,8 @@ public final class SafetyCenterIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public ConfirmationDialogDetails getConfirmationDialogDetails() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mConfirmationDialogDetails;
}
@@ -811,7 +812,8 @@ public final class SafetyCenterIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull Action action) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(action);
mId = action.mId;
@@ -890,7 +892,8 @@ public final class SafetyCenterIssue implements Parcelable {
public Builder setConfirmationDialogDetails(
@Nullable ConfirmationDialogDetails confirmationDialogDetails) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mConfirmationDialogDetails = confirmationDialogDetails;
return this;
diff --git a/framework-s/java/android/safetycenter/SafetyCenterManager.java b/framework-s/java/android/safetycenter/SafetyCenterManager.java
index bb67f578f..35d09cce3 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterManager.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterManager.java
@@ -471,7 +471,7 @@ public final class SafetyCenterManager {
@RefreshReason int refreshReason, @NonNull List<String> safetySourceIds) {
if (!SdkLevel.isAtLeastU()) {
throw new UnsupportedOperationException(
- "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(safetySourceIds, "safetySourceIds cannot be null");
diff --git a/framework-s/java/android/safetycenter/SafetyEvent.java b/framework-s/java/android/safetycenter/SafetyEvent.java
index 72e8defaa..2a0d07032 100644
--- a/framework-s/java/android/safetycenter/SafetyEvent.java
+++ b/framework-s/java/android/safetycenter/SafetyEvent.java
@@ -240,7 +240,8 @@ public final class SafetyEvent implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull SafetyEvent safetyEvent) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(safetyEvent);
mType = safetyEvent.mType;
diff --git a/framework-s/java/android/safetycenter/SafetySourceData.java b/framework-s/java/android/safetycenter/SafetySourceData.java
index 2e80621a2..04846dd75 100644
--- a/framework-s/java/android/safetycenter/SafetySourceData.java
+++ b/framework-s/java/android/safetycenter/SafetySourceData.java
@@ -216,7 +216,8 @@ public final class SafetySourceData implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Bundle getExtras() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mExtras;
}
@@ -274,7 +275,8 @@ public final class SafetySourceData implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull SafetySourceData safetySourceData) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(safetySourceData);
mIssues.addAll(safetySourceData.mIssues);
@@ -299,13 +301,14 @@ public final class SafetySourceData implements Parcelable {
/**
* Sets additional information for the {@link SafetySourceData}.
*
- * If not set, the default value is {@link Bundle#EMPTY}.
+ * <p>If not set, the default value is {@link Bundle#EMPTY}.
*/
@NonNull
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder setExtras(@NonNull Bundle extras) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mExtras = requireNonNull(extras);
return this;
@@ -319,7 +322,8 @@ public final class SafetySourceData implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder clearExtras() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mExtras = Bundle.EMPTY;
return this;
diff --git a/framework-s/java/android/safetycenter/SafetySourceIssue.java b/framework-s/java/android/safetycenter/SafetySourceIssue.java
index 985131764..b6e291fe3 100644
--- a/framework-s/java/android/safetycenter/SafetySourceIssue.java
+++ b/framework-s/java/android/safetycenter/SafetySourceIssue.java
@@ -337,7 +337,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public CharSequence getAttributionTitle() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mAttributionTitle;
}
@@ -418,7 +419,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Notification getCustomNotification() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mCustomNotification;
}
@@ -449,7 +451,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public int getNotificationBehavior() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mNotificationBehavior;
}
@@ -482,7 +485,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public String getDeduplicationId() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mDeduplicationId;
}
@@ -505,7 +509,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public int getIssueActionability() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mIssueActionability;
}
@@ -739,7 +744,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public ConfirmationDialogDetails getConfirmationDialogDetails() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mConfirmationDialogDetails;
}
@@ -938,7 +944,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull Action action) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(action);
mId = action.mId;
@@ -949,6 +956,8 @@ public final class SafetySourceIssue implements Parcelable {
mConfirmationDialogDetails = action.mConfirmationDialogDetails;
}
+ // TODO(b/303443020): Add setters for id, label, and pendingIntent
+
/**
* Sets whether the action will resolve the safety issue. Defaults to {@code false}.
*
@@ -984,7 +993,8 @@ public final class SafetySourceIssue implements Parcelable {
public Builder setConfirmationDialogDetails(
@Nullable ConfirmationDialogDetails confirmationDialogDetails) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mConfirmationDialogDetails = confirmationDialogDetails;
return this;
@@ -1229,7 +1239,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull SafetySourceIssue safetySourceIssue) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(safetySourceIssue);
mId = safetySourceIssue.mId;
@@ -1266,7 +1277,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public Builder setAttributionTitle(@Nullable CharSequence attributionTitle) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mAttributionTitle = attributionTitle;
return this;
@@ -1335,7 +1347,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder setCustomNotification(@Nullable Notification customNotification) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mCustomNotification = customNotification;
return this;
@@ -1355,7 +1368,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder setNotificationBehavior(@NotificationBehavior int notificationBehavior) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mNotificationBehavior = validateNotificationBehavior(notificationBehavior);
return this;
@@ -1370,7 +1384,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder setDeduplicationId(@Nullable String deduplicationId) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mDeduplicationId = deduplicationId;
return this;
@@ -1388,7 +1403,8 @@ public final class SafetySourceIssue implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder setIssueActionability(@IssueActionability int issueActionability) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mIssueActionability = validateIssueActionability(issueActionability);
return this;
diff --git a/framework-s/java/android/safetycenter/SafetySourceStatus.java b/framework-s/java/android/safetycenter/SafetySourceStatus.java
index 37095eb59..d8900f8d9 100644
--- a/framework-s/java/android/safetycenter/SafetySourceStatus.java
+++ b/framework-s/java/android/safetycenter/SafetySourceStatus.java
@@ -348,7 +348,8 @@ public final class SafetySourceStatus implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull SafetySourceStatus safetySourceStatus) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(safetySourceStatus);
mTitle = safetySourceStatus.mTitle;
diff --git a/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java b/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java
index c94cedbd6..f6c6c2156 100644
--- a/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java
+++ b/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java
@@ -122,7 +122,8 @@ public final class SafetyCenterConfig implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull SafetyCenterConfig safetyCenterConfig) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(safetyCenterConfig);
mSafetySourcesGroups.addAll(safetyCenterConfig.mSafetySourcesGroups);
diff --git a/framework-s/java/android/safetycenter/config/SafetySource.java b/framework-s/java/android/safetycenter/config/SafetySource.java
index fddb8b622..8aa897850 100644
--- a/framework-s/java/android/safetycenter/config/SafetySource.java
+++ b/framework-s/java/android/safetycenter/config/SafetySource.java
@@ -297,7 +297,8 @@ public final class SafetySource implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public String getOptionalPackageName() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mPackageName;
}
@@ -488,7 +489,8 @@ public final class SafetySource implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public boolean areNotificationsAllowed() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mNotificationsAllowed;
}
@@ -503,7 +505,8 @@ public final class SafetySource implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public String getDeduplicationGroup() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mDeduplicationGroup;
}
@@ -525,7 +528,8 @@ public final class SafetySource implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Set<String> getPackageCertificateHashes() {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
return mPackageCertificateHashes;
}
@@ -668,7 +672,8 @@ public final class SafetySource implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull SafetySource safetySource) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(safetySource);
mType = safetySource.mType;
@@ -884,7 +889,8 @@ public final class SafetySource implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder setNotificationsAllowed(boolean notificationsAllowed) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mNotificationsAllowed = notificationsAllowed;
return this;
@@ -903,7 +909,8 @@ public final class SafetySource implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder setDeduplicationGroup(@Nullable String deduplicationGroup) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mDeduplicationGroup = deduplicationGroup;
return this;
@@ -919,7 +926,8 @@ public final class SafetySource implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder addPackageCertificateHash(@NonNull String packageCertificateHash) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
mPackageCertificateHashes.add(packageCertificateHash);
return this;
diff --git a/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java b/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java
index 1bbe25bbb..9f9ff96cd 100644
--- a/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java
+++ b/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java
@@ -314,7 +314,8 @@ public final class SafetySourcesGroup implements Parcelable {
@RequiresApi(UPSIDE_DOWN_CAKE)
public Builder(@NonNull SafetySourcesGroup original) {
if (!SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Method not supported on versions lower than UPSIDE_DOWN_CAKE");
}
requireNonNull(original);
mSafetySources.addAll(original.mSafetySources);
diff --git a/framework-s/lint-baseline.xml b/framework-s/lint-baseline.xml
index b91b959e4..eb4ed1796 100644
--- a/framework-s/lint-baseline.xml
+++ b/framework-s/lint-baseline.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.content.Context#getUser`"
- errorLine1=" .append(String.valueOf(mContext.getUser().getIdentifier())).println();"
- errorLine2=" ~~~~~~~">
+ message="Call requires API level 33 (current min is 30): `android.util.Slog#e`"
+ errorLine1=' Slog.e(LOG_TAG, "Failed to unbind: " + e);'
+ errorLine2=" ~">
<location
file="frameworks/base/core/java/com/android/internal/infra/ServiceConnector.java"
- line="707"
- column="53"/>
+ line="576"
+ column="26"/>
</issue>
<issue
@@ -25,13 +25,13 @@
<issue
id="NewApi"
- message="Call requires API level 33 (current min is 30): `android.util.Slog#e`"
- errorLine1=' Slog.e(LOG_TAG, "Failed to unbind: " + e);'
- errorLine2=" ~">
+ message="Call requires API level 31 (current min is 30): `android.content.Context#getUser`"
+ errorLine1=" .append(String.valueOf(mContext.getUser().getIdentifier())).println();"
+ errorLine2=" ~~~~~~~">
<location
file="frameworks/base/core/java/com/android/internal/infra/ServiceConnector.java"
- line="576"
- column="26"/>
+ line="707"
+ column="53"/>
</issue>
</issues> \ No newline at end of file
diff --git a/ktfmt_includes.txt b/ktfmt_includes.txt
index 40d8f07d9..5917fc714 100644
--- a/ktfmt_includes.txt
+++ b/ktfmt_includes.txt
@@ -1,2 +1,3 @@
+SafetyCenter
++PermissionController
+tests
diff --git a/permissions/Android.bp b/permissions/Android.bp
index 8c7dab40b..6c1fdb8f8 100644
--- a/permissions/Android.bp
+++ b/permissions/Android.bp
@@ -19,9 +19,7 @@ package {
default_visibility: ["//packages/modules/Permission:__subpackages__"],
}
-prebuilt_etc {
+filegroup {
name: "privapp_allowlist_com.android.permissioncontroller.xml",
- sub_dir: "permissions",
- src: "com.android.permissioncontroller.xml",
- installable: false,
+ srcs: ["com.android.permissioncontroller.xml"],
}
diff --git a/service/Android.bp b/service/Android.bp
index 2778fdd8d..8cd3a452d 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -44,9 +44,6 @@ java_library {
"com.android.permission",
"test_com.android.permission",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -65,9 +62,6 @@ java_library {
installable: false,
min_sdk_version: "30",
sdk_version: "system_server_current",
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_sdk_library {
@@ -106,6 +100,7 @@ java_sdk_library {
"modules-utils-backgroundthread",
"modules-utils-build",
"modules-utils-os",
+ "role-controller",
"safety-center-config",
"safety-center-internal-data",
"safety-center-pending-intents",
@@ -114,6 +109,7 @@ java_sdk_library {
"service-permission-shared",
"service-permission-statsd",
"service-permission-proto-stream",
+ "android.permission.flags-aconfig-java",
],
errorprone: {
javacflags: ["-Xep:GuardedBy:ERROR"],
@@ -130,6 +126,7 @@ java_sdk_library {
lint: {
strict_updatability_linting: true,
baseline_filename: "lint-baseline.xml",
+
},
min_sdk_version: "30",
sdk_version: "system_server_current",
@@ -144,6 +141,10 @@ java_sdk_library {
"com.android.role",
"com.android.safetycenter",
],
+ optimize: {
+ proguard_compatibility: false, // TODO(b/215530220): remove when this is default behavior
+ proguard_flags_files: ["proguard.flags"],
+ },
}
genrule {
@@ -168,7 +169,4 @@ java_library {
],
min_sdk_version: "30",
sdk_version: "system_server_current",
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
diff --git a/service/api/system-server-current.txt b/service/api/system-server-current.txt
index b1869c2c7..30fbab484 100644
--- a/service/api/system-server-current.txt
+++ b/service/api/system-server-current.txt
@@ -45,6 +45,8 @@ package com.android.role.persistence {
public final class RolesState {
ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
+ ctor @FlaggedApi("android.permission.flags.system_server_role_controller_enabled") public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>, @NonNull java.util.Set<java.lang.String>);
+ method @FlaggedApi("android.permission.flags.system_server_role_controller_enabled") @NonNull public java.util.Set<java.lang.String> getFallbackEnabledRoles();
method @Nullable public String getPackagesHash();
method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
method public int getVersion();
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index 2b8765cf5..a3fd75930 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -1,4 +1,5 @@
rule android.os.HandlerExecutor com.android.permission.jarjar.@0
+rule android.permission.flags.** com.android.permission.jarjar.@0
rule android.util.IndentingPrintWriter com.android.permission.jarjar.@0
rule com.android.internal.** com.android.permission.jarjar.@0
rule com.android.modules.** com.android.permission.jarjar.@0
diff --git a/service/java/com/android/role/LocalRoleController.java b/service/java/com/android/role/LocalRoleController.java
new file mode 100644
index 000000000..03508d1cb
--- /dev/null
+++ b/service/java/com/android/role/LocalRoleController.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2023 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.role;
+
+import android.annotation.CallbackExecutor;
+import android.app.role.RoleControllerService;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.RemoteCallback;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+import com.android.role.controller.service.RoleControllerServiceImpl;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+public class LocalRoleController implements RoleController {
+
+ @NonNull
+ private final RoleControllerServiceImpl mService;
+ @NonNull
+ private final HandlerThread mWorkerThread;
+ @NonNull
+ private final Handler mWorkerHandler;
+
+ public LocalRoleController(@NonNull UserHandle user, @NonNull Context context) {
+ mService = new RoleControllerServiceImpl(user, context);
+ mWorkerThread = new HandlerThread(RoleControllerService.class.getSimpleName());
+ mWorkerThread.start();
+ mWorkerHandler = new Handler(mWorkerThread.getLooper());
+ }
+
+ @Override
+ public void grantDefaultRoles(@NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
+ mWorkerHandler.post(() -> {
+ boolean successful = mService.onGrantDefaultRoles();
+ executor.execute(() -> callback.accept(successful));
+ });
+ }
+
+ @Override
+ public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ mWorkerHandler.post(() -> {
+ boolean successful = mService.onAddRoleHolder(roleName, packageName, flags);
+ callback.sendResult(successful ? Bundle.EMPTY : null);
+ });
+ }
+
+ @Override
+ public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ mWorkerHandler.post(() -> {
+ boolean successful = mService.onRemoveRoleHolder(roleName, packageName, flags);
+ callback.sendResult(successful ? Bundle.EMPTY : null);
+ });
+ }
+
+ @Override
+ public void onClearRoleHolders(@NonNull String roleName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ mWorkerHandler.post(() -> {
+ boolean successful = mService.onClearRoleHolders(roleName, flags);
+ callback.sendResult(successful ? Bundle.EMPTY : null);
+ });
+ }
+
+ @Override
+ public boolean isRoleVisible(@NonNull String roleName) {
+ return mService.onIsRoleVisible(roleName);
+ }
+
+ @Override
+ public boolean isApplicationVisibleForRole(@NonNull String roleName,
+ @NonNull String packageName) {
+ return mService.onIsApplicationVisibleForRole(roleName, packageName);
+ }
+
+ @Override
+ public void getLegacyFallbackDisabledRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<List<String>> callback) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/service/java/com/android/role/RemoteRoleController.java b/service/java/com/android/role/RemoteRoleController.java
new file mode 100644
index 000000000..0920dd56a
--- /dev/null
+++ b/service/java/com/android/role/RemoteRoleController.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 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.role;
+
+import android.annotation.CallbackExecutor;
+import android.app.role.RoleControllerManager;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.os.RemoteCallback;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+import com.android.permission.util.ForegroundThread;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+public class RemoteRoleController implements RoleController {
+ @NonNull
+ private final RoleControllerManager mRoleControllerManager;
+
+ public RemoteRoleController(@NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = context.createContextAsUser(user, 0);
+ mRoleControllerManager =
+ RoleControllerManager.createWithInitializedRemoteServiceComponentName(
+ ForegroundThread.getHandler(), userContext);
+ }
+
+ @Override
+ public void grantDefaultRoles(@NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
+ mRoleControllerManager.grantDefaultRoles(executor, callback);
+ }
+
+ @Override
+ public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ mRoleControllerManager.onAddRoleHolder(roleName, packageName, flags, callback);
+ }
+
+ @Override
+ public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ mRoleControllerManager.onRemoveRoleHolder(roleName, packageName, flags, callback);
+ }
+
+ @Override
+ public void onClearRoleHolders(@NonNull String roleName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ mRoleControllerManager.onClearRoleHolders(roleName, flags, callback);
+ }
+
+ @Override
+ public boolean isRoleVisible(@NonNull String roleName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isApplicationVisibleForRole(@NonNull String roleName,
+ @NonNull String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void getLegacyFallbackDisabledRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<List<String>> callback) {
+ mRoleControllerManager.getLegacyFallbackDisabledRoles(executor, callback);
+ }
+}
diff --git a/service/java/com/android/role/RoleController.java b/service/java/com/android/role/RoleController.java
new file mode 100644
index 000000000..6ebbdfd45
--- /dev/null
+++ b/service/java/com/android/role/RoleController.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 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.role;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.app.role.RoleManager;
+import android.os.RemoteCallback;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+public interface RoleController {
+ /**
+ * @see android.app.role.RoleControllerManager#grantDefaultRoles
+ */
+ void grantDefaultRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<Boolean> callback);
+
+ /**
+ * @see android.app.role.RoleControllerManager#onAddRoleHolder
+ */
+ void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback);
+
+ /**
+ * @see android.app.role.RoleControllerManager#onRemoveRoleHolder
+ */
+ void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback);
+
+ /**
+ * @see android.app.role.RoleControllerManager#onClearRoleHolders
+ */
+ void onClearRoleHolders(@NonNull String roleName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback);
+
+ /**
+ * @see android.app.role.RoleControllerManager#isRoleVisible
+ */
+ boolean isRoleVisible(@NonNull String roleName);
+
+ /**
+ * @see android.app.role.RoleControllerManager#isApplicationVisibleForRole
+ */
+ boolean isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName);
+
+ /**
+ * @see android.app.role.RoleControllerManager#getLegacyFallbackDisabledRoles
+ */
+ void getLegacyFallbackDisabledRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<List<String>> callback);
+}
diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java
index 485be4e72..2524627eb 100644
--- a/service/java/com/android/role/RoleService.java
+++ b/service/java/com/android/role/RoleService.java
@@ -24,6 +24,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.AppOpsManager;
+import android.app.admin.DevicePolicyManager;
import android.app.role.IOnRoleHoldersChangedListener;
import android.app.role.IRoleManager;
import android.app.role.RoleControllerManager;
@@ -33,6 +34,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -41,6 +44,9 @@ import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.permission.flags.Flags;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
@@ -55,6 +61,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.modules.utils.build.SdkLevel;
import com.android.permission.compat.UserHandleCompat;
import com.android.permission.util.ArrayUtils;
import com.android.permission.util.CollectionUtils;
@@ -124,7 +131,7 @@ public class RoleService extends SystemService implements RoleUserState.Callback
*/
@GuardedBy("mLock")
@NonNull
- private final SparseArray<RoleControllerManager> mControllers = new SparseArray<>();
+ private final SparseArray<RoleController> mControllers = new SparseArray<>();
/**
* Maps user id to its list of listeners.
@@ -181,13 +188,14 @@ public class RoleService extends SystemService implements RoleUserState.Callback
public void onStart() {
publishBinderService(Context.ROLE_SERVICE, new Stub());
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- intentFilter.addDataScheme("package");
- intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
+ Context context = getContext();
+ IntentFilter packageIntentFilter = new IntentFilter();
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageIntentFilter.addDataScheme("package");
+ packageIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ context.registerReceiverForAllUsers(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int userId = UserHandleCompat.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1));
@@ -202,14 +210,82 @@ public class RoleService extends SystemService implements RoleUserState.Callback
}
maybeGrantDefaultRolesAsync(userId);
}
- }, intentFilter, null, null);
+ }, packageIntentFilter, null, null);
+
+ if (SdkLevel.isAtLeastV()) {
+ IntentFilter devicePolicyIntentFilter = new IntentFilter();
+ devicePolicyIntentFilter.addAction(
+ DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
+ devicePolicyIntentFilter.addAction(
+ DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED);
+ devicePolicyIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ context.registerReceiverForAllUsers(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int userId = getSendingUser().getIdentifier();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Device policy changed (" + intent.getAction()
+ + ") - re-running initial grants for user " + userId);
+ }
+ maybeGrantDefaultRolesAsync(userId);
+ }
+ }, devicePolicyIntentFilter, null, null);
+
+ context.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE), false,
+ new ContentObserver(ForegroundThread.getHandler()) {
+ public void onChange(boolean selfChange, Uri uri) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Settings.Global.DEVICE_DEMO_MODE changed.");
+ }
+ UserManager userManager =
+ context.getSystemService(UserManager.class);
+ List<UserHandle> users = userManager.getUserHandles(true);
+ int usersSize = users.size();
+ for (int i = 0; i < usersSize; i++) {
+ maybeGrantDefaultRolesAsync(users.get(i).getIdentifier());
+ }
+ }
+ });
+ }
}
@Override
public void onUserStarting(@NonNull TargetUser user) {
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ upgradeLegacyFallbackEnabledRolesIfNeeded(user);
+ }
+
maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier());
}
+ private void upgradeLegacyFallbackEnabledRolesIfNeeded(@NonNull TargetUser user) {
+ int userId = user.getUserHandle().getIdentifier();
+ RoleUserState userState = getOrCreateUserState(userId);
+ if (!userState.isVersionUpgradeNeeded()) {
+ return;
+ }
+ List<String> legacyFallbackDisabledRoles = getLegacyFallbackDisabledRolesSync(userId);
+ if (legacyFallbackDisabledRoles == null) {
+ return;
+ }
+ userState.upgradeVersion(legacyFallbackDisabledRoles);
+ }
+
+ @MainThread
+ private List<String> getLegacyFallbackDisabledRolesSync(@UserIdInt int userId) {
+ AndroidFuture<List<String>> future = new AndroidFuture<>();
+ RoleController controller = new RemoteRoleController(UserHandle.of(userId), getContext());
+ controller.getLegacyFallbackDisabledRoles(ForegroundThread.getExecutor(), future::complete);
+ try {
+ return future.get(30, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Log.e(LOG_TAG, "Failed to get the legacy role fallback disabled state for user "
+ + userId, e);
+ return null;
+ }
+ }
+
@MainThread
private void maybeGrantDefaultRolesSync(@UserIdInt int userId) {
AndroidFuture<Void> future = maybeGrantDefaultRolesInternal(userId);
@@ -277,14 +353,17 @@ public class RoleService extends SystemService implements RoleUserState.Callback
}
@NonNull
- private RoleControllerManager getOrCreateController(@UserIdInt int userId) {
+ private RoleController getOrCreateController(@UserIdInt int userId) {
synchronized (mLock) {
- RoleControllerManager controller = mControllers.get(userId);
+ RoleController controller = mControllers.get(userId);
if (controller == null) {
- Context systemContext = getContext();
- Context userContext = systemContext.createContextAsUser(UserHandle.of(userId), 0);
- controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
- ForegroundThread.getHandler(), userContext);
+ UserHandle user = UserHandle.of(userId);
+ Context context = getContext();
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ controller = new LocalRoleController(user, context);
+ } else {
+ controller = new RemoteRoleController(user, context);
+ }
mControllers.put(userId, controller);
}
return controller;
@@ -371,22 +450,33 @@ public class RoleService extends SystemService implements RoleUserState.Callback
private class Stub extends IRoleManager.Stub {
@Override
- public boolean isRoleAvailable(@NonNull String roleName) {
+ public boolean isRoleAvailableAsUser(@NonNull String roleName, @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false, "isRoleAvailableAsUser",
+ getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return false;
+ }
+
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- int userId = UserHandleCompat.getUserId(getCallingUid());
return getOrCreateUserState(userId).isRoleAvailable(roleName);
}
@Override
- public boolean isRoleHeld(@NonNull String roleName, @NonNull String packageName) {
- int callingUid = getCallingUid();
- mAppOpsManager.checkPackage(callingUid, packageName);
+ public boolean isRoleHeldAsUser(@NonNull String roleName, @NonNull String packageName,
+ @UserIdInt int userId) {
+ mAppOpsManager.checkPackage(getCallingUid(), packageName);
+
+ UserUtils.enforceCrossUserPermission(userId, false, "isRoleHeldAsUser", getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return false;
+ }
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- int userId = UserHandleCompat.getUserId(callingUid);
ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
if (roleHolders == null) {
return false;
@@ -434,8 +524,7 @@ public class RoleService extends SystemService implements RoleUserState.Callback
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
Objects.requireNonNull(callback, "callback cannot be null");
- getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
- callback);
+ getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags, callback);
}
@Override
@@ -522,11 +611,11 @@ public class RoleService extends SystemService implements RoleUserState.Callback
Preconditions.checkArgumentIsSupported(DEFAULT_APPLICATION_ROLES, roleName);
Objects.requireNonNull(callback, "callback cannot be null");
- RoleControllerManager roleControllerManager = getOrCreateController(userId);
+ RoleController roleController = getOrCreateController(userId);
if (packageName != null) {
- roleControllerManager.onAddRoleHolder(roleName, packageName, flags, callback);
+ roleController.onAddRoleHolder(roleName, packageName, flags, callback);
} else {
- roleControllerManager.onClearRoleHolders(roleName, flags, callback);
+ roleController.onClearRoleHolders(roleName, flags, callback);
}
}
@@ -605,54 +694,116 @@ public class RoleService extends SystemService implements RoleUserState.Callback
}
@Override
- public void setRoleNamesFromController(@NonNull List<String> roleNames) {
+ public boolean isRoleFallbackEnabledAsUser(@NonNull String roleName,
+ @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false, "isRoleFallbackEnabledAsUser",
+ getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return false;
+ }
+
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
+ "isRoleFallbackEnabledAsUser");
+
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+
+ return getOrCreateUserState(userId).isFallbackEnabled(roleName);
+ }
+
+ @Override
+ public void setRoleFallbackEnabledAsUser(@NonNull String roleName, boolean fallbackEnabled,
+ @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false, "setRoleFallbackEnabledAsUser",
+ getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return;
+ }
+
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
+ "setRoleFallbackEnabledAsUser");
+
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+
+ getOrCreateUserState(userId).setFallbackEnabled(roleName, fallbackEnabled);
+ }
+
+ @Override
+ public void setRoleNamesFromControllerAsUser(@NonNull List<String> roleNames,
+ @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false, "setRoleNamesFromControllerAsUser",
+ getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return;
+ }
+
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
- "setRoleNamesFromController");
+ "setRoleNamesFromControllerAsUser");
Objects.requireNonNull(roleNames, "roleNames cannot be null");
- int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
getOrCreateUserState(userId).setRoleNames(roleNames);
}
@Override
- public boolean addRoleHolderFromController(@NonNull String roleName,
- @NonNull String packageName) {
+ public boolean addRoleHolderFromControllerAsUser(@NonNull String roleName,
+ @NonNull String packageName, @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false,
+ "addRoleHolderFromControllerAsUser", getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return false;
+ }
+
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
- "addRoleHolderFromController");
+ "addRoleHolderFromControllerAsUser");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
}
@Override
- public boolean removeRoleHolderFromController(@NonNull String roleName,
- @NonNull String packageName) {
+ public boolean removeRoleHolderFromControllerAsUser(@NonNull String roleName,
+ @NonNull String packageName, @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false,
+ "removeRoleHolderFromControllerAsUser", getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return false;
+ }
+
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
- "removeRoleHolderFromController");
+ "removeRoleHolderFromControllerAsUser");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
}
@Override
- public List<String> getHeldRolesFromController(@NonNull String packageName) {
+ public List<String> getHeldRolesFromControllerAsUser(@NonNull String packageName,
+ @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false,
+ "getHeldRolesFromControllerAsUser", getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return Collections.emptyList();
+ }
+
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
- "getRolesHeldFromController");
+ "getHeldRolesFromControllerAsUser");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).getHeldRoles(packageName);
}
@@ -772,6 +923,42 @@ public class RoleService extends SystemService implements RoleUserState.Callback
}
@Override
+ public boolean isRoleVisibleAsUser(@NonNull String roleName, @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false, "isRoleVisibleAsUser",
+ getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return false;
+ }
+
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
+ "isRoleVisibleAsUser");
+
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+
+ return getOrCreateController(userId).isRoleVisible(roleName);
+ }
+
+ @Override
+ public boolean isApplicationVisibleForRoleAsUser(@NonNull String roleName,
+ @NonNull String packageName, @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false,
+ "isApplicationVisibleForRoleAsUser", getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return false;
+ }
+
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
+ "isApplicationVisibleForRoleAsUser");
+
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
+ return getOrCreateController(userId).isApplicationVisibleForRole(roleName, packageName);
+ }
+
+ @Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {
if (!checkDumpPermission("role", fout)) {
diff --git a/service/java/com/android/role/RoleUserState.java b/service/java/com/android/role/RoleUserState.java
index 727e0f122..39c1e8c3d 100644
--- a/service/java/com/android/role/RoleUserState.java
+++ b/service/java/com/android/role/RoleUserState.java
@@ -53,6 +53,8 @@ class RoleUserState {
public static final int VERSION_UNDEFINED = -1;
+ public static final int VERSION_FALLBACK_STATE_MIGRATED = 1;
+
private static final long WRITE_DELAY_MILLIS = 200;
private final RolesPersistence mPersistence = RolesPersistence.createInstance();
@@ -86,6 +88,13 @@ class RoleUserState {
@NonNull
private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>();
+ /**
+ * Role names of the roles with fallback enabled.
+ */
+ @GuardedBy("mLock")
+ @NonNull
+ private ArraySet<String> mFallbackEnabledRoles = new ArraySet<>();
+
@GuardedBy("mLock")
private boolean mWriteScheduled;
@@ -141,6 +150,15 @@ class RoleUserState {
}
/**
+ * Checks the version and returns whether a version upgrade is needed.
+ */
+ public boolean isVersionUpgradeNeeded() {
+ synchronized (mLock) {
+ return mVersion < VERSION_FALLBACK_STATE_MIGRATED;
+ }
+ }
+
+ /**
* Get the hash representing the state of packages during the last time initial grants was run.
*
* @return the hash representing the state of packages
@@ -193,6 +211,48 @@ class RoleUserState {
}
}
+ public boolean isFallbackEnabled(@NonNull String roleName) {
+ synchronized (mLock) {
+ return mFallbackEnabledRoles.contains(roleName);
+ }
+ }
+
+ public void setFallbackEnabled(@NonNull String roleName, boolean fallbackEnabled) {
+ synchronized (mLock) {
+ if (!mRoles.containsKey(roleName)) {
+ Log.e(LOG_TAG, "Cannot set fallback enabled for unknown role, role: " + roleName
+ + ", fallbackEnabled: " + fallbackEnabled);
+ return;
+ }
+ if (mFallbackEnabledRoles.contains(roleName) == fallbackEnabled) {
+ return;
+ }
+ if (fallbackEnabled) {
+ mFallbackEnabledRoles.add(roleName);
+ } else {
+ mFallbackEnabledRoles.remove(roleName);
+ }
+ scheduleWriteFileLocked();
+ }
+ }
+
+ /**
+ * Upgrade this user state to the latest version if needed.
+ */
+ public void upgradeVersion(@NonNull List<String> legacyFallbackDisabledRoles) {
+ synchronized (mLock) {
+ if (mVersion < VERSION_FALLBACK_STATE_MIGRATED) {
+ int legacyFallbackDisabledRolesSize = legacyFallbackDisabledRoles.size();
+ for (int i = 0; i < legacyFallbackDisabledRolesSize; i++) {
+ String roleName = legacyFallbackDisabledRoles.get(i);
+ mFallbackEnabledRoles.remove(roleName);
+ }
+ mVersion = VERSION_FALLBACK_STATE_MIGRATED;
+ scheduleWriteFileLocked();
+ }
+ }
+ }
+
/**
* Get whether the role is available.
*
@@ -235,6 +295,7 @@ class RoleUserState {
synchronized (mLock) {
if (!mRoles.containsKey(roleName)) {
mRoles.put(roleName, new ArraySet<>());
+ mFallbackEnabledRoles.add(roleName);
Log.i(LOG_TAG, "Added new role: " + roleName);
scheduleWriteFileLocked();
return true;
@@ -263,6 +324,7 @@ class RoleUserState {
+ " role: " + roleName + ", holders: " + packageNames);
}
mRoles.removeAt(i);
+ mFallbackEnabledRoles.remove(roleName);
changed = true;
}
}
@@ -386,7 +448,8 @@ class RoleUserState {
// Force a reconciliation on next boot if we are bypassing role qualification now.
String packagesHash = mBypassingRoleQualification ? null : mPackagesHash;
roles = new RolesState(mVersion, packagesHash,
- (Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked());
+ (Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked(),
+ snapshotFallbackEnabledRoles());
}
mPersistence.writeForUser(roles, UserHandle.of(mUserId));
@@ -397,12 +460,15 @@ class RoleUserState {
RolesState roleState = mPersistence.readForUser(UserHandle.of(mUserId));
Map<String, Set<String>> roles;
+ Set<String> fallbackEnabledRoles;
if (roleState != null) {
mVersion = roleState.getVersion();
mPackagesHash = roleState.getPackagesHash();
roles = roleState.getRoles();
+ fallbackEnabledRoles = roleState.getFallbackEnabledRoles();
} else {
roles = mPlatformHelper.getLegacyRoleState(mUserId);
+ fallbackEnabledRoles = roles.keySet();
}
mRoles.clear();
for (Map.Entry<String, Set<String>> entry : roles.entrySet()) {
@@ -410,7 +476,8 @@ class RoleUserState {
ArraySet<String> roleHolders = new ArraySet<>(entry.getValue());
mRoles.put(roleName, roleHolders);
}
-
+ mFallbackEnabledRoles.clear();
+ mFallbackEnabledRoles.addAll(fallbackEnabledRoles);
if (roleState == null) {
scheduleWriteFileLocked();
}
@@ -427,10 +494,12 @@ class RoleUserState {
int version;
String packagesHash;
ArrayMap<String, ArraySet<String>> roles;
+ ArraySet<String> fallbackEnabledRoles;
synchronized (mLock) {
version = mVersion;
packagesHash = mPackagesHash;
roles = snapshotRolesLocked();
+ fallbackEnabledRoles = snapshotFallbackEnabledRoles();
}
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
@@ -442,10 +511,12 @@ class RoleUserState {
for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) {
String roleName = roles.keyAt(rolesIndex);
ArraySet<String> roleHolders = roles.valueAt(rolesIndex);
+ boolean fallbackEnabled = fallbackEnabledRoles.contains(roleName);
long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES);
dumpOutputStream.write("name", RoleProto.NAME, roleName);
-
+ dumpOutputStream.write("fallback_enabled", RoleProto.FALLBACK_ENABLED,
+ Boolean.toString(fallbackEnabled));
int roleHoldersSize = roleHolders.size();
for (int roleHoldersIndex = 0; roleHoldersIndex < roleHoldersSize; roleHoldersIndex++) {
String roleHolder = roleHolders.valueAt(roleHoldersIndex);
@@ -485,6 +556,12 @@ class RoleUserState {
return roles;
}
+ @GuardedBy("mLock")
+ @NonNull
+ private ArraySet<String> snapshotFallbackEnabledRoles() {
+ return new ArraySet<>(mFallbackEnabledRoles);
+ }
+
/**
* Destroy this user state and delete the corresponding file. Any pending writes to the file
* will be cancelled, and any future interaction with this state will throw an exception.
diff --git a/service/java/com/android/role/TEST_MAPPING b/service/java/com/android/role/TEST_MAPPING
index 15173a9da..45cf62ff7 100644
--- a/service/java/com/android/role/TEST_MAPPING
+++ b/service/java/com/android/role/TEST_MAPPING
@@ -33,5 +33,32 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsAppSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.appsecurity.cts.StatsdAppSecurityAtomTest#testRoleHolder"
+ }
+ ]
+ },
+ {
+ "name": "CtsRoleTestCases"
+ }
+ ],
+ "mainline-postsubmit": [
+ {
+ "name": "CtsRoleTestCases[com.google.android.permission.apex]",
+ "options": [
+ // TODO(b/238677748): These two tests currently fails on R base image
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#openDefaultAppListThenIsNotDefaultAppInList"
+ },
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
+ }
+ ]
+ }
]
}
diff --git a/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index 76cf8f81f..242f7315f 100644
--- a/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -66,6 +66,7 @@ public class RolesPersistenceImpl implements RolesPersistence {
private static final String ATTRIBUTE_VERSION = "version";
private static final String ATTRIBUTE_NAME = "name";
+ private static final String ATTRIBUTE_FALLBACK_ENABLED = "fallbackEnabled";
private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
@VisibleForTesting
@@ -142,6 +143,7 @@ public class RolesPersistenceImpl implements RolesPersistence {
String packagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
Map<String, Set<String>> roles = new ArrayMap<>();
+ Set<String> fallbackEnabledRoles = new ArraySet<>();
int type;
int depth;
int innerDepth = parser.getDepth() + 1;
@@ -153,12 +155,16 @@ public class RolesPersistenceImpl implements RolesPersistence {
if (parser.getName().equals(TAG_ROLE)) {
String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+ String fallbackEnabled = parser.getAttributeValue(null, ATTRIBUTE_FALLBACK_ENABLED);
+ if (Boolean.parseBoolean(fallbackEnabled)) {
+ fallbackEnabledRoles.add(roleName);
+ }
Set<String> roleHolders = parseRoleHolders(parser);
roles.put(roleName, roleHolders);
}
}
- return new RolesState(version, packagesHash, roles);
+ return new RolesState(version, packagesHash, roles, fallbackEnabledRoles);
}
@NonNull
@@ -238,12 +244,16 @@ public class RolesPersistenceImpl implements RolesPersistence {
serializer.attribute(null, ATTRIBUTE_PACKAGES_HASH, packagesHash);
}
+ Set<String> fallbackEnabledRoles = roles.getFallbackEnabledRoles();
for (Map.Entry<String, Set<String>> entry : roles.getRoles().entrySet()) {
String roleName = entry.getKey();
Set<String> roleHolders = entry.getValue();
+ boolean isFallbackEnabled = fallbackEnabledRoles.contains(roleName);
serializer.startTag(null, TAG_ROLE);
serializer.attribute(null, ATTRIBUTE_NAME, roleName);
+ serializer.attribute(null, ATTRIBUTE_FALLBACK_ENABLED,
+ Boolean.toString(isFallbackEnabled));
serializeRoleHolders(serializer, roleHolders);
serializer.endTag(null, TAG_ROLE);
}
diff --git a/service/java/com/android/role/persistence/RolesState.java b/service/java/com/android/role/persistence/RolesState.java
index f61efa0e8..a189dd4c2 100644
--- a/service/java/com/android/role/persistence/RolesState.java
+++ b/service/java/com/android/role/persistence/RolesState.java
@@ -16,10 +16,12 @@
package com.android.role.persistence;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemApi.Client;
+import android.permission.flags.Flags;
import java.util.Map;
import java.util.Objects;
@@ -33,7 +35,6 @@ import java.util.Set;
*/
@SystemApi(client = Client.SYSTEM_SERVER)
public final class RolesState {
-
/**
* The version of the roles.
*/
@@ -52,6 +53,12 @@ public final class RolesState {
private final Map<String, Set<String>> mRoles;
/**
+ * The names of roles with fallback enabled.
+ */
+ @NonNull
+ private final Set<String> mFallbackEnabledRoles;
+
+ /**
* Create a new instance of this class.
*
* @param version the version of the roles
@@ -60,9 +67,24 @@ public final class RolesState {
*/
public RolesState(int version, @Nullable String packagesHash,
@NonNull Map<String, Set<String>> roles) {
+ this(version, packagesHash, roles, roles.keySet());
+ }
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param version the version of the roles
+ * @param packagesHash the hash of all packages in the system
+ * @param roles the roles
+ * @param fallbackEnabledRoles the roles with fallback enabled
+ */
+ @FlaggedApi(Flags.FLAG_SYSTEM_SERVER_ROLE_CONTROLLER_ENABLED)
+ public RolesState(int version, @Nullable String packagesHash,
+ @NonNull Map<String, Set<String>> roles, @NonNull Set<String> fallbackEnabledRoles) {
mVersion = version;
mPackagesHash = packagesHash;
mRoles = roles;
+ mFallbackEnabledRoles = fallbackEnabledRoles;
}
/**
@@ -94,6 +116,17 @@ public final class RolesState {
return mRoles;
}
+ /**
+ * Get the fallback enabled roles.
+ *
+ * @return fallback enabled roles
+ */
+ @NonNull
+ @FlaggedApi(Flags.FLAG_SYSTEM_SERVER_ROLE_CONTROLLER_ENABLED)
+ public Set<String> getFallbackEnabledRoles() {
+ return mFallbackEnabledRoles;
+ }
+
@Override
public boolean equals(Object object) {
if (this == object) {
@@ -105,11 +138,12 @@ public final class RolesState {
RolesState that = (RolesState) object;
return mVersion == that.mVersion
&& Objects.equals(mPackagesHash, that.mPackagesHash)
- && Objects.equals(mRoles, that.mRoles);
+ && Objects.equals(mRoles, that.mRoles)
+ && Objects.equals(mFallbackEnabledRoles, that.mFallbackEnabledRoles);
}
@Override
public int hashCode() {
- return Objects.hash(mVersion, mPackagesHash, mRoles);
+ return Objects.hash(mVersion, mPackagesHash, mRoles, mFallbackEnabledRoles);
}
}
diff --git a/service/java/com/android/safetycenter/ApiLock.java b/service/java/com/android/safetycenter/ApiLock.java
index 91466d3d5..f80e2ea32 100644
--- a/service/java/com/android/safetycenter/ApiLock.java
+++ b/service/java/com/android/safetycenter/ApiLock.java
@@ -16,10 +16,6 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
-import androidx.annotation.RequiresApi;
-
/**
* A class that is used to strongly type the {@link Object} used to synchronize the Safety Center
* APIs.
@@ -29,7 +25,6 @@ import androidx.annotation.RequiresApi;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class ApiLock {
ApiLock() {}
}
diff --git a/service/java/com/android/safetycenter/DevicePolicyResources.java b/service/java/com/android/safetycenter/DevicePolicyResources.java
index 25cab343f..8d31c254b 100644
--- a/service/java/com/android/safetycenter/DevicePolicyResources.java
+++ b/service/java/com/android/safetycenter/DevicePolicyResources.java
@@ -16,8 +16,6 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static java.util.Objects.requireNonNull;
import android.annotation.StringRes;
@@ -26,14 +24,11 @@ import android.app.admin.DevicePolicyResourcesManager;
import android.content.Context;
import android.os.Binder;
-import androidx.annotation.RequiresApi;
-
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import java.util.function.Supplier;
/** A class that handles dynamically updating enterprise-related resources. */
-@RequiresApi(TIRAMISU)
final class DevicePolicyResources {
private static final String SAFETY_CENTER_PREFIX = "SafetyCenter.";
@@ -46,31 +41,30 @@ final class DevicePolicyResources {
* DevicePolicyResourcesManager#getString}.
*/
static String getSafetySourceWorkString(
- SafetyCenterResourcesContext safetyCenterResourcesContext,
+ SafetyCenterResourcesApk safetyCenterResourcesApk,
String safetySourceId,
@StringRes int workResId) {
return getEnterpriseString(
- safetyCenterResourcesContext,
+ safetyCenterResourcesApk.getContext(),
safetySourceId,
- () -> safetyCenterResourcesContext.getString(workResId));
+ () -> safetyCenterResourcesApk.getString(workResId));
}
/**
* Returns the updated string for the {@code work_profile_paused} string by calling {@link
* DevicePolicyResourcesManager#getString}.
*/
- static String getWorkProfilePausedString(
- SafetyCenterResourcesContext safetyCenterResourcesContext) {
+ static String getWorkProfilePausedString(SafetyCenterResourcesApk safetyCenterResourcesApk) {
return getEnterpriseString(
- safetyCenterResourcesContext,
+ safetyCenterResourcesApk.getContext(),
WORK_PROFILE_PAUSED_TITLE,
- () -> safetyCenterResourcesContext.getStringByName("work_profile_paused"));
+ () -> safetyCenterResourcesApk.getStringByName("work_profile_paused"));
}
private static String getEnterpriseString(
Context context, String devicePolicyIdentifier, Supplier<String> defaultValueLoader) {
// This call requires the caller’s identity to match the package name of the given context.
- // However, the SafetyCenterResourcesContext’s has package name "android", which does not
+ // However, the SafetyCenterResourceApk Context's has package name "android", which does not
// necessarily match the caller’s package when making Binder calls, so the calling identity
// has to be cleared.
final long callingId = Binder.clearCallingIdentity();
diff --git a/service/java/com/android/safetycenter/PendingIntentFactory.java b/service/java/com/android/safetycenter/PendingIntentFactory.java
index 8c447c477..c4e9decd2 100644
--- a/service/java/com/android/safetycenter/PendingIntentFactory.java
+++ b/service/java/com/android/safetycenter/PendingIntentFactory.java
@@ -16,15 +16,13 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static java.util.Objects.requireNonNull;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ResolveInfoFlags;
import android.content.pm.ResolveInfo;
@@ -32,9 +30,9 @@ import android.os.Binder;
import android.os.UserHandle;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import java.util.Arrays;
@@ -43,7 +41,6 @@ import java.util.Arrays;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class PendingIntentFactory {
private static final String TAG = "PendingIntentFactory";
@@ -53,21 +50,20 @@ public final class PendingIntentFactory {
private static final String IS_SETTINGS_HOMEPAGE = "is_from_settings_homepage";
private final Context mContext;
- private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
+ private final SafetyCenterResourcesApk mSafetyCenterResourcesApk;
- PendingIntentFactory(
- Context context, SafetyCenterResourcesContext safetyCenterResourcesContext) {
+ PendingIntentFactory(Context context, SafetyCenterResourcesApk safetyCenterResourcesApk) {
mContext = context;
- mSafetyCenterResourcesContext = safetyCenterResourcesContext;
+ mSafetyCenterResourcesApk = safetyCenterResourcesApk;
}
/**
* Creates or retrieves a {@link PendingIntent} that will start a new {@code Activity} matching
* the given {@code intentAction}.
*
- * <p>If the given {@code intentAction} resolves for the given {@code packageName}, the {@link
- * PendingIntent} will explicitly target the {@code packageName}. If the {@code intentAction}
- * resolves elsewhere, the {@link PendingIntent} will be implicit.
+ * <p>If the given {@code intentAction} resolves, the {@link PendingIntent} will use an implicit
+ * {@link Intent}. Otherwise, the {@link PendingIntent} will explicitly target the {@code
+ * packageName} if it resolves.
*
* <p>The {@code PendingIntent} is associated with a specific source given by {@code sourceId}.
*
@@ -75,7 +71,7 @@ public final class PendingIntentFactory {
* is no valid target for the given {@code intentAction}.
*/
@Nullable
- PendingIntent getPendingIntent(
+ public PendingIntent getPendingIntent(
String sourceId,
@Nullable String intentAction,
String packageName,
@@ -118,26 +114,25 @@ public final class PendingIntentFactory {
intent.setIdentifier("with_settings_homepage_extra");
}
+ if (intentResolvesToActivity(packageContext, intent)) {
+ return intent;
+ }
+
// If the intent resolves for the package provided, then we make the assumption that it is
// the desired app and make the intent explicit. This is to workaround implicit internal
// intents that may not be exported which will stop working on Android U+.
- // This assumes that the source or the caller has the highest priority to resolve the intent
- // action.
Intent explicitIntent = new Intent(intent).setPackage(packageContext.getPackageName());
- if (intentResolves(packageContext, explicitIntent)) {
+ if (intentResolvesToActivity(packageContext, explicitIntent)) {
return explicitIntent;
}
- if (intentResolves(packageContext, intent)) {
- return intent;
- }
-
// resolveActivity does not return any activity when the work profile is in quiet mode, even
// though it opens the quiet mode dialog and/or the original intent would otherwise resolve
// when quiet mode is turned off. So, we assume that the explicit intent will always resolve
// to this dialog. This heuristic is preferable on U+ as it has a higher chance of resolving
// once the work profile is enabled considering the implicit internal intent restriction.
if (isQuietModeEnabled) {
+ // TODO(b/266538628): Find a way to fix this, this heuristic isn't ideal.
return explicitIntent;
}
@@ -146,14 +141,26 @@ public final class PendingIntentFactory {
private boolean shouldAddSettingsHomepageExtra(String sourceId) {
return Arrays.asList(
- mSafetyCenterResourcesContext
+ mSafetyCenterResourcesApk
.getStringByName("config_useSettingsHomepageIntentExtra")
.split(","))
.contains(sourceId);
}
- private static boolean intentResolves(Context packageContext, Intent intent) {
- return resolveActivity(packageContext, intent) != null;
+ private static boolean intentResolvesToActivity(Context packageContext, Intent intent) {
+ ResolveInfo resolveInfo = resolveActivity(packageContext, intent);
+ if (resolveInfo == null) {
+ return false;
+ }
+ ActivityInfo activityInfo = resolveInfo.activityInfo;
+ if (activityInfo == null) {
+ return false;
+ }
+ boolean intentIsImplicit = intent.getPackage() == null && intent.getComponent() == null;
+ if (intentIsImplicit) {
+ return activityInfo.exported;
+ }
+ return true;
}
@Nullable
@@ -235,7 +242,8 @@ public final class PendingIntentFactory {
// This call requires the INTERACT_ACROSS_USERS permission.
final long callingId = Binder.clearCallingIdentity();
try {
- return context.createPackageContextAsUser(packageName, 0, UserHandle.of(userId));
+ return context.createPackageContextAsUser(
+ packageName, /* flags= */ 0, UserHandle.of(userId));
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Package name " + packageName + " not found", e);
return null;
diff --git a/service/java/com/android/safetycenter/RefreshReasons.java b/service/java/com/android/safetycenter/RefreshReasons.java
index ee318c7fd..f62d4cddb 100644
--- a/service/java/com/android/safetycenter/RefreshReasons.java
+++ b/service/java/com/android/safetycenter/RefreshReasons.java
@@ -16,7 +16,6 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA;
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA;
@@ -33,12 +32,7 @@ import android.safetycenter.SafetyCenterManager.RefreshReason;
import android.safetycenter.SafetyCenterManager.RefreshRequestType;
import android.util.Log;
-import androidx.annotation.RequiresApi;
-
-import com.android.modules.utils.build.SdkLevel;
-
/** Helpers to do with {@link RefreshReason}. */
-@RequiresApi(TIRAMISU)
final class RefreshReasons {
private static final String TAG = "RefreshReasons";
@@ -49,6 +43,7 @@ final class RefreshReasons {
* Validates the given {@link RefreshReason}, and throws an {@link IllegalArgumentException} in
* case of unexpected value.
*/
+ @TargetApi(UPSIDE_DOWN_CAKE)
static void validate(@RefreshReason int refreshReason) {
switch (refreshReason) {
case REFRESH_REASON_RESCAN_BUTTON_CLICK:
@@ -57,11 +52,9 @@ final class RefreshReasons {
case REFRESH_REASON_DEVICE_LOCALE_CHANGE:
case REFRESH_REASON_SAFETY_CENTER_ENABLED:
case REFRESH_REASON_OTHER:
+ case REFRESH_REASON_PERIODIC:
return;
}
- if (SdkLevel.isAtLeastU() && refreshReason == REFRESH_REASON_PERIODIC) {
- return;
- }
throw new IllegalArgumentException("Unexpected refresh reason: " + refreshReason);
}
diff --git a/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java b/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java
index e8e6befe5..a36beb2d3 100644
--- a/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java
+++ b/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java
@@ -18,8 +18,8 @@ package com.android.safetycenter;
import static android.Manifest.permission.READ_SAFETY_CENTER_STATUS;
import static android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE;
+import static android.content.Intent.FLAG_INCLUDE_STOPPED_PACKAGES;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.os.PowerExemptionManager.REASON_REFRESH_SAFETY_SOURCES;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES;
@@ -32,8 +32,6 @@ import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_SAFETY_CEN
import static java.util.Collections.unmodifiableList;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.BroadcastOptions;
import android.content.Context;
@@ -42,13 +40,12 @@ import android.os.Binder;
import android.os.UserHandle;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyCenterManager.RefreshReason;
-import android.safetycenter.SafetyCenterManager.RefreshRequestType;
import android.safetycenter.SafetySourceData;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.permission.util.PackageUtils;
import com.android.safetycenter.SafetyCenterConfigReader.Broadcast;
@@ -67,7 +64,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* <p>This class isn't thread safe. Thread safety must be handled by the caller.
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetyCenterBroadcastDispatcher {
private static final String TAG = "SafetyCenterBroadcastDi";
@@ -139,7 +135,6 @@ final class SafetyCenterBroadcastDispatcher {
String broadcastId,
@Nullable List<String> requiredSourceIds) {
boolean hasSentAtLeastOneBroadcast = false;
- int requestType = RefreshReasons.toRefreshRequestType(refreshReason);
String packageName = broadcast.getPackageName();
Set<String> deniedSourceIds = getRefreshDeniedSourceIds(refreshReason);
SparseArray<List<String>> userIdsToSourceIds =
@@ -163,7 +158,7 @@ final class SafetyCenterBroadcastDispatcher {
continue;
}
- Intent intent = createRefreshIntent(requestType, packageName, sourceIds, broadcastId);
+ Intent intent = createRefreshIntent(refreshReason, packageName, sourceIds, broadcastId);
boolean broadcastWasSent =
sendBroadcastIfResolves(intent, UserHandle.of(userId), broadcastOptions);
if (broadcastWasSent) {
@@ -198,7 +193,11 @@ final class SafetyCenterBroadcastDispatcher {
}
Intent implicitIntent = createImplicitEnabledChangedIntent();
- sendBroadcast(implicitIntent, UserHandle.SYSTEM, READ_SAFETY_CENTER_STATUS, null);
+ sendBroadcast(
+ implicitIntent,
+ UserHandle.SYSTEM,
+ READ_SAFETY_CENTER_STATUS,
+ /* broadcastOptions= */ null);
}
private void sendEnabledChangedBroadcast(
@@ -206,15 +205,17 @@ final class SafetyCenterBroadcastDispatcher {
BroadcastOptions broadcastOptions,
List<UserProfileGroup> userProfileGroups) {
Intent intent = createExplicitEnabledChangedIntent(broadcast.getPackageName());
- // The same ENABLED reason is used here for both enable and disable events. It is not sent
- // externally and is only used internally to filter safety sources in the methods of the
- // Broadcast class.
- int refreshReason = REFRESH_REASON_SAFETY_CENTER_ENABLED;
for (int i = 0; i < userProfileGroups.size(); i++) {
UserProfileGroup userProfileGroup = userProfileGroups.get(i);
SparseArray<List<String>> userIdsToSourceIds =
- getUserIdsToSourceIds(broadcast, userProfileGroup, refreshReason);
+ getUserIdsToSourceIds(
+ broadcast,
+ userProfileGroup,
+ // The same ENABLED reason is used here for both enable and disable
+ // events. It is not sent externally and is only used internally to
+ // filter safety sources in the methods of the Broadcast class.
+ REFRESH_REASON_SAFETY_CENTER_ENABLED);
for (int j = 0; j < userIdsToSourceIds.size(); j++) {
int userId = userIdsToSourceIds.keyAt(j);
@@ -229,24 +230,22 @@ final class SafetyCenterBroadcastDispatcher {
if (!doesBroadcastResolve(intent, userHandle)) {
Log.w(
TAG,
- "No receiver for intent targeting "
+ "No receiver for intent targeting: "
+ intent.getPackage()
- + " and user "
- + userHandle);
+ + ", and user id: "
+ + userHandle.getIdentifier());
return false;
}
Log.v(
TAG,
- "Found receiver for intent targeting "
+ "Found receiver for intent targeting: "
+ intent.getPackage()
- + " and user "
- + userHandle);
+ + ", and user id: "
+ + userHandle.getIdentifier());
sendBroadcast(intent, userHandle, SEND_SAFETY_CENTER_UPDATE, broadcastOptions);
return true;
}
- // TODO(b/193460475): Remove when tooling supports SystemApi to public API.
- @SuppressLint("NewApi")
private void sendBroadcast(
Intent intent,
UserHandle userHandle,
@@ -267,7 +266,7 @@ final class SafetyCenterBroadcastDispatcher {
private boolean doesBroadcastResolve(Intent broadcastIntent, UserHandle userHandle) {
return !PackageUtils.queryUnfilteredBroadcastReceiversAsUser(
- broadcastIntent, 0, userHandle.getIdentifier(), mContext)
+ broadcastIntent, /* flags= */ 0, userHandle.getIdentifier(), mContext)
.isEmpty();
}
@@ -280,24 +279,29 @@ final class SafetyCenterBroadcastDispatcher {
}
private static Intent createRefreshIntent(
- @RefreshRequestType int requestType,
+ @RefreshReason int refreshReason,
String packageName,
List<String> sourceIdsToRefresh,
String broadcastId) {
String[] sourceIdsArray = sourceIdsToRefresh.toArray(new String[0]);
- return createBroadcastIntent(ACTION_REFRESH_SAFETY_SOURCES)
- .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE, requestType)
- .putExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS, sourceIdsArray)
- .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, broadcastId)
- .setPackage(packageName);
+ int requestType = RefreshReasons.toRefreshRequestType(refreshReason);
+ Intent refreshIntent =
+ createBroadcastIntent(ACTION_REFRESH_SAFETY_SOURCES)
+ .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE, requestType)
+ .putExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS, sourceIdsArray)
+ .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, broadcastId)
+ .setPackage(packageName);
+ boolean isUserInitiated = !RefreshReasons.isBackgroundRefresh(refreshReason);
+ if (isUserInitiated) {
+ return refreshIntent.addFlags(FLAG_INCLUDE_STOPPED_PACKAGES);
+ }
+ return refreshIntent;
}
private static Intent createBroadcastIntent(String intentAction) {
- return new Intent(intentAction).setFlags(FLAG_RECEIVER_FOREGROUND);
+ return new Intent(intentAction).addFlags(FLAG_RECEIVER_FOREGROUND);
}
- // TODO(b/193460475): Remove when tooling supports SystemApi to public API.
- @SuppressLint("NewApi")
private static BroadcastOptions createBroadcastOptions() {
BroadcastOptions broadcastOptions = BroadcastOptions.makeBasic();
Duration allowListDuration = SafetyCenterFlags.getFgsAllowlistDuration();
diff --git a/service/java/com/android/safetycenter/SafetyCenterConfigReader.java b/service/java/com/android/safetycenter/SafetyCenterConfigReader.java
index 92959a47d..c473ad916 100644
--- a/service/java/com/android/safetycenter/SafetyCenterConfigReader.java
+++ b/service/java/com/android/safetycenter/SafetyCenterConfigReader.java
@@ -16,12 +16,9 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static java.util.Collections.unmodifiableList;
import static java.util.Objects.requireNonNull;
-import android.annotation.Nullable;
import android.content.res.Resources;
import android.safetycenter.config.SafetyCenterConfig;
import android.safetycenter.config.SafetySource;
@@ -29,11 +26,11 @@ import android.safetycenter.config.SafetySourcesGroup;
import android.util.ArrayMap;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.safetycenter.config.ParseException;
import com.android.safetycenter.config.SafetyCenterConfigParser;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import java.io.InputStream;
import java.io.PrintWriter;
@@ -50,21 +47,20 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
public final class SafetyCenterConfigReader {
private static final String TAG = "SafetyCenterConfigReade";
- private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
+ private final SafetyCenterResourcesApk mSafetyCenterResourcesApk;
@Nullable private SafetyCenterConfigInternal mConfigInternalFromXml;
@Nullable private SafetyCenterConfigInternal mConfigInternalOverrideForTests;
- /** Creates a {@link SafetyCenterConfigReader} from a {@link SafetyCenterResourcesContext}. */
- SafetyCenterConfigReader(SafetyCenterResourcesContext safetyCenterResourcesContext) {
- mSafetyCenterResourcesContext = safetyCenterResourcesContext;
+ /** Creates a {@link SafetyCenterConfigReader} from a {@link SafetyCenterResourcesApk}. */
+ SafetyCenterConfigReader(SafetyCenterResourcesApk safetyCenterResourcesApk) {
+ mSafetyCenterResourcesApk = safetyCenterResourcesApk;
}
/**
@@ -76,7 +72,7 @@ public final class SafetyCenterConfigReader {
* this method was {@code true}.
*/
boolean loadConfig() {
- SafetyCenterConfig safetyCenterConfig = readSafetyCenterConfig();
+ SafetyCenterConfig safetyCenterConfig = loadSafetyCenterConfig();
if (safetyCenterConfig == null) {
return false;
}
@@ -114,7 +110,7 @@ public final class SafetyCenterConfigReader {
/**
* Returns the groups of {@link SafetySource}, filtering out any sources where {@link
- * SafetySources#isLoggable(SafetySource)} is false (and any resultingly empty groups).
+ * SafetySources#isLoggable(SafetySource)} is {@code false} (and any resulting empty groups).
*/
public List<SafetySourcesGroup> getLoggableSafetySourcesGroups() {
return getCurrentConfigInternal().getLoggableSourcesGroups();
@@ -137,15 +133,15 @@ public final class SafetyCenterConfigReader {
@Nullable
public ExternalSafetySource getExternalSafetySource(
String safetySourceId, String callingPackageName) {
- SafetyCenterConfigInternal currentConfig = getCurrentConfigInternal();
+ SafetyCenterConfigInternal testConfig = mConfigInternalOverrideForTests;
SafetyCenterConfigInternal xmlConfig = requireNonNull(mConfigInternalFromXml);
- if (currentConfig == xmlConfig) {
+ if (testConfig == null) {
// No override, access source directly.
- return currentConfig.getExternalSafetySources().get(safetySourceId);
+ return xmlConfig.getExternalSafetySources().get(safetySourceId);
}
ExternalSafetySource externalSafetySourceInTestConfig =
- currentConfig.getExternalSafetySources().get(safetySourceId);
+ testConfig.getExternalSafetySources().get(safetySourceId);
ExternalSafetySource externalSafetySourceInRealConfig =
xmlConfig.getExternalSafetySources().get(safetySourceId);
@@ -179,16 +175,20 @@ public final class SafetyCenterConfigReader {
* source is expected to interact with Safety Center, but is currently being silenced / no-ops
* while an override for tests is in place.
*
- * <p>The {@code callingPackageName} is used to differentiate a real source being overridden. It
- * could be that a test is overriding a real source and as such the real source should not be
- * able to provide data while its override is in place.
+ * <p>The {@code callingPackageName} can be used to differentiate a real source being
+ * overridden. It could be that a test is overriding a real source and as such the real source
+ * should not be able to provide data while its override is in place.
*/
- public boolean isExternalSafetySourceActive(String safetySourceId, String callingPackageName) {
+ public boolean isExternalSafetySourceActive(
+ String safetySourceId, @Nullable String callingPackageName) {
ExternalSafetySource externalSafetySourceInCurrentConfig =
getCurrentConfigInternal().getExternalSafetySources().get(safetySourceId);
if (externalSafetySourceInCurrentConfig == null) {
return false;
}
+ if (callingPackageName == null) {
+ return true;
+ }
return Objects.equals(
externalSafetySourceInCurrentConfig.getSafetySource().getPackageName(),
callingPackageName);
@@ -225,26 +225,21 @@ public final class SafetyCenterConfigReader {
}
@Nullable
- private SafetyCenterConfig readSafetyCenterConfig() {
- InputStream in = mSafetyCenterResourcesContext.getSafetyCenterConfig();
+ private SafetyCenterConfig loadSafetyCenterConfig() {
+ InputStream in = mSafetyCenterResourcesApk.getSafetyCenterConfig();
if (in == null) {
- Log.e(TAG, "Cannot get safety center config file, safety center will be disabled.");
- return null;
- }
-
- Resources resources = mSafetyCenterResourcesContext.getResources();
- if (resources == null) {
- Log.e(TAG, "Cannot get safety center resources, safety center will be disabled.");
+ Log.e(TAG, "Cannot access Safety Center config file");
return null;
}
+ Resources resources = mSafetyCenterResourcesApk.getResources();
try {
SafetyCenterConfig safetyCenterConfig =
SafetyCenterConfigParser.parseXmlResource(in, resources);
- Log.i(TAG, "SafetyCenterConfig read successfully");
+ Log.d(TAG, "SafetyCenterConfig loaded successfully");
return safetyCenterConfig;
} catch (ParseException e) {
- Log.e(TAG, "Cannot read SafetyCenterConfig, safety center will be disabled.", e);
+ Log.e(TAG, "Cannot parse SafetyCenterConfig", e);
return null;
}
}
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.java b/service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.java
index e8bf2626a..0e5617c8d 100644
--- a/service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.java
+++ b/service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.java
@@ -16,12 +16,8 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import android.annotation.UserIdInt;
-import androidx.annotation.RequiresApi;
-
import com.android.safetycenter.notifications.SafetyCenterNotificationSender;
import java.util.List;
@@ -34,7 +30,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
public final class SafetyCenterDataChangeNotifier {
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataFactory.java b/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
index fe4a1ee43..d74d160f4 100644
--- a/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
+++ b/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
@@ -16,14 +16,14 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static com.android.safetycenter.internaldata.SafetyCenterBundles.ISSUES_TO_GROUPS_BUNDLE_KEY;
import static com.android.safetycenter.internaldata.SafetyCenterBundles.STATIC_ENTRIES_TO_IDS_BUNDLE_KEY;
import static java.util.Collections.emptyList;
-import android.annotation.Nullable;
+import android.annotation.TargetApi;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.Context;
@@ -50,7 +50,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
import com.android.permission.util.UserUtils;
@@ -61,7 +61,7 @@ import com.android.safetycenter.internaldata.SafetyCenterIds;
import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
import com.android.safetycenter.internaldata.SafetyCenterIssueId;
import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import java.util.ArrayList;
import java.util.List;
@@ -78,7 +78,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
public final class SafetyCenterDataFactory {
@@ -87,7 +86,7 @@ public final class SafetyCenterDataFactory {
private static final String ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID = "AndroidLockScreenSources";
private final Context mContext;
- private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
+ private final SafetyCenterResourcesApk mSafetyCenterResourcesApk;
private final SafetyCenterConfigReader mSafetyCenterConfigReader;
private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker;
private final PendingIntentFactory mPendingIntentFactory;
@@ -96,13 +95,13 @@ public final class SafetyCenterDataFactory {
SafetyCenterDataFactory(
Context context,
- SafetyCenterResourcesContext safetyCenterResourcesContext,
+ SafetyCenterResourcesApk safetyCenterResourcesApk,
SafetyCenterConfigReader safetyCenterConfigReader,
SafetyCenterRefreshTracker safetyCenterRefreshTracker,
PendingIntentFactory pendingIntentFactory,
SafetyCenterDataManager safetyCenterDataManager) {
mContext = context;
- mSafetyCenterResourcesContext = safetyCenterResourcesContext;
+ mSafetyCenterResourcesApk = safetyCenterResourcesApk;
mSafetyCenterConfigReader = safetyCenterConfigReader;
mSafetyCenterRefreshTracker = safetyCenterRefreshTracker;
mPendingIntentFactory = pendingIntentFactory;
@@ -334,7 +333,7 @@ public final class SafetyCenterDataFactory {
if (SdkLevel.isAtLeastU()) {
CharSequence issueAttributionTitle =
TextUtils.isEmpty(safetySourceIssue.getAttributionTitle())
- ? mSafetyCenterResourcesContext.getOptionalString(
+ ? mSafetyCenterResourcesApk.getOptionalString(
safetySourcesGroup.getTitleResId())
: safetySourceIssue.getAttributionTitle();
safetyCenterIssueBuilder.setAttributionTitle(issueAttributionTitle);
@@ -400,8 +399,8 @@ public final class SafetyCenterDataFactory {
safetySource,
defaultPackageName,
userProfileGroup.getProfileParentUserId(),
- false,
- false));
+ /* isUserManaged= */ false,
+ /* isManagedUserRunning= */ false));
if (!SafetySources.supportsManagedProfiles(safetySource)) {
continue;
@@ -422,7 +421,7 @@ public final class SafetyCenterDataFactory {
safetySource,
defaultPackageName,
managedProfileUserId,
- true,
+ /* isUserManaged= */ true,
isManagedUserRunning));
}
}
@@ -443,7 +442,7 @@ public final class SafetyCenterDataFactory {
new SafetyCenterEntryOrGroup(
new SafetyCenterEntryGroup.Builder(
safetySourcesGroup.getId(),
- mSafetyCenterResourcesContext.getString(
+ mSafetyCenterResourcesApk.getString(
safetySourcesGroup.getTitleResId()))
.setSeverityLevel(groupSafetyCenterEntryLevel)
.setSummary(groupSummary)
@@ -509,13 +508,10 @@ public final class SafetyCenterDataFactory {
for (int i = 0; i < entries.size(); i++) {
SafetySourceKey key = toSafetySourceKey(entries.get(i).getId());
if (mSafetyCenterDataManager.sourceHasError(key)) {
- // We always use the singular form of the error string for groups because
- // they appear as single entries in the UI and this ensures consistency,
- // especially when subpages are enabled.
- return getRefreshErrorString(1);
+ return getRefreshErrorString();
}
}
- return mSafetyCenterResourcesContext.getStringByName("group_unknown_summary");
+ return mSafetyCenterResourcesApk.getStringByName("group_unknown_summary");
}
Log.w(
@@ -529,8 +525,7 @@ public final class SafetyCenterDataFactory {
private CharSequence getDefaultGroupSummary(
SafetySourcesGroup safetySourcesGroup, List<SafetyCenterEntry> entries) {
CharSequence groupSummary =
- mSafetyCenterResourcesContext.getOptionalString(
- safetySourcesGroup.getSummaryResId());
+ mSafetyCenterResourcesApk.getOptionalString(safetySourcesGroup.getSummaryResId());
if (safetySourcesGroup.getId().equals(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
&& TextUtils.isEmpty(groupSummary)) {
@@ -649,7 +644,7 @@ public final class SafetyCenterDataFactory {
.setSummary(
inQuietMode
? DevicePolicyResources.getWorkProfilePausedString(
- mSafetyCenterResourcesContext)
+ mSafetyCenterResourcesApk)
: safetySourceStatus.getSummary())
.setEnabled(enabled)
.setSeverityUnspecifiedIconType(severityUnspecifiedIconType)
@@ -710,20 +705,19 @@ public final class SafetyCenterDataFactory {
CharSequence title =
isUserManaged
? DevicePolicyResources.getSafetySourceWorkString(
- mSafetyCenterResourcesContext,
+ mSafetyCenterResourcesApk,
safetySource.getId(),
safetySource.getTitleForWorkResId())
- : mSafetyCenterResourcesContext.getString(safetySource.getTitleResId());
+ : mSafetyCenterResourcesApk.getString(safetySource.getTitleResId());
CharSequence summary =
mSafetyCenterDataManager.sourceHasError(
SafetySourceKey.of(safetySource.getId(), userId))
- ? getRefreshErrorString(1)
- : mSafetyCenterResourcesContext.getOptionalString(
+ ? getRefreshErrorString()
+ : mSafetyCenterResourcesApk.getOptionalString(
safetySource.getSummaryResId());
if (isQuietModeEnabled) {
enabled = false;
- summary =
- DevicePolicyResources.getWorkProfilePausedString(mSafetyCenterResourcesContext);
+ summary = DevicePolicyResources.getWorkProfilePausedString(mSafetyCenterResourcesApk);
}
return new SafetyCenterEntry.Builder(
SafetyCenterIds.encodeToString(safetyCenterEntryId), title)
@@ -754,8 +748,8 @@ public final class SafetyCenterDataFactory {
safetySource,
defaultPackageName,
userProfileGroup.getProfileParentUserId(),
- false,
- false);
+ /* isUserManaged= */ false,
+ /* isManagedUserRunning= */ false);
if (!SafetySources.supportsManagedProfiles(safetySource)) {
continue;
@@ -774,7 +768,7 @@ public final class SafetyCenterDataFactory {
safetySource,
defaultPackageName,
managedProfileUserId,
- true,
+ /* isUserManaged= */ true,
isManagedUserRunning);
}
}
@@ -785,7 +779,7 @@ public final class SafetyCenterDataFactory {
safetyCenterStaticEntryGroups.add(
new SafetyCenterStaticEntryGroup(
- mSafetyCenterResourcesContext.getString(safetySourcesGroup.getTitleResId()),
+ mSafetyCenterResourcesApk.getString(safetySourcesGroup.getTitleResId()),
staticEntries));
}
@@ -864,7 +858,7 @@ public final class SafetyCenterDataFactory {
.setSummary(
inQuietMode
? DevicePolicyResources.getWorkProfilePausedString(
- mSafetyCenterResourcesContext)
+ mSafetyCenterResourcesApk)
: safetySourceStatus.getSummary())
.setPendingIntent(entryPendingIntent)
.build();
@@ -914,19 +908,18 @@ public final class SafetyCenterDataFactory {
CharSequence title =
isUserManaged
? DevicePolicyResources.getSafetySourceWorkString(
- mSafetyCenterResourcesContext,
+ mSafetyCenterResourcesApk,
safetySource.getId(),
safetySource.getTitleForWorkResId())
- : mSafetyCenterResourcesContext.getString(safetySource.getTitleResId());
+ : mSafetyCenterResourcesApk.getString(safetySource.getTitleResId());
CharSequence summary =
mSafetyCenterDataManager.sourceHasError(
SafetySourceKey.of(safetySource.getId(), userId))
- ? getRefreshErrorString(1)
- : mSafetyCenterResourcesContext.getOptionalString(
+ ? getRefreshErrorString()
+ : mSafetyCenterResourcesApk.getOptionalString(
safetySource.getSummaryResId());
if (isQuietModeEnabled) {
- summary =
- DevicePolicyResources.getWorkProfilePausedString(mSafetyCenterResourcesContext);
+ summary = DevicePolicyResources.getWorkProfilePausedString(mSafetyCenterResourcesApk);
}
return new SafetyCenterStaticEntry.Builder(title)
.setSummary(summary)
@@ -1088,11 +1081,10 @@ public final class SafetyCenterDataFactory {
case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
if (hasSettingsToReview) {
- return mSafetyCenterResourcesContext.getStringByName(
+ return mSafetyCenterResourcesApk.getStringByName(
"overall_severity_level_ok_review_title");
}
- return mSafetyCenterResourcesContext.getStringByName(
- "overall_severity_level_ok_title");
+ return mSafetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title");
case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
return getStatusTitleFromIssueCategories(
topNonDismissedIssueInfo,
@@ -1117,6 +1109,7 @@ public final class SafetyCenterDataFactory {
return "";
}
+ @TargetApi(UPSIDE_DOWN_CAKE)
private String getStatusTitleFromIssueCategories(
@Nullable SafetySourceIssueInfo topNonDismissedIssueInfo,
String deviceResourceName,
@@ -1125,7 +1118,7 @@ public final class SafetyCenterDataFactory {
String dataResourceName,
String passwordsResourceName,
String personalSafetyResourceName) {
- String generalString = mSafetyCenterResourcesContext.getStringByName(generalResourceName);
+ String generalString = mSafetyCenterResourcesApk.getStringByName(generalResourceName);
if (topNonDismissedIssueInfo == null) {
Log.w(TAG, "No safety center issues found in a non-green status");
return generalString;
@@ -1133,22 +1126,17 @@ public final class SafetyCenterDataFactory {
int issueCategory = topNonDismissedIssueInfo.getSafetySourceIssue().getIssueCategory();
switch (issueCategory) {
case SafetySourceIssue.ISSUE_CATEGORY_DEVICE:
- return mSafetyCenterResourcesContext.getStringByName(deviceResourceName);
+ return mSafetyCenterResourcesApk.getStringByName(deviceResourceName);
case SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT:
- return mSafetyCenterResourcesContext.getStringByName(accountResourceName);
+ return mSafetyCenterResourcesApk.getStringByName(accountResourceName);
case SafetySourceIssue.ISSUE_CATEGORY_GENERAL:
return generalString;
- }
- if (SdkLevel.isAtLeastU()) {
- switch (issueCategory) {
- case SafetySourceIssue.ISSUE_CATEGORY_DATA:
- return mSafetyCenterResourcesContext.getStringByName(dataResourceName);
- case SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS:
- return mSafetyCenterResourcesContext.getStringByName(passwordsResourceName);
- case SafetySourceIssue.ISSUE_CATEGORY_PERSONAL_SAFETY:
- return mSafetyCenterResourcesContext.getStringByName(
- personalSafetyResourceName);
- }
+ case SafetySourceIssue.ISSUE_CATEGORY_DATA:
+ return mSafetyCenterResourcesApk.getStringByName(dataResourceName);
+ case SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS:
+ return mSafetyCenterResourcesApk.getStringByName(passwordsResourceName);
+ case SafetySourceIssue.ISSUE_CATEGORY_PERSONAL_SAFETY:
+ return mSafetyCenterResourcesApk.getStringByName(personalSafetyResourceName);
}
Log.w(TAG, "Unexpected SafetySourceIssue.IssueCategory: " + issueCategory);
@@ -1172,17 +1160,16 @@ public final class SafetyCenterDataFactory {
case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
if (topNonDismissedIssue == null) {
if (safetyCenterOverallState.hasSettingsToReview()) {
- return mSafetyCenterResourcesContext.getStringByName(
+ return mSafetyCenterResourcesApk.getStringByName(
"overall_severity_level_ok_review_summary");
}
- return mSafetyCenterResourcesContext.getStringByName(
+ return mSafetyCenterResourcesApk.getStringByName(
"overall_severity_level_ok_summary");
} else if (isTip(topNonDismissedIssue.getSafetySourceIssue())) {
- return mSafetyCenterResourcesContext.getStringByName(
- "overall_severity_level_tip_summary", numTipIssues);
+ return getIcuPluralsString("overall_severity_level_tip_summary", numTipIssues);
} else if (isAutomatic(topNonDismissedIssue.getSafetySourceIssue())) {
- return mSafetyCenterResourcesContext.getStringByName(
+ return getIcuPluralsString(
"overall_severity_level_action_taken_summary", numAutomaticIssues);
}
// Fall through.
@@ -1207,14 +1194,14 @@ public final class SafetyCenterDataFactory {
== SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC;
}
- private String getRefreshErrorString(int numberOfErrorEntries) {
- return getIcuPluralsString("refresh_error", numberOfErrorEntries);
+ private String getRefreshErrorString() {
+ return getIcuPluralsString("refresh_error", /* count= */ 1);
}
private String getIcuPluralsString(String name, int count, Object... formatArgs) {
MessageFormat messageFormat =
new MessageFormat(
- mSafetyCenterResourcesContext.getStringByName(name, formatArgs),
+ mSafetyCenterResourcesApk.getStringByName(name, formatArgs),
Locale.getDefault());
ArrayMap<String, Object> arguments = new ArrayMap<>();
arguments.put("count", count);
@@ -1233,7 +1220,7 @@ public final class SafetyCenterDataFactory {
}
// Fall through.
case SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS:
- return mSafetyCenterResourcesContext.getStringByName("scanning_title");
+ return mSafetyCenterResourcesApk.getStringByName("scanning_title");
}
Log.w(TAG, "Unexpected SafetyCenterStatus.RefreshStatus: " + refreshStatus);
@@ -1248,7 +1235,7 @@ public final class SafetyCenterDataFactory {
return null;
case SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS:
case SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS:
- return mSafetyCenterResourcesContext.getStringByName("loading_summary");
+ return mSafetyCenterResourcesApk.getStringByName("loading_summary");
}
Log.w(TAG, "Unexpected SafetyCenterStatus.RefreshStatus: " + refreshStatus);
diff --git a/service/java/com/android/safetycenter/SafetyCenterFlags.java b/service/java/com/android/safetycenter/SafetyCenterFlags.java
index 1fc88d4b0..e51d3a1cf 100644
--- a/service/java/com/android/safetycenter/SafetyCenterFlags.java
+++ b/service/java/com/android/safetycenter/SafetyCenterFlags.java
@@ -16,10 +16,8 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.safetycenter.SafetyCenterManager.RefreshReason;
-import android.annotation.Nullable;
import android.os.Binder;
import android.provider.DeviceConfig;
import android.safetycenter.SafetySourceData;
@@ -27,20 +25,22 @@ import android.safetycenter.SafetySourceIssue;
import android.util.ArraySet;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import java.io.PrintWriter;
import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
* A class to access the Safety Center {@link DeviceConfig} flags.
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class SafetyCenterFlags {
private static final String TAG = "SafetyCenterFlags";
@@ -63,9 +63,6 @@ public final class SafetyCenterFlags {
private static final String PROPERTY_NOTIFICATION_RESURFACE_INTERVAL =
"safety_center_notification_resurface_interval";
- private static final String PROPERTY_SHOW_ERROR_ENTRIES_ON_TIMEOUT =
- "safety_center_show_error_entries_on_timeout";
-
private static final String PROPERTY_REPLACE_LOCK_SCREEN_ICON_ACTION =
"safety_center_replace_lock_screen_icon_action";
@@ -108,6 +105,9 @@ public final class SafetyCenterFlags {
private static final String PROPERTY_TEMP_HIDDEN_ISSUE_RESURFACE_DELAY_MILLIS =
"safety_center_temp_hidden_issue_resurface_delay_millis";
+ private static final String PROPERTY_ACTIONS_TO_OVERRIDE_WITH_DEFAULT_INTENT =
+ "safety_center_actions_to_override_with_default_intent";
+
private static final Duration RESOLVING_ACTION_TIMEOUT_DEFAULT_DURATION =
Duration.ofSeconds(10);
@@ -123,6 +123,9 @@ public final class SafetyCenterFlags {
private static final String RESURFACE_ISSUE_DELAYS_DEFAULT = "";
private static final Duration RESURFACE_ISSUE_DELAYS_DEFAULT_DURATION = Duration.ofDays(180);
+ private static final ArraySet<String> sAllowedNotificationSourcesUPlus =
+ new ArraySet<>(new String[] {"GoogleBackupAndRestore"});
+
private static volatile String sUntrackedSourcesDefault =
"AndroidAccessibility,AndroidBackgroundLocation,"
+ "AndroidNotificationListener,AndroidPermissionAutoRevoke";
@@ -131,30 +134,40 @@ public final class SafetyCenterFlags {
private static volatile String sIssueCategoryAllowlistDefault = "";
- private static volatile String sRefreshOnPageOpenSourcesDefault =
- "AndroidBiometrics,AndroidLockScreen";
+ private static volatile String sRefreshOnPageOpenSourcesDefault = "AndroidBiometrics";
+
+ private static volatile String sActionsToOverrideWithDefaultIntentDefault = "";
- static void init(SafetyCenterResourcesContext resourceContext) {
+ static void init(SafetyCenterResourcesApk safetyCenterResourcesApk) {
String untrackedSourcesDefault =
- resourceContext.getOptionalStringByName("config_defaultUntrackedSources");
+ safetyCenterResourcesApk.getOptionalStringByName("config_defaultUntrackedSources");
if (untrackedSourcesDefault != null) {
sUntrackedSourcesDefault = untrackedSourcesDefault;
}
String backgroundRefreshDenyDefault =
- resourceContext.getOptionalStringByName("config_defaultBackgroundRefreshDeny");
+ safetyCenterResourcesApk.getOptionalStringByName(
+ "config_defaultBackgroundRefreshDeny");
if (backgroundRefreshDenyDefault != null) {
sBackgroundRefreshDenyDefault = backgroundRefreshDenyDefault;
}
String issueCategoryAllowlistDefault =
- resourceContext.getOptionalStringByName("config_defaultIssueCategoryAllowlist");
+ safetyCenterResourcesApk.getOptionalStringByName(
+ "config_defaultIssueCategoryAllowlist");
if (issueCategoryAllowlistDefault != null) {
sIssueCategoryAllowlistDefault = issueCategoryAllowlistDefault;
}
String refreshOnPageOpenSourcesDefault =
- resourceContext.getOptionalStringByName("config_defaultRefreshOnPageOpenSources");
+ safetyCenterResourcesApk.getOptionalStringByName(
+ "config_defaultRefreshOnPageOpenSources");
if (refreshOnPageOpenSourcesDefault != null) {
sRefreshOnPageOpenSourcesDefault = refreshOnPageOpenSourcesDefault;
}
+ String actionsToOverrideWithDefaultIntentDefault =
+ safetyCenterResourcesApk.getOptionalStringByName(
+ "config_defaultActionsToOverrideWithDefaultIntent");
+ if (actionsToOverrideWithDefaultIntentDefault != null) {
+ sActionsToOverrideWithDefaultIntentDefault = actionsToOverrideWithDefaultIntentDefault;
+ }
}
private static final Duration TEMP_HIDDEN_ISSUE_RESURFACE_DELAY_DEFAULT_DURATION =
@@ -165,7 +178,10 @@ public final class SafetyCenterFlags {
fout.println("FLAGS");
printFlag(fout, PROPERTY_SAFETY_CENTER_ENABLED, getSafetyCenterEnabled());
printFlag(fout, PROPERTY_NOTIFICATIONS_ENABLED, getNotificationsEnabled());
- printFlag(fout, PROPERTY_NOTIFICATIONS_ALLOWED_SOURCES, getNotificationsAllowedSourceIds());
+ printFlag(
+ fout,
+ PROPERTY_NOTIFICATIONS_ALLOWED_SOURCES,
+ getNotificationsAllowedSourceIdsFlag());
printFlag(fout, PROPERTY_NOTIFICATIONS_MIN_DELAY, getNotificationsMinDelay());
printFlag(
fout,
@@ -173,7 +189,6 @@ public final class SafetyCenterFlags {
getImmediateNotificationBehaviorIssues());
printFlag(
fout, PROPERTY_NOTIFICATION_RESURFACE_INTERVAL, getNotificationResurfaceInterval());
- printFlag(fout, PROPERTY_SHOW_ERROR_ENTRIES_ON_TIMEOUT, getShowErrorEntriesOnTimeout());
printFlag(fout, PROPERTY_REPLACE_LOCK_SCREEN_ICON_ACTION, getReplaceLockScreenIconAction());
printFlag(fout, PROPERTY_RESOLVING_ACTION_TIMEOUT_MILLIS, getResolvingActionTimeout());
printFlag(fout, PROPERTY_FGS_ALLOWLIST_DURATION_MILLIS, getFgsAllowlistDuration());
@@ -235,6 +250,20 @@ public final class SafetyCenterFlags {
* and therefore this is the only way to enable notifications for sources on Android T.
*/
public static ArraySet<String> getNotificationsAllowedSourceIds() {
+ ArraySet<String> sources = getNotificationsAllowedSourceIdsFlag();
+ if (SdkLevel.isAtLeastU()) {
+ // This is a hack to update the flag value via mainline update. Reasons why we can't do
+ // this via:
+ // remote flag update - these are generally avoided and considered risky
+ // XML config - it would break GTS tests for OEMs that have a separate config copy
+ // default flag value - it would also require a remote flag update
+ sources.addAll(sAllowedNotificationSourcesUPlus);
+ }
+
+ return sources;
+ }
+
+ private static ArraySet<String> getNotificationsAllowedSourceIdsFlag() {
return getCommaSeparatedStrings(PROPERTY_NOTIFICATIONS_ALLOWED_SOURCES);
}
@@ -284,13 +313,6 @@ public final class SafetyCenterFlags {
}
/**
- * Returns whether we should show error entries for sources that timeout when refreshing them.
- */
- static boolean getShowErrorEntriesOnTimeout() {
- return getBoolean(PROPERTY_SHOW_ERROR_ENTRIES_ON_TIMEOUT, true);
- }
-
- /**
* Returns whether we should replace the lock screen source's {@link
* android.safetycenter.SafetySourceStatus.IconAction}.
*/
@@ -407,6 +429,17 @@ public final class SafetyCenterFlags {
return getString(PROPERTY_RESURFACE_ISSUE_DELAYS_MILLIS, RESURFACE_ISSUE_DELAYS_DEFAULT);
}
+ /**
+ * Returns a comma-delimited list of colon-delimited pairs of SourceId:ActionId. The action IDs
+ * listed by this flag should have their {@code PendingIntent}s overridden with the source's
+ * default intent drawn from Safety Center's config file, if available.
+ */
+ private static String getActionsToOverrideWithDefaultIntent() {
+ return getString(
+ PROPERTY_ACTIONS_TO_OVERRIDE_WITH_DEFAULT_INTENT,
+ sActionsToOverrideWithDefaultIntentDefault);
+ }
+
/** Returns a duration after which a temporarily hidden issue will resurface. */
public static Duration getTemporarilyHiddenIssueResurfaceDelay() {
return getDuration(
@@ -420,19 +453,10 @@ public final class SafetyCenterFlags {
*/
public static boolean isIssueCategoryAllowedForSource(
@SafetySourceIssue.IssueCategory int issueCategory, String safetySourceId) {
- String issueCategoryAllowlists = getIssueCategoryAllowlists();
- String allowlistString =
- getStringValueFromStringMapping(issueCategoryAllowlists, issueCategory);
- if (allowlistString == null) {
- return true;
- }
- String[] allowlistArray = allowlistString.split("\\|");
- for (int i = 0; i < allowlistArray.length; i++) {
- if (allowlistArray[i].equals(safetySourceId)) {
- return true;
- }
- }
- return false;
+ List<String> allowlist =
+ getStringListValueFromStringMapping(
+ getIssueCategoryAllowlists(), Integer.toString(issueCategory));
+ return allowlist.isEmpty() || allowlist.contains(safetySourceId);
}
/** Returns a set of package certificates allowlisted for the given package name. */
@@ -442,7 +466,7 @@ public final class SafetyCenterFlags {
if (allowlistedCertString == null) {
return new ArraySet<>();
}
- return new ArraySet<String>(allowlistedCertString.split("\\|"));
+ return new ArraySet<>(allowlistedCertString.split("\\|"));
}
/**
@@ -464,6 +488,16 @@ public final class SafetyCenterFlags {
}
/**
+ * Returns a list of action IDs that should be overridden with the source's default intent drawn
+ * from the config for a given source.
+ */
+ public static List<String> getActionsToOverrideWithDefaultIntentForSource(
+ String safetySourceId) {
+ return getStringListValueFromStringMapping(
+ getActionsToOverrideWithDefaultIntent(), safetySourceId);
+ }
+
+ /**
* Returns whether to show subpages in the Safety Center UI for Android-U instead of the
* expand-and-collapse list implementation.
*/
@@ -527,15 +561,15 @@ public final class SafetyCenterFlags {
* pairs of integers and longs.
*/
@Nullable
- private static Long getLongValueFromStringMapping(String config, int key) {
- String valueString = getStringValueFromStringMapping(config, key);
+ private static Long getLongValueFromStringMapping(String mapping, int key) {
+ String valueString = getStringValueFromStringMapping(mapping, key);
if (valueString == null) {
return null;
}
try {
return Long.parseLong(valueString);
} catch (NumberFormatException e) {
- Log.w(TAG, "Badly formatted string config: " + config, e);
+ Log.w(TAG, "Badly formatted string mapping: " + mapping, e);
return null;
}
}
@@ -545,8 +579,8 @@ public final class SafetyCenterFlags {
* of integers and strings.
*/
@Nullable
- private static String getStringValueFromStringMapping(String config, int key) {
- return getStringValueFromStringMapping(config, Integer.toString(key));
+ private static String getStringValueFromStringMapping(String mapping, int key) {
+ return getStringValueFromStringMapping(mapping, Integer.toString(key));
}
/**
@@ -554,15 +588,15 @@ public final class SafetyCenterFlags {
* string pairs.
*/
@Nullable
- private static String getStringValueFromStringMapping(String config, String key) {
- if (config.isEmpty()) {
+ private static String getStringValueFromStringMapping(String mapping, String key) {
+ if (mapping.isEmpty()) {
return null;
}
- String[] pairsList = config.split(",");
+ String[] pairsList = mapping.split(",");
for (int i = 0; i < pairsList.length; i++) {
String[] pair = pairsList[i].split(":", -1 /* allow trailing empty strings */);
if (pair.length != 2) {
- Log.w(TAG, "Badly formatted string config: " + config);
+ Log.w(TAG, "Badly formatted string mapping: " + mapping);
continue;
}
if (pair[0].equals(key)) {
@@ -572,5 +606,14 @@ public final class SafetyCenterFlags {
return null;
}
+ private static List<String> getStringListValueFromStringMapping(String mapping, String key) {
+ String value = getStringValueFromStringMapping(mapping, key);
+ if (value == null) {
+ return Collections.emptyList();
+ }
+
+ return Arrays.asList(value.split("\\|"));
+ }
+
private SafetyCenterFlags() {}
}
diff --git a/service/java/com/android/safetycenter/SafetyCenterListeners.java b/service/java/com/android/safetycenter/SafetyCenterListeners.java
index 9e07c3d17..5f89f46ff 100644
--- a/service/java/com/android/safetycenter/SafetyCenterListeners.java
+++ b/service/java/com/android/safetycenter/SafetyCenterListeners.java
@@ -16,9 +16,6 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.os.IBinder;
import android.os.RemoteCallbackList;
@@ -30,7 +27,7 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicReference;
@@ -43,7 +40,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* <p>This class isn't thread safe. Thread safety must be handled by the caller.
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetyCenterListeners {
@@ -67,7 +63,7 @@ final class SafetyCenterListeners {
try {
listener.onSafetyCenterDataChanged(safetyCenterData);
} catch (RemoteException e) {
- Log.e(TAG, "Error delivering SafetyCenterData to listener", e);
+ Log.w(TAG, "Error delivering SafetyCenterData to listener", e);
}
}
@@ -81,7 +77,7 @@ final class SafetyCenterListeners {
try {
listener.onError(safetyCenterErrorDetails);
} catch (RemoteException e) {
- Log.e(TAG, "Error delivering SafetyCenterErrorDetails to listener", e);
+ Log.w(TAG, "Error delivering SafetyCenterErrorDetails to listener", e);
}
}
@@ -94,7 +90,11 @@ final class SafetyCenterListeners {
int[] relevantUserIds = userProfileGroup.getProfileParentAndManagedRunningProfilesUserIds();
for (int i = 0; i < relevantUserIds.length; i++) {
deliverUpdateForUser(
- relevantUserIds[i], userProfileGroup, safetyCenterDataCache, true, null);
+ relevantUserIds[i],
+ userProfileGroup,
+ safetyCenterDataCache,
+ /* updateSafetyCenterData= */ true,
+ /* safetyCenterErrorDetails= */ null);
}
}
@@ -111,7 +111,7 @@ final class SafetyCenterListeners {
relevantUserIds[i],
userProfileGroup,
safetyCenterDataCache,
- false,
+ /* updateSafetyCenterData= */ false,
safetyCenterErrorDetails);
}
}
diff --git a/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java b/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java
index a28ce7d22..d98127300 100644
--- a/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java
+++ b/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java
@@ -16,14 +16,12 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK;
import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT;
import static com.android.safetycenter.logging.SafetyCenterStatsdLogger.toSystemEventResult;
import android.annotation.ElapsedRealtimeLong;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.os.SystemClock;
@@ -34,7 +32,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.permission.util.UserUtils;
import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
@@ -53,7 +51,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
public final class SafetyCenterRefreshTracker {
private static final String TAG = "SafetyCenterRefreshTrac";
@@ -78,15 +75,15 @@ public final class SafetyCenterRefreshTracker {
String reportRefreshInProgress(
@RefreshReason int refreshReason, UserProfileGroup userProfileGroup) {
if (mRefreshInProgress != null) {
- Log.w(TAG, "Replacing an ongoing refresh");
+ Log.i(TAG, "Replacing ongoing refresh with id: " + mRefreshInProgress.getId());
}
String refreshBroadcastId = UUID.randomUUID() + "_" + mRefreshCounter++;
- Log.v(
+ Log.d(
TAG,
- "Starting a new refresh with refreshReason:"
+ "Starting a new refresh with reason: "
+ refreshReason
- + " refreshBroadcastId:"
+ + ", and id: "
+ refreshBroadcastId);
mRefreshInProgress =
@@ -158,8 +155,7 @@ public final class SafetyCenterRefreshTracker {
*/
public boolean reportSourceRefreshCompleted(
String refreshBroadcastId,
- String sourceId,
- @UserIdInt int userId,
+ SafetySourceKey safetySourceKey,
boolean successful,
boolean dataChanged) {
RefreshInProgress refreshInProgress =
@@ -168,9 +164,9 @@ public final class SafetyCenterRefreshTracker {
return false;
}
- SafetySourceKey sourceKey = SafetySourceKey.of(sourceId, userId);
Duration duration =
- refreshInProgress.markSourceRefreshComplete(sourceKey, successful, dataChanged);
+ refreshInProgress.markSourceRefreshComplete(
+ safetySourceKey, successful, dataChanged);
int refreshReason = refreshInProgress.getReason();
int requestType = RefreshReasons.toRefreshRequestType(refreshReason);
@@ -178,8 +174,8 @@ public final class SafetyCenterRefreshTracker {
int sourceResult = toSystemEventResult(successful);
SafetyCenterStatsdLogger.writeSourceRefreshSystemEvent(
requestType,
- sourceId,
- UserUtils.isManagedProfile(userId, mContext),
+ safetySourceKey.getSourceId(),
+ UserUtils.isManagedProfile(safetySourceKey.getUserId(), mContext),
duration,
sourceResult,
refreshReason,
@@ -237,7 +233,7 @@ public final class SafetyCenterRefreshTracker {
*/
void clearRefreshForUser(@UserIdInt int userId) {
if (mRefreshInProgress == null) {
- Log.v(TAG, "Clear refresh for user called but no refresh in progress");
+ Log.d(TAG, "Clear refresh for user called but no refresh in progress");
return;
}
if (mRefreshInProgress.clearForUser(userId)) {
@@ -272,6 +268,15 @@ public final class SafetyCenterRefreshTracker {
int refreshReason = clearedRefresh.getReason();
int requestType = RefreshReasons.toRefreshRequestType(refreshReason);
+ Log.w(
+ TAG,
+ "Timeout after "
+ + clearedRefresh.getDurationSinceStart()
+ + " for refresh with reason: "
+ + refreshReason
+ + ", and id: "
+ + clearedRefresh.getId());
+
for (int i = 0; i < timedOutSources.size(); i++) {
SafetySourceKey sourceKey = timedOutSources.valueAt(i);
Duration duration = clearedRefresh.getDurationSinceSourceStart(sourceKey);
@@ -285,6 +290,15 @@ public final class SafetyCenterRefreshTracker {
refreshReason,
false);
}
+
+ Log.w(
+ TAG,
+ "Refresh with id: "
+ + clearedRefresh.getId()
+ + " timed out for tracked source id: "
+ + sourceKey.getSourceId()
+ + ", and user id: "
+ + sourceKey.getUserId());
}
SafetyCenterStatsdLogger.writeWholeRefreshSystemEvent(
@@ -298,7 +312,7 @@ public final class SafetyCenterRefreshTracker {
}
/**
- * Clears the any refresh in progress and returns it for the caller to do what it needs to.
+ * Clears the refresh in progress and returns it for the caller to do what it needs to.
*
* <p>If there was no refresh in progress then {@code null} is returned.
*/
@@ -306,11 +320,11 @@ public final class SafetyCenterRefreshTracker {
private RefreshInProgress clearRefreshInternal() {
RefreshInProgress refreshToClear = mRefreshInProgress;
if (refreshToClear == null) {
- Log.v(TAG, "Clear refresh called but no refresh in progress");
+ Log.d(TAG, "Clear refresh called but no refresh in progress");
return null;
}
- Log.v(TAG, "Clearing refresh with refreshBroadcastId:" + refreshToClear.getId());
+ Log.v(TAG, "Clearing refresh with id: " + refreshToClear.getId());
mRefreshInProgress = null;
return refreshToClear;
}
@@ -324,13 +338,7 @@ public final class SafetyCenterRefreshTracker {
String methodName, String refreshBroadcastId) {
RefreshInProgress refreshInProgress = mRefreshInProgress;
if (refreshInProgress == null || !refreshInProgress.getId().equals(refreshBroadcastId)) {
- Log.i(
- TAG,
- methodName
- + " called for invalid refresh broadcast id: "
- + refreshBroadcastId
- + "; no such refresh in"
- + " progress");
+ Log.i(TAG, methodName + " called with invalid refresh id: " + refreshBroadcastId);
return null;
}
return refreshInProgress;
@@ -435,19 +443,19 @@ public final class SafetyCenterRefreshTracker {
}
Log.v(
TAG,
- "Refresh started for sourceId:"
+ "Refresh with id: "
+ + mId
+ + " started for source id: "
+ safetySourceKey.getSourceId()
- + " userId:"
+ + ", user id: "
+ safetySourceKey.getUserId()
- + " with refreshBroadcastId:"
- + mId
- + " at currentElapsedMillis:"
+ + ", elapsed millis: "
+ currentElapsedMillis
- + " & tracking:"
+ + ", tracking: "
+ tracked
+ ", now "
+ mSourceRefreshesInFlight.size()
- + " tracked sources in flight.");
+ + " tracked sources in flight");
}
@Nullable
@@ -464,23 +472,23 @@ public final class SafetyCenterRefreshTracker {
: Duration.ofMillis(SystemClock.elapsedRealtime() - startElapsedMillis);
Log.v(
TAG,
- "Refresh completed for sourceId:"
+ "Refresh with id: "
+ + mId
+ + " completed for source id: "
+ safetySourceKey.getSourceId()
- + " userId:"
+ + ", user id: "
+ safetySourceKey.getUserId()
- + " with refreshBroadcastId:"
- + mId
- + " duration:"
+ + ", duration: "
+ duration
- + " successful:"
+ + ", successful: "
+ successful
- + " dataChanged:"
+ + ", data changed: "
+ dataChanged
- + " & tracking:"
+ + ", tracking: "
+ tracked
- + ", "
+ + ", now "
+ mSourceRefreshesInFlight.size()
- + " tracked sources still in flight.");
+ + " tracked sources in flight");
return duration;
}
diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java
index f23f041bd..62d0a0d78 100644
--- a/service/java/com/android/safetycenter/SafetyCenterService.java
+++ b/service/java/com/android/safetycenter/SafetyCenterService.java
@@ -21,8 +21,8 @@ import static android.Manifest.permission.READ_SAFETY_CENTER_STATUS;
import static android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_DEVICE_LOCALE_CHANGE;
import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_OTHER;
import static android.safetycenter.SafetyCenterManager.RefreshReason;
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED;
@@ -35,11 +35,10 @@ import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriend
import static java.util.Objects.requireNonNull;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.PendingIntent;
import android.app.StatsManager;
-import android.app.StatsManager.StatsPullAtomCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -69,13 +68,17 @@ import android.util.ArraySet;
import android.util.Log;
import androidx.annotation.Keep;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.internal.annotations.GuardedBy;
import com.android.modules.utils.BackgroundThread;
+import com.android.modules.utils.build.SdkLevel;
import com.android.permission.util.ForegroundThread;
import com.android.permission.util.UserUtils;
import com.android.safetycenter.data.SafetyCenterDataManager;
+import com.android.safetycenter.data.SafetyEventFix;
+import com.android.safetycenter.data.SafetySourceDataFix;
import com.android.safetycenter.internaldata.SafetyCenterIds;
import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
import com.android.safetycenter.internaldata.SafetyCenterIssueId;
@@ -85,16 +88,13 @@ import com.android.safetycenter.notifications.SafetyCenterNotificationChannels;
import com.android.safetycenter.notifications.SafetyCenterNotificationReceiver;
import com.android.safetycenter.notifications.SafetyCenterNotificationSender;
import com.android.safetycenter.pendingintents.PendingIntentSender;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.Executor;
-
-import javax.annotation.concurrent.NotThreadSafe;
/**
* Service for the safety center.
@@ -102,7 +102,6 @@ import javax.annotation.concurrent.NotThreadSafe;
* @hide
*/
@Keep
-@RequiresApi(TIRAMISU)
public final class SafetyCenterService extends SystemService {
private static final String TAG = "SafetyCenterService";
@@ -112,9 +111,8 @@ public final class SafetyCenterService extends SystemService {
@GuardedBy("mApiLock")
private final SafetyCenterTimeouts mSafetyCenterTimeouts = new SafetyCenterTimeouts();
- private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
-
- private final SafetyCenterNotificationChannels mNotificationChannels;
+ @GuardedBy("mApiLock")
+ private final SafetyCenterResourcesApk mSafetyCenterResourcesApk;
@GuardedBy("mApiLock")
private final SafetyCenterConfigReader mSafetyCenterConfigReader;
@@ -122,6 +120,8 @@ public final class SafetyCenterService extends SystemService {
@GuardedBy("mApiLock")
private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker;
+ private final SafetySourceDataFix mSafetySourceDataFix;
+
@GuardedBy("mApiLock")
private final SafetyCenterDataManager mSafetyCenterDataManager;
@@ -132,6 +132,9 @@ public final class SafetyCenterService extends SystemService {
private final SafetyCenterListeners mSafetyCenterListeners;
@GuardedBy("mApiLock")
+ private final SafetyCenterNotificationChannels mNotificationChannels;
+
+ @GuardedBy("mApiLock")
private final SafetyCenterNotificationSender mNotificationSender;
@GuardedBy("mApiLock")
@@ -140,34 +143,37 @@ public final class SafetyCenterService extends SystemService {
@GuardedBy("mApiLock")
private final SafetyCenterDataChangeNotifier mSafetyCenterDataChangeNotifier;
- private final StatsPullAtomCallback mPullAtomCallback;
private final boolean mDeviceSupportsSafetyCenter;
/** Whether the {@link SafetyCenterConfig} was successfully loaded. */
- private volatile boolean mConfigAvailable;
+ private volatile boolean mConfigAvailable = false;
public SafetyCenterService(Context context) {
super(context);
- mSafetyCenterResourcesContext = new SafetyCenterResourcesContext(context);
- mSafetyCenterConfigReader = new SafetyCenterConfigReader(mSafetyCenterResourcesContext);
+ mSafetyCenterResourcesApk = new SafetyCenterResourcesApk(context);
+ mSafetyCenterConfigReader = new SafetyCenterConfigReader(mSafetyCenterResourcesApk);
mSafetyCenterRefreshTracker = new SafetyCenterRefreshTracker(context);
+ PendingIntentFactory pendingIntentFactory =
+ new PendingIntentFactory(context, mSafetyCenterResourcesApk);
+ mSafetySourceDataFix =
+ new SafetySourceDataFix(context, pendingIntentFactory, mSafetyCenterConfigReader);
mSafetyCenterDataManager =
new SafetyCenterDataManager(
context, mSafetyCenterConfigReader, mSafetyCenterRefreshTracker, mApiLock);
mSafetyCenterDataFactory =
new SafetyCenterDataFactory(
context,
- mSafetyCenterResourcesContext,
+ mSafetyCenterResourcesApk,
mSafetyCenterConfigReader,
mSafetyCenterRefreshTracker,
- new PendingIntentFactory(context, mSafetyCenterResourcesContext),
+ pendingIntentFactory,
mSafetyCenterDataManager);
mSafetyCenterListeners = new SafetyCenterListeners(mSafetyCenterDataFactory);
- mNotificationChannels = new SafetyCenterNotificationChannels(mSafetyCenterResourcesContext);
+ mNotificationChannels = new SafetyCenterNotificationChannels(mSafetyCenterResourcesApk);
mNotificationSender =
SafetyCenterNotificationSender.newInstance(
context,
- mSafetyCenterResourcesContext,
+ mSafetyCenterResourcesApk,
mNotificationChannels,
mSafetyCenterDataManager);
mSafetyCenterBroadcastDispatcher =
@@ -176,13 +182,6 @@ public final class SafetyCenterService extends SystemService {
mSafetyCenterConfigReader,
mSafetyCenterRefreshTracker,
mSafetyCenterDataManager);
- mPullAtomCallback =
- new SafetyCenterPullAtomCallback(
- context,
- mApiLock,
- mSafetyCenterConfigReader,
- mSafetyCenterDataFactory,
- mSafetyCenterDataManager);
mSafetyCenterDataChangeNotifier =
new SafetyCenterDataChangeNotifier(mNotificationSender, mSafetyCenterListeners);
mDeviceSupportsSafetyCenter =
@@ -191,57 +190,98 @@ public final class SafetyCenterService extends SystemService {
Resources.getSystem()
.getIdentifier(
"config_enableSafetyCenter", "bool", "android"));
- if (!mDeviceSupportsSafetyCenter) {
- Log.i(TAG, "Device does not support safety center, safety center will be disabled.");
- }
}
@Override
public void onStart() {
publishBinderService(Context.SAFETY_CENTER_SERVICE, new Stub());
- if (mDeviceSupportsSafetyCenter) {
- synchronized (mApiLock) {
- mSafetyCenterResourcesContext.init();
- SafetyCenterFlags.init(mSafetyCenterResourcesContext);
- mConfigAvailable = mSafetyCenterConfigReader.loadConfig();
- if (mConfigAvailable) {
- mSafetyCenterDataManager.loadPersistableDataStateFromFile();
- new UserBroadcastReceiver().register(getContext());
- new SafetyCenterNotificationReceiver(
- this,
- mSafetyCenterDataManager,
- mSafetyCenterDataChangeNotifier,
- mApiLock)
- .register(getContext());
- new LocaleBroadcastReceiver().register(getContext());
- }
+ if (!mDeviceSupportsSafetyCenter) {
+ Log.i(TAG, "Device does not support Safety Center, it will be disabled");
+ return;
+ }
+
+ synchronized (mApiLock) {
+ boolean safetyCenterResourcesInitialized = mSafetyCenterResourcesApk.init();
+ if (!safetyCenterResourcesInitialized) {
+ Log.e(TAG, "Cannot init Safety Center resources, Safety Center will be disabled");
+ return;
+ }
+
+ SafetyCenterFlags.init(mSafetyCenterResourcesApk);
+
+ if (!mSafetyCenterConfigReader.loadConfig()) {
+ Log.e(TAG, "Cannot init Safety Center config, Safety Center will be disabled");
+ return;
}
+
+ mConfigAvailable = true;
+ mSafetyCenterDataManager.loadPersistableDataStateFromFile();
+ new UserBroadcastReceiver().register(getContext());
+ new SafetyCenterNotificationReceiver(
+ /* service= */ this,
+ mSafetyCenterDataManager,
+ mSafetyCenterDataChangeNotifier,
+ mApiLock)
+ .register(getContext());
+ new LocaleBroadcastReceiver().register(getContext());
}
}
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_BOOT_COMPLETED && canUseSafetyCenter()) {
- registerSafetyCenterEnabledListener();
- registerSafetyCenterPullAtomCallback();
- mNotificationChannels.createAllChannelsForAllUsers(getContext());
+ if (phase != SystemService.PHASE_BOOT_COMPLETED || !canUseSafetyCenter()) {
+ return;
}
+
+ SafetyCenterPullAtomCallback pullAtomCallback;
+ synchronized (mApiLock) {
+ registerSafetyCenterEnabledListenerLocked();
+ pullAtomCallback = newSafetyCenterPullAtomCallbackLocked();
+ }
+ registerSafetyCenterPullAtomCallback(pullAtomCallback);
}
- private void registerSafetyCenterEnabledListener() {
- Executor foregroundThreadExecutor = ForegroundThread.getExecutor();
- SafetyCenterEnabledListener listener = new SafetyCenterEnabledListener();
- // Ensure the listener is called first with the current state on the same thread.
- foregroundThreadExecutor.execute(listener::setInitialState);
+ @GuardedBy("mApiLock")
+ private void registerSafetyCenterEnabledListenerLocked() {
+ SafetyCenterEnabledListener safetyCenterEnabledListener = new SafetyCenterEnabledListener();
DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_PRIVACY, foregroundThreadExecutor, listener);
+ DeviceConfig.NAMESPACE_PRIVACY,
+ ForegroundThread.getExecutor(),
+ safetyCenterEnabledListener);
+ // Set the initial state *after* registering the listener, in the unlikely event that the
+ // flag changes between creating the listener and registering it (in which case we could
+ // miss an update and end up with an inconsistent state).
+ setInitialStateLocked(safetyCenterEnabledListener);
+ }
+
+ @GuardedBy("mApiLock")
+ @SuppressWarnings("GuardedBy")
+ // @GuardedBy is unable to infer that the `SafetyCenterService.this.mApiLock` in
+ // `SafetyCenterService` is the same as the one in `SafetyCenterEnabledListener` here, so it
+ // has to be suppressed.
+ private void setInitialStateLocked(SafetyCenterEnabledListener safetyCenterEnabledListener) {
+ safetyCenterEnabledListener.setInitialStateLocked();
+ }
+
+ @GuardedBy("mApiLock")
+ private SafetyCenterPullAtomCallback newSafetyCenterPullAtomCallbackLocked() {
+ return new SafetyCenterPullAtomCallback(
+ getContext(),
+ mApiLock,
+ mSafetyCenterConfigReader,
+ mSafetyCenterDataFactory,
+ mSafetyCenterDataManager);
}
- private void registerSafetyCenterPullAtomCallback() {
+ private void registerSafetyCenterPullAtomCallback(
+ SafetyCenterPullAtomCallback pullAtomCallback) {
StatsManager statsManager =
requireNonNull(getContext().getSystemService(StatsManager.class));
statsManager.setPullAtomCallback(
- SAFETY_STATE, null, BackgroundThread.getExecutor(), mPullAtomCallback);
+ SAFETY_STATE,
+ /* metadata= */ null,
+ BackgroundThread.getExecutor(),
+ pullAtomCallback);
}
/** Service implementation of {@link ISafetyCenterManager.Stub}. */
@@ -275,6 +315,16 @@ public final class SafetyCenterService extends SystemService {
UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
synchronized (mApiLock) {
+ safetySourceData =
+ mSafetySourceDataFix.maybeOverrideSafetySourceData(
+ safetySourceId, safetySourceData, packageName, userId);
+ safetyEvent =
+ SafetyEventFix.maybeOverrideSafetyEvent(
+ mSafetyCenterDataManager,
+ safetySourceId,
+ safetySourceData,
+ safetyEvent,
+ userId);
boolean hasUpdate =
mSafetyCenterDataManager.setSafetySourceData(
safetySourceData, safetySourceId, safetyEvent, packageName, userId);
@@ -298,9 +348,8 @@ public final class SafetyCenterService extends SystemService {
String safetySourceId, String packageName, @UserIdInt int userId) {
requireNonNull(safetySourceId);
requireNonNull(packageName);
- getContext()
- .enforceCallingOrSelfPermission(
- SEND_SAFETY_CENTER_UPDATE, "getSafetySourceData");
+ enforceAnyCallingOrSelfPermissions(
+ "getSafetySourceData", SEND_SAFETY_CENTER_UPDATE, MANAGE_SAFETY_CENTER);
if (!enforceCrossUserPermission("getSafetySourceData", userId)
|| !enforcePackage(Binder.getCallingUid(), packageName, userId)
|| !checkApiEnabled("getSafetySourceData")) {
@@ -342,7 +391,7 @@ public final class SafetyCenterService extends SystemService {
== SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED) {
safetyCenterErrorDetails =
new SafetyCenterErrorDetails(
- mSafetyCenterResourcesContext.getStringByName(
+ mSafetyCenterResourcesApk.getStringByName(
"resolving_action_error"));
}
if (hasUpdate) {
@@ -363,7 +412,10 @@ public final class SafetyCenterService extends SystemService {
|| !checkApiEnabled("refreshSafetySources")) {
return;
}
- startRefreshingSafetySources(refreshReason, userId);
+
+ synchronized (mApiLock) {
+ startRefreshingSafetySourcesLocked(refreshReason, userId);
+ }
}
@Override
@@ -380,7 +432,10 @@ public final class SafetyCenterService extends SystemService {
|| !checkApiEnabled("refreshSpecificSafetySources")) {
return;
}
- startRefreshingSafetySources(refreshReason, userId, safetySourceIds);
+
+ synchronized (mApiLock) {
+ startRefreshingSafetySourcesLocked(refreshReason, userId, safetySourceIds);
+ }
}
@Override
@@ -392,7 +447,7 @@ public final class SafetyCenterService extends SystemService {
// search works by adding all the entries very rarely (and relies on filtering them out
// instead).
if (!canUseSafetyCenter()) {
- Log.w(TAG, "Called getSafetyCenterConfig, but Safety Center is not supported");
+ Log.i(TAG, "Called getSafetyCenterConfig, but Safety Center is not supported");
return null;
}
@@ -504,7 +559,7 @@ public final class SafetyCenterService extends SystemService {
PendingIntent onDismissPendingIntent =
safetySourceIssue.getOnDismissPendingIntent();
if (onDismissPendingIntent != null
- && !dispatchPendingIntent(onDismissPendingIntent, null)) {
+ && !dispatchPendingIntent(onDismissPendingIntent)) {
Log.w(
TAG,
"Error dispatching dismissal for issue: "
@@ -634,13 +689,14 @@ public final class SafetyCenterService extends SystemService {
/** Enforces cross user permission and returns whether the user is valid. */
private boolean enforceCrossUserPermission(String message, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, message, getContext());
+ UserUtils.enforceCrossUserPermission(
+ userId, /* allowAll= */ false, message, getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.w(
TAG,
"Called "
+ message
- + " with user id "
+ + " with user id: "
+ userId
+ ", which does not correspond to an existing user");
return false;
@@ -650,7 +706,7 @@ public final class SafetyCenterService extends SystemService {
TAG,
"Called "
+ message
- + " with user id "
+ + " with user id: "
+ userId
+ ", which is an unsupported user");
return false;
@@ -676,7 +732,7 @@ public final class SafetyCenterService extends SystemService {
packageManager.getPackageUidAsUser(
packageName, PackageInfoFlags.of(0), userId);
} catch (NameNotFoundException e) {
- Log.e(TAG, "packageName=" + packageName + ", not found for userId=" + userId, e);
+ Log.w(TAG, "Package: " + packageName + ", not found for user id: " + userId, e);
return false;
}
if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID) {
@@ -684,9 +740,9 @@ public final class SafetyCenterService extends SystemService {
}
if (UserHandle.getAppId(callingUid) != UserHandle.getAppId(actualUid)) {
throw new SecurityException(
- "packageName="
+ "Package: "
+ packageName
- + ", does not belong to callingUid="
+ + ", does not belong to calling uid: "
+ callingUid);
}
return true;
@@ -719,9 +775,11 @@ public final class SafetyCenterService extends SystemService {
ParcelFileDescriptor err,
String[] args) {
return new SafetyCenterShellCommandHandler(
- getContext(), this, mDeviceSupportsSafetyCenter)
+ getContext(),
+ /* safetyCenterManager= */ this,
+ mDeviceSupportsSafetyCenter)
.exec(
- this,
+ /* target= */ this,
in.getFileDescriptor(),
out.getFileDescriptor(),
err.getFileDescriptor(),
@@ -793,12 +851,10 @@ public final class SafetyCenterService extends SystemService {
* value maps to {@link SafetyCenterManager#isSafetyCenterEnabled()}. It should only be
* registered if the device supports SafetyCenter and the {@link SafetyCenterConfig} was loaded
* successfully.
- *
- * <p>This listener is not thread-safe; it should be called on a single thread.
*/
- @NotThreadSafe
private final class SafetyCenterEnabledListener implements OnPropertiesChangedListener {
+ @GuardedBy("mApiLock")
private boolean mSafetyCenterEnabled;
@Override
@@ -807,41 +863,64 @@ public final class SafetyCenterService extends SystemService {
return;
}
boolean safetyCenterEnabled =
- properties.getBoolean(PROPERTY_SAFETY_CENTER_ENABLED, false);
- if (mSafetyCenterEnabled == safetyCenterEnabled) {
- return;
+ properties.getBoolean(PROPERTY_SAFETY_CENTER_ENABLED, SdkLevel.isAtLeastU());
+ synchronized (mApiLock) {
+ if (mSafetyCenterEnabled == safetyCenterEnabled) {
+ Log.i(
+ TAG,
+ "Safety Center is already "
+ + (mSafetyCenterEnabled ? "enabled" : "disabled")
+ + ", ignoring change");
+ return;
+ }
+ onSafetyCenterEnabledChangedLocked(safetyCenterEnabled);
}
- onSafetyCenterEnabledChanged(safetyCenterEnabled);
}
- private void setInitialState() {
+ @GuardedBy("mApiLock")
+ private void setInitialStateLocked() {
mSafetyCenterEnabled = SafetyCenterFlags.getSafetyCenterEnabled();
- Log.w(TAG, "SafetyCenter is " + (mSafetyCenterEnabled ? "enabled." : "disabled."));
+ if (mSafetyCenterEnabled) {
+ onApiInitEnabledLocked();
+ }
+ Log.i(TAG, "Safety Center is " + (mSafetyCenterEnabled ? "enabled" : "disabled"));
}
- private void onSafetyCenterEnabledChanged(boolean safetyCenterEnabled) {
- Log.w(TAG, "SafetyCenter is now " + (safetyCenterEnabled ? "enabled." : "disabled."));
-
+ @GuardedBy("mApiLock")
+ private void onSafetyCenterEnabledChangedLocked(boolean safetyCenterEnabled) {
if (safetyCenterEnabled) {
- onApiEnabled();
+ onApiEnabledLocked();
} else {
- onApiDisabled();
+ onApiDisabledLocked();
}
+
mSafetyCenterEnabled = safetyCenterEnabled;
+ Log.i(TAG, "Safety Center is now " + (mSafetyCenterEnabled ? "enabled" : "disabled"));
}
- private void onApiEnabled() {
- synchronized (mApiLock) {
- mSafetyCenterBroadcastDispatcher.sendEnabledChanged();
- }
+ @GuardedBy("mApiLock")
+ private void onApiInitEnabledLocked() {
+ mNotificationChannels.createAllChannelsForAllUsers(getContext());
}
- private void onApiDisabled() {
- synchronized (mApiLock) {
- clearDataLocked();
- mSafetyCenterListeners.clear();
- mSafetyCenterBroadcastDispatcher.sendEnabledChanged();
- }
+ @GuardedBy("mApiLock")
+ private void onApiEnabledLocked() {
+ mNotificationChannels.createAllChannelsForAllUsers(getContext());
+ mSafetyCenterBroadcastDispatcher.sendEnabledChanged();
+ }
+
+ @GuardedBy("mApiLock")
+ private void onApiDisabledLocked() {
+ // We're not clearing the Safety Center notification channels here. The reason for this
+ // is that the NotificationManager will post a runnable to cancel all associated
+ // notifications when clearing the channels. Given this happens asynchronously, this can
+ // leak between test cases and cause notifications that should be active to be cleared
+ // inadvertently. We're ok with the inconsistency because the channels are hidden
+ // somewhat deeply under Settings anyway, and we're unlikely to turn off Safety Center
+ // in production.
+ clearDataLocked();
+ mSafetyCenterListeners.clear();
+ mSafetyCenterBroadcastDispatcher.sendEnabledChanged();
}
}
@@ -870,28 +949,13 @@ public final class SafetyCenterService extends SystemService {
if (stillInFlight == null) {
return;
}
- boolean showErrorEntriesOnTimeout =
- SafetyCenterFlags.getShowErrorEntriesOnTimeout();
- boolean setError =
- showErrorEntriesOnTimeout
- && !RefreshReasons.isBackgroundRefresh(mRefreshReason);
+ boolean setError = !RefreshReasons.isBackgroundRefresh(mRefreshReason);
for (int i = 0; i < stillInFlight.size(); i++) {
mSafetyCenterDataManager.markSafetySourceRefreshTimedOut(
stillInFlight.valueAt(i), setError);
}
mSafetyCenterDataChangeNotifier.updateDataConsumers(mUserProfileGroup);
- if (!showErrorEntriesOnTimeout) {
- mSafetyCenterListeners.deliverErrorForUserProfileGroup(
- mUserProfileGroup,
- new SafetyCenterErrorDetails(
- mSafetyCenterResourcesContext.getStringByName(
- "refresh_timeout")));
- }
}
-
- Log.v(
- TAG,
- "Cleared refresh with broadcastId:" + mRefreshBroadcastId + " after a timeout");
}
@Override
@@ -938,8 +1002,12 @@ public final class SafetyCenterService extends SystemService {
mSafetyCenterListeners.deliverErrorForUserProfileGroup(
mUserProfileGroup,
new SafetyCenterErrorDetails(
- mSafetyCenterResourcesContext.getStringByName(
+ mSafetyCenterResourcesApk.getStringByName(
"resolving_action_error")));
+ Log.w(
+ TAG,
+ "Resolving action timed out for: "
+ + toUserFriendlyString(mSafetyCenterIssueActionId));
}
}
@@ -961,18 +1029,38 @@ public final class SafetyCenterService extends SystemService {
/** {@link BroadcastReceiver} which handles Locale changes. */
private final class LocaleBroadcastReceiver extends BroadcastReceiver {
- private static final String TAG = "LocaleBroadcastReceiver";
+ private static final String TAG = "SafetyCenterLocaleBroad";
void register(Context context) {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
- context.registerReceiverForAllUsers(this, filter, null, null);
+ context.registerReceiverForAllUsers(
+ /* receiver= */ this,
+ filter,
+ /* broadcastPermission= */ null,
+ /* scheduler= */ null);
}
@Override
public void onReceive(Context context, Intent intent) {
+ if (!SafetyCenterFlags.getSafetyCenterEnabled()) {
+ Log.i(TAG, "Safety Center is disabled, ignoring intent: " + intent);
+ return;
+ }
+
+ String action = intent.getAction();
+ if (!TextUtils.equals(action, Intent.ACTION_LOCALE_CHANGED)) {
+ Log.w(TAG, "Received unexpected action: " + action);
+ return;
+ }
+
Log.d(TAG, "Locale changed broadcast received");
- mNotificationChannels.createAllChannelsForAllUsers(getContext());
+
+ int userId = ActivityManager.getCurrentUser();
+ synchronized (mApiLock) {
+ startRefreshingSafetySourcesLocked(REFRESH_REASON_DEVICE_LOCALE_CHANGE, userId);
+ mNotificationChannels.createAllChannelsForUser(getContext(), UserHandle.of(userId));
+ }
}
}
@@ -982,62 +1070,98 @@ public final class SafetyCenterService extends SystemService {
*/
private final class UserBroadcastReceiver extends BroadcastReceiver {
- private static final String TAG = "UserBroadcastReceiver";
+ private static final String TAG = "SafetyCenterUserBroadca";
void register(Context context) {
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
- context.registerReceiverForAllUsers(this, filter, null, null);
+ context.registerReceiverForAllUsers(
+ /* receiver= */ this,
+ filter,
+ /* broadcastPermission= */ null,
+ /* scheduler= */ null);
}
@Override
public void onReceive(Context context, Intent intent) {
+ if (!SafetyCenterFlags.getSafetyCenterEnabled()) {
+ Log.i(TAG, "Safety Center is disabled, ignoring intent: " + intent);
+ return;
+ }
+
String action = intent.getAction();
if (action == null) {
- Log.w(TAG, "Received broadcast with null action!");
+ Log.w(TAG, "Received broadcast with null action");
return;
}
UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle.class);
if (userHandle == null) {
- Log.w(TAG, "Received " + action + " broadcast missing user extra!");
+ Log.w(TAG, "Received action: " + action + ", but missing user extra");
return;
}
int userId = userHandle.getIdentifier();
+ Log.d(TAG, "Received action: " + action + ", for user id: " + userId);
if (!UserProfileGroup.isSupported(userId, context)) {
Log.i(
TAG,
- "Received broadcast for user id "
+ "Received broadcast for user id: "
+ userId
+ ", which is an unsupported user");
return;
}
- Log.d(TAG, "Received " + action + " broadcast for user " + userId);
switch (action) {
case Intent.ACTION_USER_REMOVED:
case Intent.ACTION_MANAGED_PROFILE_REMOVED:
- removeUser(userId, true);
+ removeUserAndData(userId);
break;
case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
- removeUser(userId, false);
- // fall through!
- case Intent.ACTION_USER_ADDED:
+ removeUser(userId);
+ break;
+ case Intent.ACTION_USER_SWITCHED:
+ if (userId != ActivityManager.getCurrentUser()) {
+ Log.w(
+ TAG,
+ "Received broadcast for user id: "
+ + userId
+ + ", which is not the current user");
+ return;
+ }
+ // Fall through
case Intent.ACTION_MANAGED_PROFILE_ADDED:
case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
- startRefreshingSafetySources(REFRESH_REASON_OTHER, userId);
- mNotificationChannels.createAllChannelsForUser(getContext(), userHandle);
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.w(
+ TAG,
+ "Received broadcast for user id: "
+ + userId
+ + ", which does not exist");
+ return;
+ }
+ synchronized (mApiLock) {
+ startRefreshingSafetySourcesLocked(REFRESH_REASON_OTHER, userId);
+ mNotificationChannels.createAllChannelsForUser(getContext(), userHandle);
+ }
break;
}
}
}
+ private void removeUserAndData(@UserIdInt int userId) {
+ removeUser(userId, /* clearDataPermanently= */ true);
+ }
+
+ private void removeUser(@UserIdInt int userId) {
+ removeUser(userId, /* clearDataPermanently= */ false);
+ }
+
private void removeUser(@UserIdInt int userId, boolean clearDataPermanently) {
UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
synchronized (mApiLock) {
@@ -1053,31 +1177,44 @@ public final class SafetyCenterService extends SystemService {
}
}
- private void startRefreshingSafetySources(
+ @GuardedBy("mApiLock")
+ private void startRefreshingSafetySourcesLocked(
@RefreshReason int refreshReason, @UserIdInt int userId) {
- startRefreshingSafetySources(refreshReason, userId, null);
+ startRefreshingSafetySourcesLocked(
+ refreshReason,
+ UserProfileGroup.fromUser(getContext(), userId),
+ /* selectedSafetySourceIds= */ null);
}
- private void startRefreshingSafetySources(
+ @GuardedBy("mApiLock")
+ private void startRefreshingSafetySourcesLocked(
@RefreshReason int refreshReason,
@UserIdInt int userId,
+ List<String> selectedSafetySourceIds) {
+ startRefreshingSafetySourcesLocked(
+ refreshReason,
+ UserProfileGroup.fromUser(getContext(), userId),
+ selectedSafetySourceIds);
+ }
+
+ @GuardedBy("mApiLock")
+ private void startRefreshingSafetySourcesLocked(
+ @RefreshReason int refreshReason,
+ UserProfileGroup userProfileGroup,
@Nullable List<String> selectedSafetySourceIds) {
- UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
- synchronized (mApiLock) {
- String refreshBroadcastId =
- mSafetyCenterBroadcastDispatcher.sendRefreshSafetySources(
- refreshReason, userProfileGroup, selectedSafetySourceIds);
- if (refreshBroadcastId == null) {
- return;
- }
+ String refreshBroadcastId =
+ mSafetyCenterBroadcastDispatcher.sendRefreshSafetySources(
+ refreshReason, userProfileGroup, selectedSafetySourceIds);
+ if (refreshBroadcastId == null) {
+ return;
+ }
- RefreshTimeout refreshTimeout =
- new RefreshTimeout(refreshBroadcastId, refreshReason, userProfileGroup);
- mSafetyCenterTimeouts.add(
- refreshTimeout, SafetyCenterFlags.getRefreshSourcesTimeout(refreshReason));
+ RefreshTimeout refreshTimeout =
+ new RefreshTimeout(refreshBroadcastId, refreshReason, userProfileGroup);
+ mSafetyCenterTimeouts.add(
+ refreshTimeout, SafetyCenterFlags.getRefreshSourcesTimeout(refreshReason));
- mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup);
- }
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup);
}
/**
@@ -1091,7 +1228,7 @@ public final class SafetyCenterService extends SystemService {
safetyCenterIssueActionId.getSafetyCenterIssueKey();
UserProfileGroup userProfileGroup =
UserProfileGroup.fromUser(getContext(), safetyCenterIssueKey.getUserId());
- executeIssueActionInternal(safetyCenterIssueActionId, userProfileGroup, null);
+ executeIssueActionInternal(safetyCenterIssueActionId, userProfileGroup, /* taskId= */ null);
}
private void executeIssueActionInternal(
@@ -1120,16 +1257,19 @@ public final class SafetyCenterService extends SystemService {
CharSequence errorMessage;
if (safetySourceIssueAction.willResolve()) {
errorMessage =
- mSafetyCenterResourcesContext.getStringByName("resolving_action_error");
+ mSafetyCenterResourcesApk.getStringByName("resolving_action_error");
} else {
- errorMessage =
- mSafetyCenterResourcesContext.getStringByName("redirecting_error");
+ errorMessage = mSafetyCenterResourcesApk.getStringByName("redirecting_error");
}
mSafetyCenterListeners.deliverErrorForUserProfileGroup(
userProfileGroup, new SafetyCenterErrorDetails(errorMessage));
return;
}
if (safetySourceIssueAction.willResolve()) {
+ Log.d(
+ TAG,
+ "Starting resolving action for: "
+ + toUserFriendlyString(safetyCenterIssueActionId));
mSafetyCenterDataManager.markSafetyCenterIssueActionInFlight(
safetyCenterIssueActionId);
ResolvingActionTimeout resolvingActionTimeout =
@@ -1141,6 +1281,10 @@ public final class SafetyCenterService extends SystemService {
}
}
+ private boolean dispatchPendingIntent(PendingIntent pendingIntent) {
+ return dispatchPendingIntent(pendingIntent, /* launchTaskId= */ null);
+ }
+
private boolean dispatchPendingIntent(
PendingIntent pendingIntent, @Nullable Integer launchTaskId) {
if (launchTaskId != null
diff --git a/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java b/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java
index 87e3372f7..82983f0bb 100644
--- a/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java
+++ b/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java
@@ -16,7 +16,6 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_DEVICE_LOCALE_CHANGE;
import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_DEVICE_REBOOT;
import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_OTHER;
@@ -27,14 +26,13 @@ import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_SAFETY_CEN
import static java.util.Collections.unmodifiableMap;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.os.RemoteException;
import android.safetycenter.ISafetyCenterManager;
import android.safetycenter.SafetyCenterManager.RefreshReason;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.modules.utils.BasicShellCommandHandler;
import com.android.modules.utils.build.SdkLevel;
@@ -48,7 +46,6 @@ import java.util.Map;
*
* <p>Example usage: $ adb shell cmd safety_center refresh --reason PAGE_OPEN --user 10
*/
-@RequiresApi(TIRAMISU)
final class SafetyCenterShellCommandHandler extends BasicShellCommandHandler {
private static final Map<String, Integer> REASONS = createReasonMap();
@@ -89,11 +86,18 @@ final class SafetyCenterShellCommandHandler extends BasicShellCommandHandler {
return handleDefaultCommands(cmd);
}
} catch (RemoteException | IllegalArgumentException e) {
- e.printStackTrace(getErrPrintWriter());
+ printError(e);
return 1;
}
}
+ // We want to log the stack trace on a specific PrintWriter here, this is a false positive as
+ // the warning does not consider the overload that takes a PrintWriter as an argument (yet).
+ @SuppressWarnings("CatchAndPrintStackTrace")
+ private void printError(Throwable error) {
+ error.printStackTrace(getErrPrintWriter());
+ }
+
private int onEnabled() throws RemoteException {
getOutPrintWriter().println(mSafetyCenterManager.isSafetyCenterEnabled());
return 0;
diff --git a/service/java/com/android/safetycenter/SafetyCenterTimeouts.java b/service/java/com/android/safetycenter/SafetyCenterTimeouts.java
index f8bfd691e..b37951fb1 100644
--- a/service/java/com/android/safetycenter/SafetyCenterTimeouts.java
+++ b/service/java/com/android/safetycenter/SafetyCenterTimeouts.java
@@ -16,12 +16,8 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import android.os.Handler;
-import androidx.annotation.RequiresApi;
-
import com.android.permission.util.ForegroundThread;
import java.io.PrintWriter;
@@ -36,7 +32,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* <p>This class isn't thread safe. Thread safety must be handled by the caller.
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetyCenterTimeouts {
diff --git a/service/java/com/android/safetycenter/SafetySourceIssueInfo.java b/service/java/com/android/safetycenter/SafetySourceIssueInfo.java
index 51e6567d7..0dfa7c814 100644
--- a/service/java/com/android/safetycenter/SafetySourceIssueInfo.java
+++ b/service/java/com/android/safetycenter/SafetySourceIssueInfo.java
@@ -16,8 +16,6 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString;
import android.annotation.UserIdInt;
@@ -25,8 +23,6 @@ import android.safetycenter.SafetySourceIssue;
import android.safetycenter.config.SafetySource;
import android.safetycenter.config.SafetySourcesGroup;
-import androidx.annotation.RequiresApi;
-
import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
import java.util.Objects;
@@ -36,7 +32,6 @@ import java.util.Objects;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class SafetySourceIssueInfo {
private final SafetySourceIssue mSafetySourceIssue;
@@ -65,6 +60,7 @@ public final class SafetySourceIssueInfo {
public SafetyCenterIssueKey getSafetyCenterIssueKey() {
return mSafetyCenterIssueKey;
}
+
/** Returns the {@link SafetySourceIssue}. */
public SafetySourceIssue getSafetySourceIssue() {
return mSafetySourceIssue;
diff --git a/service/java/com/android/safetycenter/SafetySourceIssues.java b/service/java/com/android/safetycenter/SafetySourceIssues.java
new file mode 100644
index 000000000..dc3c2a83e
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetySourceIssues.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2023 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.safetycenter;
+
+import android.safetycenter.SafetySourceIssue;
+
+import androidx.annotation.Nullable;
+
+import com.android.modules.utils.build.SdkLevel;
+
+import java.util.List;
+
+/**
+ * A helper class to facilitate working with {@link SafetySourceIssue} objects.
+ *
+ * @hide
+ */
+public final class SafetySourceIssues {
+
+ /**
+ * Returns the {@link SafetySourceIssue.Action} with the given action ID belonging to the given
+ * {@link SafetySourceIssue} or {@code null} if no such action is present.
+ *
+ * <p>The action will either belong to the issue directly from {@link
+ * SafetySourceIssue#getActions()} or via {@link SafetySourceIssue#getCustomNotification()} if
+ * the issue has a custom notification.
+ */
+ @Nullable
+ public static SafetySourceIssue.Action findAction(SafetySourceIssue issue, String actionId) {
+ SafetySourceIssue.Action action = null;
+ if (SdkLevel.isAtLeastU() && issue.getCustomNotification() != null) {
+ action = findAction(issue.getCustomNotification().getActions(), actionId);
+ }
+ if (action == null) {
+ action = findAction(issue.getActions(), actionId);
+ }
+ return action;
+ }
+
+ @Nullable
+ private static SafetySourceIssue.Action findAction(
+ List<SafetySourceIssue.Action> actions, String actionId) {
+ for (int i = 0; i < actions.size(); i++) {
+ SafetySourceIssue.Action action = actions.get(i);
+ if (action.getId().equals(actionId)) {
+ return action;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns {@code true} if {@code actionId} corresponds to a "primary" action of the given
+ * {@code issue}, or {@code false} if the action is not the primary or if no action with the
+ * given ID is found.
+ *
+ * <p>A primary action is the first action of either the issue, or its custom notification.
+ */
+ public static boolean isPrimaryAction(SafetySourceIssue issue, String actionId) {
+ boolean isPrimaryNotificationAction =
+ SdkLevel.isAtLeastU()
+ && issue.getCustomNotification() != null
+ && matchesFirst(issue.getCustomNotification().getActions(), actionId);
+ boolean isPrimaryIssueAction = matchesFirst(issue.getActions(), actionId);
+ return isPrimaryNotificationAction || isPrimaryIssueAction;
+ }
+
+ private static boolean matchesFirst(List<SafetySourceIssue.Action> actions, String actionId) {
+ return !actions.isEmpty() && actions.get(0).getId().equals(actionId);
+ }
+
+ private SafetySourceIssues() {}
+}
diff --git a/service/java/com/android/safetycenter/SafetySourceKey.java b/service/java/com/android/safetycenter/SafetySourceKey.java
index 511fbef73..9e1400e30 100644
--- a/service/java/com/android/safetycenter/SafetySourceKey.java
+++ b/service/java/com/android/safetycenter/SafetySourceKey.java
@@ -16,13 +16,9 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import android.annotation.UserIdInt;
import android.safetycenter.SafetySourceData;
-import androidx.annotation.RequiresApi;
-
import java.util.Objects;
/**
@@ -32,7 +28,7 @@ import java.util.Objects;
* @hide
*/
// TODO(b/219697341): Look into using AutoValue for this data class.
-@RequiresApi(TIRAMISU)
+
public final class SafetySourceKey {
private final String mSourceId;
diff --git a/service/java/com/android/safetycenter/SafetySources.java b/service/java/com/android/safetycenter/SafetySources.java
index c0b0bdc48..02d83d27b 100644
--- a/service/java/com/android/safetycenter/SafetySources.java
+++ b/service/java/com/android/safetycenter/SafetySources.java
@@ -16,20 +16,15 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import android.safetycenter.SafetySourceData;
import android.safetycenter.config.SafetySource;
import android.util.Log;
-import androidx.annotation.RequiresApi;
-
/**
* A helper class to facilitate working with {@link SafetySource} objects.
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class SafetySources {
private static final String TAG = "SafetySources";
diff --git a/service/java/com/android/safetycenter/SafetySourcesGroups.java b/service/java/com/android/safetycenter/SafetySourcesGroups.java
index 5233302aa..a86eccada 100644
--- a/service/java/com/android/safetycenter/SafetySourcesGroups.java
+++ b/service/java/com/android/safetycenter/SafetySourcesGroups.java
@@ -16,16 +16,11 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import android.safetycenter.config.SafetySourcesGroup;
-import androidx.annotation.RequiresApi;
-
import com.android.modules.utils.build.SdkLevel;
/** Static utilities for working with {@link SafetySourcesGroup} objects. */
-@RequiresApi(TIRAMISU)
final class SafetySourcesGroups {
/**
diff --git a/service/java/com/android/safetycenter/UserProfileGroup.java b/service/java/com/android/safetycenter/UserProfileGroup.java
index 8d3adc573..74b9b136f 100644
--- a/service/java/com/android/safetycenter/UserProfileGroup.java
+++ b/service/java/com/android/safetycenter/UserProfileGroup.java
@@ -16,11 +16,8 @@
package com.android.safetycenter;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static java.util.Objects.requireNonNull;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -30,7 +27,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.permission.util.UserUtils;
@@ -45,7 +42,6 @@ import java.util.Objects;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class UserProfileGroup {
private static final String TAG = "UserProfileGroup";
@@ -141,9 +137,9 @@ public final class UserProfileGroup {
Arrays.copyOf(
managedRunningProfilesUserIds, managedRunningProfilesUserIdsLen));
if (!userProfileGroup.contains(userId)) {
- Log.w(
+ Log.i(
TAG,
- "User id " + userId + " does not belong to " + userProfileGroup,
+ "User id: " + userId + " does not belong to: " + userProfileGroup,
new Exception());
}
return userProfileGroup;
@@ -167,7 +163,8 @@ public final class UserProfileGroup {
return context;
} else {
try {
- return context.createPackageContextAsUser(context.getPackageName(), 0, userHandle);
+ return context.createPackageContextAsUser(
+ context.getPackageName(), /* flags= */ 0, userHandle);
} catch (PackageManager.NameNotFoundException doesNotHappen) {
throw new IllegalStateException(doesNotHappen);
}
@@ -232,9 +229,9 @@ public final class UserProfileGroup {
profileParentAndManagedRunningProfilesUserIds[0] = mProfileParentUserId;
System.arraycopy(
mManagedRunningProfilesUserIds,
- 0,
+ /* srcPos= */ 0,
profileParentAndManagedRunningProfilesUserIds,
- 1,
+ /* destPos= */ 1,
mManagedRunningProfilesUserIds.length);
return profileParentAndManagedRunningProfilesUserIds;
}
diff --git a/service/java/com/android/safetycenter/data/AndroidLockScreenFix.java b/service/java/com/android/safetycenter/data/AndroidLockScreenFix.java
index 5db3cfbad..53043c0f8 100644
--- a/service/java/com/android/safetycenter/data/AndroidLockScreenFix.java
+++ b/service/java/com/android/safetycenter/data/AndroidLockScreenFix.java
@@ -16,9 +16,6 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
-import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -30,8 +27,6 @@ import android.safetycenter.SafetySourceIssue;
import android.safetycenter.SafetySourceStatus;
import android.util.Log;
-import androidx.annotation.RequiresApi;
-
import com.android.modules.utils.build.SdkLevel;
import com.android.safetycenter.PendingIntentFactory;
import com.android.safetycenter.SafetyCenterFlags;
@@ -42,7 +37,6 @@ import java.util.List;
* A class to work around an issue with the {@code AndroidLockScreen} safety source, by potentially
* overriding its {@link SafetySourceData}.
*/
-@RequiresApi(TIRAMISU)
final class AndroidLockScreenFix {
private static final String TAG = "AndroidLockScreenFix";
@@ -57,9 +51,22 @@ final class AndroidLockScreenFix {
private AndroidLockScreenFix() {}
+ static boolean shouldApplyFix(String sourceId) {
+ if (SdkLevel.isAtLeastU()) {
+ // No need to override on U+ as the issue has been fixed in a T QPR release.
+ // As such, U+ fields for the SafetySourceData are not taken into account in the methods
+ // below.
+ return false;
+ }
+ if (!ANDROID_LOCK_SCREEN_SOURCE_ID.equals(sourceId)) {
+ return false;
+ }
+ return SafetyCenterFlags.getReplaceLockScreenIconAction();
+ }
+
/**
- * Potentially overrides the {@link SafetySourceData} of the {@code AndroidLockScreen} source by
- * replacing its {@link PendingIntent}s.
+ * Overrides the {@link SafetySourceData} of the {@code AndroidLockScreen} source by replacing
+ * its {@link PendingIntent}s.
*
* <p>This is done because of a bug in the Settings app where the {@link PendingIntent}s created
* end up referencing either the {@link SafetyCenterEntry#getPendingIntent()} or the {@link
@@ -72,109 +79,76 @@ final class AndroidLockScreenFix {
* different request codes for the different {@link PendingIntent}s to ensure new instances are
* created (the key does take into account the request code).
*/
- @Nullable
- static SafetySourceData maybeOverrideSafetySourceData(
- Context context, String sourceId, @Nullable SafetySourceData safetySourceData) {
- if (safetySourceData == null) {
- return null;
- }
- if (SdkLevel.isAtLeastU()) {
- // No need to override on U+ as the issue has been fixed in a T QPR release.
- // As such, U+ fields for the SafetySourceData are not taken into account in the methods
- // below.
- return safetySourceData;
- }
- if (!ANDROID_LOCK_SCREEN_SOURCE_ID.equals(sourceId)) {
- return safetySourceData;
- }
- if (!SafetyCenterFlags.getReplaceLockScreenIconAction()) {
- return safetySourceData;
- }
- return overrideTiramisuSafetySourceData(context, safetySourceData);
- }
+ static SafetySourceData applyFix(Context context, SafetySourceData data) {
+ SafetySourceData.Builder overriddenData =
+ SafetySourceDataOverrides.copyDataToBuilderWithoutIssues(data);
- private static SafetySourceData overrideTiramisuSafetySourceData(
- Context context, SafetySourceData safetySourceData) {
- SafetySourceData.Builder overriddenSafetySourceData = new SafetySourceData.Builder();
- SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
- if (safetySourceStatus != null) {
- overriddenSafetySourceData.setStatus(
- overrideTiramisuSafetySourceStatus(context, safetySourceStatus));
+ SafetySourceStatus originalStatus = data.getStatus();
+ if (originalStatus != null) {
+ overriddenData.setStatus(overrideTiramisuSafetySourceStatus(context, originalStatus));
}
- List<SafetySourceIssue> safetySourceIssues = safetySourceData.getIssues();
- for (int i = 0; i < safetySourceIssues.size(); i++) {
- SafetySourceIssue safetySourceIssue = safetySourceIssues.get(i);
- overriddenSafetySourceData.addIssue(
- overrideTiramisuSafetySourceIssue(context, safetySourceIssue));
+
+ List<SafetySourceIssue> issues = data.getIssues();
+ for (int i = 0; i < issues.size(); i++) {
+ overriddenData.addIssue(overrideTiramisuIssue(context, issues.get(i)));
}
- return overriddenSafetySourceData.build();
+
+ return overriddenData.build();
}
private static SafetySourceStatus overrideTiramisuSafetySourceStatus(
- Context context, SafetySourceStatus safetySourceStatus) {
- SafetySourceStatus.Builder overriddenSafetySourceStatus =
- new SafetySourceStatus.Builder(
- safetySourceStatus.getTitle(),
- safetySourceStatus.getSummary(),
- safetySourceStatus.getSeverityLevel())
- .setPendingIntent(
- overridePendingIntent(
- context, safetySourceStatus.getPendingIntent(), false))
- .setEnabled(safetySourceStatus.isEnabled());
- SafetySourceStatus.IconAction iconAction = safetySourceStatus.getIconAction();
+ Context context, SafetySourceStatus status) {
+ SafetySourceStatus.Builder overriddenStatus =
+ SafetySourceDataOverrides.copyStatusToBuilder(status);
+
+ PendingIntent originalPendingIntent = status.getPendingIntent();
+ if (originalPendingIntent != null) {
+ overriddenStatus.setPendingIntent(
+ overridePendingIntent(
+ context, originalPendingIntent, /* isIconAction= */ false));
+ }
+
+ SafetySourceStatus.IconAction iconAction = status.getIconAction();
if (iconAction != null) {
- overriddenSafetySourceStatus.setIconAction(
- overrideTiramisuSafetySourceStatusIconAction(
- context, safetySourceStatus.getIconAction()));
+ overriddenStatus.setIconAction(
+ overrideTiramisuIconAction(context, status.getIconAction()));
}
- return overriddenSafetySourceStatus.build();
+
+ return overriddenStatus.build();
}
- private static SafetySourceStatus.IconAction overrideTiramisuSafetySourceStatusIconAction(
+ private static SafetySourceStatus.IconAction overrideTiramisuIconAction(
Context context, SafetySourceStatus.IconAction iconAction) {
return new SafetySourceStatus.IconAction(
iconAction.getIconType(),
- overridePendingIntent(context, iconAction.getPendingIntent(), true));
+ overridePendingIntent(
+ context, iconAction.getPendingIntent(), /* isIconAction= */ true));
}
- private static SafetySourceIssue overrideTiramisuSafetySourceIssue(
- Context context, SafetySourceIssue safetySourceIssue) {
- SafetySourceIssue.Builder overriddenSafetySourceIssue =
- new SafetySourceIssue.Builder(
- safetySourceIssue.getId(),
- safetySourceIssue.getTitle(),
- safetySourceIssue.getSummary(),
- safetySourceIssue.getSeverityLevel(),
- safetySourceIssue.getIssueTypeId())
- .setSubtitle(safetySourceIssue.getSubtitle())
- .setIssueCategory(safetySourceIssue.getIssueCategory())
- .setOnDismissPendingIntent(safetySourceIssue.getOnDismissPendingIntent());
- List<SafetySourceIssue.Action> actions = safetySourceIssue.getActions();
+ private static SafetySourceIssue overrideTiramisuIssue(
+ Context context, SafetySourceIssue issue) {
+ SafetySourceIssue.Builder overriddenIssue =
+ SafetySourceDataOverrides.copyIssueToBuilderWithoutActions(issue);
+
+ List<SafetySourceIssue.Action> actions = issue.getActions();
for (int i = 0; i < actions.size(); i++) {
SafetySourceIssue.Action action = actions.get(i);
- overriddenSafetySourceIssue.addAction(
- overrideTiramisuSafetySourceIssueAction(context, action));
+ overriddenIssue.addAction(overrideTiramisuIssueAction(context, action));
}
- return overriddenSafetySourceIssue.build();
+
+ return overriddenIssue.build();
}
- private static SafetySourceIssue.Action overrideTiramisuSafetySourceIssueAction(
+ private static SafetySourceIssue.Action overrideTiramisuIssueAction(
Context context, SafetySourceIssue.Action action) {
- return new SafetySourceIssue.Action.Builder(
- action.getId(),
- action.getLabel(),
- overridePendingIntent(context, action.getPendingIntent(), false))
- .setWillResolve(action.willResolve())
- .setSuccessMessage(action.getSuccessMessage())
- .build();
+ PendingIntent pendingIntent =
+ overridePendingIntent(
+ context, action.getPendingIntent(), /* isIconAction= */ false);
+ return SafetySourceDataOverrides.overrideActionPendingIntent(action, pendingIntent);
}
- @Nullable
private static PendingIntent overridePendingIntent(
- Context context, @Nullable PendingIntent pendingIntent, boolean isIconAction) {
- if (pendingIntent == null) {
- return null;
- }
+ Context context, PendingIntent pendingIntent, boolean isIconAction) {
String settingsPackageName = pendingIntent.getCreatorPackage();
int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
Context settingsPackageContext =
@@ -206,7 +180,7 @@ final class AndroidLockScreenFix {
// This is important because there are scenarios where the Settings app provides different
// pending intents (e.g. in the work profile), and in this case we shouldn't override them.
if (isIconAction) {
- Log.w(
+ Log.i(
TAG,
"Replacing " + ANDROID_LOCK_SCREEN_SOURCE_ID + " icon action pending intent");
return PendingIntentFactory.getActivityPendingIntent(
@@ -215,7 +189,7 @@ final class AndroidLockScreenFix {
newLockScreenIconActionIntent(settingsPackageName),
PendingIntent.FLAG_IMMUTABLE);
}
- Log.w(TAG, "Replacing " + ANDROID_LOCK_SCREEN_SOURCE_ID + " entry or issue pending intent");
+ Log.i(TAG, "Replacing " + ANDROID_LOCK_SCREEN_SOURCE_ID + " entry or issue pending intent");
return PendingIntentFactory.getActivityPendingIntent(
settingsPackageContext,
ANDROID_LOCK_SCREEN_ENTRY_REQ_CODE,
diff --git a/service/java/com/android/safetycenter/data/DefaultActionOverrideFix.java b/service/java/com/android/safetycenter/data/DefaultActionOverrideFix.java
new file mode 100644
index 000000000..9ca188670
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/DefaultActionOverrideFix.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.data;
+
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import android.annotation.UserIdInt;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.permission.util.UserUtils;
+import com.android.safetycenter.PendingIntentFactory;
+import com.android.safetycenter.SafetyCenterConfigReader;
+import com.android.safetycenter.SafetyCenterFlags;
+
+import java.util.List;
+
+/**
+ * Replaces {@link SafetySourceIssue.Action}s with the corresponding source's default intent drawn
+ * from the Safety Center config.
+ *
+ * <p>Actions to be replaced are controlled by the {@code
+ * safety_center_actions_to_override_with_default_intent} DeviceConfig flag.
+ *
+ * <p>This is done to support cases where we allow OEMs to override intents in the config, but
+ * sources are unaware of and unable to access those overrides when providing issues and
+ * notifications. We use the default intent when sources provide a null pending intent in their
+ * status. This fix allows us to implement a similar behavior for actions, without changing the
+ * non-null requirement on their pending intent fields.
+ */
+final class DefaultActionOverrideFix {
+
+ private final Context mContext;
+ private final PendingIntentFactory mPendingIntentFactory;
+ private final SafetyCenterConfigReader mSafetyCenterConfigReader;
+
+ DefaultActionOverrideFix(
+ Context context,
+ PendingIntentFactory pendingIntentFactory,
+ SafetyCenterConfigReader safetyCenterConfigReader) {
+ mContext = context;
+ mPendingIntentFactory = pendingIntentFactory;
+ mSafetyCenterConfigReader = safetyCenterConfigReader;
+ }
+
+ static boolean shouldApplyFix(String sourceId) {
+ List<String> actionsToOverride =
+ SafetyCenterFlags.getActionsToOverrideWithDefaultIntentForSource(sourceId);
+ return !actionsToOverride.isEmpty();
+ }
+
+ SafetySourceData applyFix(
+ String sourceId,
+ SafetySourceData safetySourceData,
+ String packageName,
+ @UserIdInt int userId) {
+ if (safetySourceData.getIssues().isEmpty()) {
+ return safetySourceData;
+ }
+
+ PendingIntent defaultIntentForSource =
+ getDefaultIntentForSource(sourceId, packageName, userId);
+ if (defaultIntentForSource == null) {
+ // If there's no default intent, we can't override any actions with it.
+ return safetySourceData;
+ }
+
+ List<String> actionsToOverride =
+ SafetyCenterFlags.getActionsToOverrideWithDefaultIntentForSource(sourceId);
+ if (actionsToOverride.isEmpty()) {
+ // This shouldn't happen if shouldApplyFix is called first, but we check for good
+ // measure.
+ return safetySourceData;
+ }
+
+ SafetySourceData.Builder overriddenSafetySourceData =
+ SafetySourceDataOverrides.copyDataToBuilderWithoutIssues(safetySourceData);
+ List<SafetySourceIssue> issues = safetySourceData.getIssues();
+ for (int i = 0; i < issues.size(); i++) {
+ overriddenSafetySourceData.addIssue(
+ maybeOverrideActionsWithDefaultIntent(
+ issues.get(i), actionsToOverride, defaultIntentForSource));
+ }
+
+ return overriddenSafetySourceData.build();
+ }
+
+ @Nullable
+ private PendingIntent getDefaultIntentForSource(
+ String sourceId, String packageName, @UserIdInt int userId) {
+ SafetyCenterConfigReader.ExternalSafetySource externalSafetySource =
+ mSafetyCenterConfigReader.getExternalSafetySource(sourceId, packageName);
+ if (externalSafetySource == null) {
+ return null;
+ }
+
+ boolean isQuietModeEnabled =
+ UserUtils.isManagedProfile(userId, mContext)
+ && !UserUtils.isProfileRunning(userId, mContext);
+
+ return mPendingIntentFactory.getPendingIntent(
+ sourceId,
+ externalSafetySource.getSafetySource().getIntentAction(),
+ packageName,
+ userId,
+ isQuietModeEnabled);
+ }
+
+ private SafetySourceIssue maybeOverrideActionsWithDefaultIntent(
+ SafetySourceIssue issue, List<String> actionsToOverride, PendingIntent defaultIntent) {
+ SafetySourceIssue.Builder overriddenIssue =
+ SafetySourceDataOverrides.copyIssueToBuilderWithoutActions(issue);
+
+ List<SafetySourceIssue.Action> actions = issue.getActions();
+ for (int i = 0; i < actions.size(); i++) {
+ overriddenIssue.addAction(
+ maybeOverrideAction(actions.get(i), actionsToOverride, defaultIntent));
+ }
+
+ if (SdkLevel.isAtLeastU()) {
+ overriddenIssue.setCustomNotification(
+ maybeOverrideNotification(
+ issue.getCustomNotification(), actionsToOverride, defaultIntent));
+ }
+
+ return overriddenIssue.build();
+ }
+
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ @Nullable
+ private static SafetySourceIssue.Notification maybeOverrideNotification(
+ @Nullable SafetySourceIssue.Notification notification,
+ List<String> actionsToOverride,
+ PendingIntent defaultIntent) {
+ if (notification == null) {
+ return null;
+ }
+
+ SafetySourceIssue.Notification.Builder overriddenNotification =
+ new SafetySourceIssue.Notification.Builder(notification).clearActions();
+
+ List<SafetySourceIssue.Action> actions = notification.getActions();
+ for (int i = 0; i < actions.size(); i++) {
+ overriddenNotification.addAction(
+ maybeOverrideAction(actions.get(i), actionsToOverride, defaultIntent));
+ }
+
+ return overriddenNotification.build();
+ }
+
+ private static SafetySourceIssue.Action maybeOverrideAction(
+ SafetySourceIssue.Action action,
+ List<String> actionsToOverride,
+ PendingIntent defaultIntent) {
+ if (actionsToOverride.contains(action.getId())) {
+ return SafetySourceDataOverrides.overrideActionPendingIntent(action, defaultIntent);
+ }
+ return action;
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java b/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java
index 734732401..dff7c4339 100644
--- a/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java
+++ b/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java
@@ -16,11 +16,11 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.Manifest.permission.MANAGE_SAFETY_CENTER;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.safetycenter.logging.SafetyCenterStatsdLogger.toSystemEventResult;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.safetycenter.SafetyCenterData;
@@ -30,9 +30,10 @@ import android.safetycenter.SafetySourceErrorDetails;
import android.safetycenter.SafetySourceIssue;
import android.safetycenter.config.SafetyCenterConfig;
import android.safetycenter.config.SafetySourcesGroup;
+import android.util.ArraySet;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.safetycenter.ApiLock;
import com.android.safetycenter.SafetyCenterConfigReader;
@@ -60,12 +61,12 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
public final class SafetyCenterDataManager {
private static final String TAG = "SafetyCenterDataManager";
+ private final Context mContext;
private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker;
private final SafetySourceDataRepository mSafetySourceDataRepository;
private final SafetyCenterIssueDismissalRepository mSafetyCenterIssueDismissalRepository;
@@ -81,6 +82,7 @@ public final class SafetyCenterDataManager {
SafetyCenterConfigReader safetyCenterConfigReader,
SafetyCenterRefreshTracker safetyCenterRefreshTracker,
ApiLock apiLock) {
+ mContext = context;
mSafetyCenterRefreshTracker = safetyCenterRefreshTracker;
mSafetyCenterInFlightIssueActionRepository =
new SafetyCenterInFlightIssueActionRepository(context);
@@ -88,7 +90,6 @@ public final class SafetyCenterDataManager {
new SafetyCenterIssueDismissalRepository(apiLock, safetyCenterConfigReader);
mSafetySourceDataRepository =
new SafetySourceDataRepository(
- context,
mSafetyCenterInFlightIssueActionRepository,
mSafetyCenterIssueDismissalRepository);
mSafetyCenterIssueRepository =
@@ -134,10 +135,14 @@ public final class SafetyCenterDataManager {
String packageName,
@UserIdInt int userId) {
if (!mSafetySourceDataValidator.validateRequest(
- safetySourceData, safetySourceId, packageName, userId)) {
+ safetySourceData,
+ /* callerCanAccessAnySource= */ false,
+ safetySourceId,
+ packageName,
+ userId)) {
return false;
}
- SafetySourceKey key = SafetySourceKey.of(safetySourceId, userId);
+ SafetySourceKey safetySourceKey = SafetySourceKey.of(safetySourceId, userId);
// Must fetch refresh reason before calling processSafetyEvent because the latter may
// complete and clear the current refresh.
@@ -147,11 +152,15 @@ public final class SafetyCenterDataManager {
refreshReason = mSafetyCenterRefreshTracker.getRefreshReason();
}
- boolean sourceDataDiffers =
- mSafetySourceDataRepository.setSafetySourceData(
- safetySourceData, safetySourceId, userId);
+ // It is important to process the event first as it relies on the data available prior to
+ // changing it.
+ boolean sourceDataWillChange =
+ !mSafetySourceDataRepository.sourceHasData(safetySourceKey, safetySourceData);
boolean eventCausedChange =
- processSafetyEvent(safetySourceId, safetyEvent, userId, false, sourceDataDiffers);
+ processSafetyEvent(
+ safetySourceKey, safetyEvent, /* isError= */ false, sourceDataWillChange);
+ boolean sourceDataDiffers =
+ mSafetySourceDataRepository.setSafetySourceData(safetySourceKey, safetySourceData);
boolean safetyCenterDataChanged = sourceDataDiffers || eventCausedChange;
if (safetyCenterDataChanged) {
@@ -159,7 +168,12 @@ public final class SafetyCenterDataManager {
}
mSafetySourceStateCollectedLogger.writeSourceUpdatedAtom(
- key, safetySourceData, refreshReason, sourceDataDiffers, userId, safetyEvent);
+ safetySourceKey,
+ safetySourceData,
+ refreshReason,
+ sourceDataDiffers,
+ userId,
+ safetyEvent);
return safetyCenterDataChanged;
}
@@ -199,11 +213,15 @@ public final class SafetyCenterDataManager {
String packageName,
@UserIdInt int userId) {
if (!mSafetySourceDataValidator.validateRequest(
- null, safetySourceId, packageName, userId)) {
+ /* safetySourceData= */ null,
+ /* callerCanAccessAnySource= */ false,
+ safetySourceId,
+ packageName,
+ userId)) {
return false;
}
SafetyEvent safetyEvent = safetySourceErrorDetails.getSafetyEvent();
- SafetySourceKey key = SafetySourceKey.of(safetySourceId, userId);
+ SafetySourceKey safetySourceKey = SafetySourceKey.of(safetySourceId, userId);
// Must fetch refresh reason before calling processSafetyEvent because the latter may
// complete and clear the current refresh.
@@ -213,11 +231,15 @@ public final class SafetyCenterDataManager {
refreshReason = mSafetyCenterRefreshTracker.getRefreshReason();
}
+ // It is important to process the event first as it relies on the data available prior to
+ // changing it.
+ boolean sourceDataWillChange = !mSafetySourceDataRepository.sourceHasError(safetySourceKey);
+ boolean eventCausedChange =
+ processSafetyEvent(
+ safetySourceKey, safetyEvent, /* isError= */ true, sourceDataWillChange);
boolean sourceDataDiffers =
mSafetySourceDataRepository.reportSafetySourceError(
- safetySourceErrorDetails, safetySourceId, userId);
- boolean eventCausedChange =
- processSafetyEvent(safetySourceId, safetyEvent, userId, true, sourceDataDiffers);
+ safetySourceKey, safetySourceErrorDetails);
boolean safetyCenterDataChanged = sourceDataDiffers || eventCausedChange;
if (safetyCenterDataChanged) {
@@ -225,7 +247,12 @@ public final class SafetyCenterDataManager {
}
mSafetySourceStateCollectedLogger.writeSourceUpdatedAtom(
- key, null, refreshReason, sourceDataDiffers, userId, safetyEvent);
+ safetySourceKey,
+ /* safetySourceData= */ null,
+ refreshReason,
+ sourceDataDiffers,
+ userId,
+ safetyEvent);
return safetyCenterDataChanged;
}
@@ -389,6 +416,11 @@ public final class SafetyCenterDataManager {
safetyCenterIssueActionId);
}
+ /** Returns a list of IDs of in-flight actions for the given source and user */
+ ArraySet<SafetyCenterIssueActionId> getInFlightActions(String sourceId, @UserIdInt int userId) {
+ return mSafetyCenterInFlightIssueActionRepository.getInFlightActions(sourceId, userId);
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////////
////////////////////// SafetySourceDataRepository ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -406,8 +438,14 @@ public final class SafetyCenterDataManager {
@Nullable
public SafetySourceData getSafetySourceData(
String safetySourceId, String packageName, @UserIdInt int userId) {
+ boolean callerCanAccessAnySource =
+ mContext.checkCallingOrSelfPermission(MANAGE_SAFETY_CENTER) == PERMISSION_GRANTED;
if (!mSafetySourceDataValidator.validateRequest(
- null, safetySourceId, packageName, userId)) {
+ /* safetySourceData= */ null,
+ callerCanAccessAnySource,
+ safetySourceId,
+ packageName,
+ userId)) {
return null;
}
return mSafetySourceDataRepository.getSafetySourceData(
@@ -472,38 +510,37 @@ public final class SafetyCenterDataManager {
}
private boolean processSafetyEvent(
- String safetySourceId,
+ SafetySourceKey safetySourceKey,
SafetyEvent safetyEvent,
- @UserIdInt int userId,
boolean isError,
- boolean sourceDataChanged) {
+ boolean sourceDataWillChange) {
int type = safetyEvent.getType();
switch (type) {
case SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED:
String refreshBroadcastId = safetyEvent.getRefreshBroadcastId();
if (refreshBroadcastId == null) {
- Log.w(TAG, "No refresh broadcast id in SafetyEvent of type " + type);
+ Log.w(TAG, "No refresh broadcast id in SafetyEvent of type: " + type);
return false;
}
return mSafetyCenterRefreshTracker.reportSourceRefreshCompleted(
- refreshBroadcastId, safetySourceId, userId, !isError, sourceDataChanged);
+ refreshBroadcastId, safetySourceKey, !isError, sourceDataWillChange);
case SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED:
case SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED:
String safetySourceIssueId = safetyEvent.getSafetySourceIssueId();
if (safetySourceIssueId == null) {
- Log.w(TAG, "No safety source issue id in SafetyEvent of type " + type);
+ Log.w(TAG, "No safety source issue id in SafetyEvent of type: " + type);
return false;
}
String safetySourceIssueActionId = safetyEvent.getSafetySourceIssueActionId();
if (safetySourceIssueActionId == null) {
- Log.w(TAG, "No safety source issue action id in SafetyEvent of type " + type);
+ Log.w(TAG, "No safety source issue action id in SafetyEvent of type: " + type);
return false;
}
SafetyCenterIssueKey safetyCenterIssueKey =
SafetyCenterIssueKey.newBuilder()
- .setSafetySourceId(safetySourceId)
+ .setSafetySourceId(safetySourceKey.getSourceId())
.setSafetySourceIssueId(safetySourceIssueId)
- .setUserId(userId)
+ .setUserId(safetySourceKey.getUserId())
.build();
SafetyCenterIssueActionId safetyCenterIssueActionId =
SafetyCenterIssueActionId.newBuilder()
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java b/service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java
index 4fa6e5363..82eb3a6c7 100644
--- a/service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java
+++ b/service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java
@@ -16,33 +16,30 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.os.SystemClock;
import android.safetycenter.SafetySourceIssue;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.permission.util.UserUtils;
+import com.android.safetycenter.SafetySourceIssues;
import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
import java.io.PrintWriter;
import java.time.Duration;
-import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
/** Maintains data about in-flight issue actions. */
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetyCenterInFlightIssueActionRepository {
@@ -113,6 +110,19 @@ final class SafetyCenterInFlightIssueActionRepository {
return mSafetyCenterIssueActionsInFlight.containsKey(safetyCenterIssueActionId);
}
+ /** Returns a list of IDs of in-flight actions for the given source and user */
+ ArraySet<SafetyCenterIssueActionId> getInFlightActions(String sourceId, @UserIdInt int userId) {
+ ArraySet<SafetyCenterIssueActionId> result = new ArraySet<>();
+ for (int i = 0; i < mSafetyCenterIssueActionsInFlight.size(); i++) {
+ SafetyCenterIssueActionId actionId = mSafetyCenterIssueActionsInFlight.keyAt(i);
+ SafetyCenterIssueKey issueKey = actionId.getSafetyCenterIssueKey();
+ if (sourceId.equals(issueKey.getSafetySourceId()) && issueKey.getUserId() == userId) {
+ result.add(actionId);
+ }
+ }
+ return result;
+ }
+
/**
* Returns {@link SafetySourceIssue.Action} identified by the given {@link
* SafetyCenterIssueActionId} and {@link SafetySourceIssue}.
@@ -125,18 +135,8 @@ final class SafetyCenterInFlightIssueActionRepository {
return null;
}
- List<SafetySourceIssue.Action> safetySourceIssueActions = safetySourceIssue.getActions();
- for (int i = 0; i < safetySourceIssueActions.size(); i++) {
- SafetySourceIssue.Action safetySourceIssueAction = safetySourceIssueActions.get(i);
-
- if (safetyCenterIssueActionId
- .getSafetySourceIssueActionId()
- .equals(safetySourceIssueAction.getId())) {
- return safetySourceIssueAction;
- }
- }
-
- return null;
+ return SafetySourceIssues.findAction(
+ safetySourceIssue, safetyCenterIssueActionId.getSafetySourceIssueActionId());
}
/** Dumps in-flight action data for debugging purposes. */
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java b/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java
index d5218a0aa..1a86640dd 100644
--- a/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java
+++ b/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java
@@ -16,7 +16,6 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString;
@@ -27,13 +26,13 @@ import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.safetycenter.config.SafetySourcesGroup;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.safetycenter.SafetySourceIssueInfo;
@@ -48,7 +47,6 @@ import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
/** Deduplicates issues based on deduplication info provided by the source and the issue. */
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetyCenterIssueDeduplicator {
@@ -56,7 +54,6 @@ final class SafetyCenterIssueDeduplicator {
private final SafetyCenterIssueDismissalRepository mSafetyCenterIssueDismissalRepository;
- @RequiresApi(TIRAMISU)
SafetyCenterIssueDeduplicator(
SafetyCenterIssueDismissalRepository safetyCenterIssueDismissalRepository) {
this.mSafetyCenterIssueDismissalRepository = safetyCenterIssueDismissalRepository;
@@ -72,7 +69,7 @@ final class SafetyCenterIssueDeduplicator {
* <p>In case any issue, in the bucket of duplicate issues, was dismissed, all issues of the
* same or lower severity will be dismissed as well.
*
- * @return deduplicated list of issues, and some other information gathere in the deduplication
+ * @return deduplicated list of issues, and some other information gathered in the deduplication
* process
*/
@RequiresApi(UPSIDE_DOWN_CAKE)
@@ -123,7 +120,7 @@ final class SafetyCenterIssueDeduplicator {
for (int i = 0; i < dedupBuckets.size(); i++) {
List<SafetySourceIssueInfo> duplicates = dedupBuckets.valueAt(i);
if (duplicates.isEmpty()) {
- Log.w(TAG, "List of duplicates in a dedupBucket is empty");
+ Log.w(TAG, "List of duplicates in a deduplication bucket is empty");
continue;
}
@@ -164,7 +161,7 @@ final class SafetyCenterIssueDeduplicator {
}
/**
- * Handles dismissals logic: in each bucket, dismissal details of the top (highest priority)
+ * Handles dismissals logic: in each bucket, dismissal details of the highest priority (top)
* dismissed issue will be copied to all other duplicate issues in that bucket, that are of
* equal or lower severity (not priority). Notification-dismissal details are handled similarly.
*/
@@ -329,7 +326,6 @@ final class SafetyCenterIssueDeduplicator {
}
/** Encapsulates deduplication result along with some additional information. */
- @RequiresApi(TIRAMISU) // to simplify code and minimize code path differences across SDKs
static final class DeduplicationInfo {
private final List<SafetySourceIssueInfo> mDeduplicatedIssues;
private final List<SafetySourceIssueInfo> mFilteredOutDuplicates;
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java b/service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java
index bc9bfb2d6..c84aa54f3 100644
--- a/service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java
+++ b/service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java
@@ -16,11 +16,8 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.content.ApexEnvironment;
@@ -30,7 +27,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.modules.utils.BackgroundThread;
import com.android.safetycenter.ApiLock;
@@ -48,6 +45,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
@@ -66,7 +64,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* <p>This class isn't thread safe. Thread safety must be handled by the caller.
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetyCenterIssueDismissalRepository {
@@ -130,11 +127,7 @@ final class SafetyCenterIssueDismissalRepository {
Duration timeSinceLastDismissal = Duration.between(dismissedAt, Instant.now());
boolean isTimeToResurface = timeSinceLastDismissal.compareTo(delay) >= 0;
- if (isTimeToResurface) {
- return false;
- }
-
- return true;
+ return !isTimeToResurface;
}
/**
@@ -342,7 +335,7 @@ final class SafetyCenterIssueDismissalRepository {
* and all following calls won't have any effect.
*/
void resurfaceHiddenIssueAfterPeriod(SafetyCenterIssueKey safetyCenterIssueKey) {
- IssueData issueData = getOrWarn(safetyCenterIssueKey, "resurfaceIssueAfterPeriod");
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "resurfacing hidden issue");
if (issueData == null) {
return;
}
@@ -439,13 +432,22 @@ final class SafetyCenterIssueDismissalRepository {
fout.flush();
try {
Files.copy(issueDismissalRepositoryFile.toPath(), new FileOutputStream(fd));
+ fout.println();
+ } catch (NoSuchFileException e) {
+ fout.println("<No File> (equivalent to empty issue list)");
} catch (IOException e) {
- // TODO(b/266202404)
- e.printStackTrace(fout);
+ printError(e, fout);
}
fout.println();
}
+ // We want to dump the stack trace on a specific PrintWriter here, this is a false positive as
+ // the warning does not consider the overload that takes a PrintWriter as an argument (yet).
+ @SuppressWarnings("CatchAndPrintStackTrace")
+ private void printError(Throwable error, PrintWriter fout) {
+ error.printStackTrace(fout);
+ }
+
@Nullable
private IssueData getOrWarn(SafetyCenterIssueKey issueKey, String reason) {
IssueData issueData = mIssues.get(issueKey);
@@ -492,9 +494,9 @@ final class SafetyCenterIssueDismissalRepository {
try {
persistedSafetyCenterIssues =
SafetyCenterIssuesPersistence.read(getIssueDismissalRepositoryFile());
- Log.i(TAG, "Safety Center persisted issues read successfully");
+ Log.d(TAG, "Safety Center persisted issues read successfully");
} catch (PersistenceException e) {
- Log.e(TAG, "Cannot read Safety Center persisted issues", e);
+ Log.w(TAG, "Cannot read Safety Center persisted issues", e);
}
load(persistedSafetyCenterIssues);
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java b/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java
index 566c28c1e..2e6f707a3 100644
--- a/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java
+++ b/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java
@@ -16,8 +16,6 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static com.android.safetycenter.data.SafetyCenterIssueDeduplicator.DeduplicationInfo;
import static java.util.Collections.emptyList;
@@ -32,8 +30,6 @@ import android.safetycenter.config.SafetySource;
import android.safetycenter.config.SafetySourcesGroup;
import android.util.SparseArray;
-import androidx.annotation.RequiresApi;
-
import com.android.modules.utils.build.SdkLevel;
import com.android.permission.util.UserUtils;
import com.android.safetycenter.SafetyCenterConfigReader;
@@ -56,7 +52,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* <p>Responsible for generating lists of issues and deduplication of issues.
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetyCenterIssueRepository {
@@ -92,19 +87,6 @@ final class SafetyCenterIssueRepository {
* Updates the class as per the current state of issues. Should be called after any state update
* that can affect issues.
*/
- void updateIssues(UserProfileGroup userProfileGroup) {
- updateIssues(userProfileGroup.getProfileParentUserId(), /* isManagedProfile= */ false);
-
- int[] managedProfileUserIds = userProfileGroup.getManagedProfilesUserIds();
- for (int i = 0; i < managedProfileUserIds.length; i++) {
- updateIssues(managedProfileUserIds[i], /* isManagedProfile= */ true);
- }
- }
-
- /**
- * Updates the class as per the current state of issues. Should be called after any state update
- * that can affect issues.
- */
void updateIssues(@UserIdInt int userId) {
updateIssues(userId, UserUtils.isManagedProfile(userId, mContext));
}
diff --git a/service/java/com/android/safetycenter/data/SafetyEventFix.java b/service/java/com/android/safetycenter/data/SafetyEventFix.java
new file mode 100644
index 000000000..4050eddfb
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetyEventFix.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.data;
+
+import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED;
+import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED;
+
+import android.annotation.UserIdInt;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
+
+import java.util.List;
+
+/**
+ * Works around sources sending unexpected {@link SafetyEvent}s by optionally replacing them using
+ * heuristics based on the incoming {@link SafetySourceData} and Safety Center's current state.
+ *
+ * @hide
+ */
+public final class SafetyEventFix {
+
+ private static final String TAG = "SafetyEventFix";
+
+ private SafetyEventFix() {}
+
+ /**
+ * Optionally returns a new {@link SafetyEvent} if heuristics indicate that the one provided by
+ * the source is inappropriate, otherwise returns the source-provided event unchanged.
+ *
+ * <p>If the incoming event has type {@link SafetyEvent#SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED}
+ * but the {@link SafetySourceData} no longer includes an issue, for which Safety Center has a
+ * record of an in-flight, resolving action, then the event will be exchanged for a new one of
+ * type {@link SafetyEvent#SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED}.
+ */
+ public static SafetyEvent maybeOverrideSafetyEvent(
+ SafetyCenterDataManager dataManager,
+ String safetySourceId,
+ @Nullable SafetySourceData safetySourceData,
+ SafetyEvent safetyEvent,
+ @UserIdInt int userId) {
+ if (safetySourceData == null
+ || safetyEvent.getType() != SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED) {
+ return safetyEvent;
+ }
+
+ ArraySet<SafetyCenterIssueActionId> possiblySuccessfulActions =
+ dataManager.getInFlightActions(safetySourceId, userId);
+
+ if (possiblySuccessfulActions.isEmpty()) {
+ return safetyEvent;
+ }
+
+ // Discard any actions for which the issue is still present in the latest source data, they
+ // cannot have been resolved successfully!
+ ArraySet<String> presentSourceIssueIds = getSourceIssueIds(safetySourceData);
+ for (int i = possiblySuccessfulActions.size() - 1; i >= 0; i--) {
+ String sourceIssueId =
+ possiblySuccessfulActions
+ .valueAt(i)
+ .getSafetyCenterIssueKey()
+ .getSafetySourceIssueId();
+ if (presentSourceIssueIds.contains(sourceIssueId)) {
+ possiblySuccessfulActions.removeAt(i);
+ }
+ }
+
+ if (possiblySuccessfulActions.isEmpty()) {
+ return safetyEvent;
+ }
+
+ if (possiblySuccessfulActions.size() > 1) {
+ Log.i(TAG, "Multiple actions resolved, not overriding " + safetyEvent);
+ return safetyEvent;
+ }
+
+ SafetyCenterIssueActionId successfulAction = possiblySuccessfulActions.valueAt(0);
+ SafetyEvent replacement = newActionSucceededEvent(successfulAction);
+ Log.i(TAG, "Replacing incoming " + safetyEvent + " with " + replacement);
+ return replacement;
+ }
+
+ private static ArraySet<String> getSourceIssueIds(SafetySourceData safetySourceData) {
+ List<SafetySourceIssue> issues = safetySourceData.getIssues();
+ ArraySet<String> issueIds = new ArraySet<>(issues.size());
+ for (int i = 0; i < issues.size(); i++) {
+ issueIds.add(issues.get(i).getId());
+ }
+ return issueIds;
+ }
+
+ private static SafetyEvent newActionSucceededEvent(SafetyCenterIssueActionId actionId) {
+ return new SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
+ .setSafetySourceIssueId(actionId.getSafetyCenterIssueKey().getSafetySourceIssueId())
+ .setSafetySourceIssueActionId(actionId.getSafetySourceIssueActionId())
+ .build();
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetySourceDataFix.java b/service/java/com/android/safetycenter/data/SafetySourceDataFix.java
new file mode 100644
index 000000000..a34f3b03b
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetySourceDataFix.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.data;
+
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.safetycenter.SafetySourceData;
+
+import androidx.annotation.Nullable;
+
+import com.android.safetycenter.PendingIntentFactory;
+import com.android.safetycenter.SafetyCenterConfigReader;
+
+/**
+ * Applies various workarounds and fixes to {@link SafetySourceData} as it's received.
+ *
+ * @hide
+ */
+public final class SafetySourceDataFix {
+
+ private final DefaultActionOverrideFix mDefaultActionOverrideFix;
+ private Context mContext;
+
+ public SafetySourceDataFix(
+ Context context,
+ PendingIntentFactory pendingIntentFactory,
+ SafetyCenterConfigReader safetyCenterConfigReader) {
+ mContext = context;
+ mDefaultActionOverrideFix =
+ new DefaultActionOverrideFix(
+ context, pendingIntentFactory, safetyCenterConfigReader);
+ }
+
+ /**
+ * Potentially overrides the {@link SafetySourceData}.
+ *
+ * <p>Should be called when the data is received from a source and before it's stored by Safety
+ * Center.
+ */
+ @Nullable
+ public SafetySourceData maybeOverrideSafetySourceData(
+ String sourceId,
+ @Nullable SafetySourceData safetySourceData,
+ String packageName,
+ @UserIdInt int userId) {
+ if (safetySourceData == null) {
+ return null;
+ }
+
+ if (AndroidLockScreenFix.shouldApplyFix(sourceId)) {
+ safetySourceData = AndroidLockScreenFix.applyFix(mContext, safetySourceData);
+ }
+
+ if (DefaultActionOverrideFix.shouldApplyFix(sourceId)) {
+ safetySourceData =
+ mDefaultActionOverrideFix.applyFix(
+ sourceId, safetySourceData, packageName, userId);
+ }
+
+ return safetySourceData;
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetySourceDataOverrides.java b/service/java/com/android/safetycenter/data/SafetySourceDataOverrides.java
new file mode 100644
index 000000000..b292ae6cb
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetySourceDataOverrides.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.data;
+
+import android.app.PendingIntent;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+import android.safetycenter.SafetySourceStatus;
+
+import com.android.modules.utils.build.SdkLevel;
+
+final class SafetySourceDataOverrides {
+ private SafetySourceDataOverrides() {}
+
+ static SafetySourceData.Builder copyDataToBuilderWithoutIssues(SafetySourceData data) {
+ if (SdkLevel.isAtLeastU()) {
+ return new SafetySourceData.Builder(data).clearIssues();
+ }
+
+ // Copy T-only fields
+ return new SafetySourceData.Builder().setStatus(data.getStatus());
+ }
+
+ static SafetySourceStatus.Builder copyStatusToBuilder(SafetySourceStatus status) {
+ if (SdkLevel.isAtLeastU()) {
+ return new SafetySourceStatus.Builder(status);
+ }
+
+ // Copy T-only fields
+ return new SafetySourceStatus.Builder(
+ status.getTitle(), status.getSummary(), status.getSeverityLevel())
+ .setPendingIntent(status.getPendingIntent())
+ .setEnabled(status.isEnabled())
+ .setIconAction(status.getIconAction());
+ }
+
+ static SafetySourceIssue.Builder copyIssueToBuilderWithoutActions(SafetySourceIssue issue) {
+ if (SdkLevel.isAtLeastU()) {
+ return new SafetySourceIssue.Builder(issue).clearActions();
+ }
+
+ // Copy T-only fields
+ return new SafetySourceIssue.Builder(
+ issue.getId(),
+ issue.getTitle(),
+ issue.getSummary(),
+ issue.getSeverityLevel(),
+ issue.getIssueTypeId())
+ .setIssueCategory(issue.getIssueCategory())
+ .setSubtitle(issue.getSubtitle())
+ .setOnDismissPendingIntent(issue.getOnDismissPendingIntent());
+ }
+
+ /**
+ * Returns an new {@link SafetySourceIssue.Action} object, replacing its {@link PendingIntent}
+ * with the one supplied.
+ */
+ static SafetySourceIssue.Action overrideActionPendingIntent(
+ SafetySourceIssue.Action action, PendingIntent pendingIntent) {
+ // TODO(b/303443020): Add setter for pendingIntent so this method can use the copy builder.
+ return new SafetySourceIssue.Action.Builder(
+ action.getId(), action.getLabel(), pendingIntent)
+ .setWillResolve(action.willResolve())
+ .setSuccessMessage(action.getSuccessMessage())
+ .build();
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetySourceDataRepository.java b/service/java/com/android/safetycenter/data/SafetySourceDataRepository.java
index b47f7925e..cdb8709d6 100644
--- a/service/java/com/android/safetycenter/data/SafetySourceDataRepository.java
+++ b/service/java/com/android/safetycenter/data/SafetySourceDataRepository.java
@@ -16,18 +16,14 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__DATA_PROVIDED;
import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__NO_DATA_PROVIDED;
import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_TIMEOUT;
import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_CLEARED;
import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR;
-import android.annotation.Nullable;
import android.annotation.UptimeMillisLong;
import android.annotation.UserIdInt;
-import android.content.Context;
import android.os.SystemClock;
import android.safetycenter.SafetyCenterData;
import android.safetycenter.SafetyEvent;
@@ -38,7 +34,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.safetycenter.SafetySourceKey;
import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
@@ -57,7 +53,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* <p>This class isn't thread safe. Thread safety must be handled by the caller.
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetySourceDataRepository {
@@ -68,24 +63,20 @@ final class SafetySourceDataRepository {
private final ArrayMap<SafetySourceKey, Long> mSafetySourceLastUpdated = new ArrayMap<>();
private final ArrayMap<SafetySourceKey, Integer> mSourceStates = new ArrayMap<>();
- private final Context mContext;
private final SafetyCenterInFlightIssueActionRepository
mSafetyCenterInFlightIssueActionRepository;
private final SafetyCenterIssueDismissalRepository mSafetyCenterIssueDismissalRepository;
SafetySourceDataRepository(
- Context context,
SafetyCenterInFlightIssueActionRepository safetyCenterInFlightIssueActionRepository,
SafetyCenterIssueDismissalRepository safetyCenterIssueDismissalRepository) {
- mContext = context;
mSafetyCenterInFlightIssueActionRepository = safetyCenterInFlightIssueActionRepository;
mSafetyCenterIssueDismissalRepository = safetyCenterIssueDismissalRepository;
}
/**
- * Sets the latest {@link SafetySourceData} for the given {@code safetySourceId}, {@link
- * SafetyEvent}, {@code packageName} and {@code userId}, and returns {@code true} if this caused
- * any changes which would alter {@link SafetyCenterData}.
+ * Sets the latest {@link SafetySourceData} for the given {@link SafetySourceKey}, and returns
+ * {@code true} if this caused any changes which would alter {@link SafetyCenterData}.
*
* <p>This method does not perform any validation, {@link
* SafetyCenterDataManager#setSafetySourceData(SafetySourceData, String, SafetyEvent, String,
@@ -98,22 +89,16 @@ final class SafetySourceDataRepository {
* <p>This method may modify the {@link SafetyCenterIssueDismissalRepository}.
*/
boolean setSafetySourceData(
- @Nullable SafetySourceData safetySourceData,
- String safetySourceId,
- @UserIdInt int userId) {
- SafetySourceKey key = SafetySourceKey.of(safetySourceId, userId);
- safetySourceData =
- AndroidLockScreenFix.maybeOverrideSafetySourceData(
- mContext, safetySourceId, safetySourceData);
-
- boolean sourceDataDiffers = !Objects.equals(safetySourceData, mSafetySourceData.get(key));
- boolean removedSourceError = mSafetySourceErrors.remove(key);
+ SafetySourceKey safetySourceKey, @Nullable SafetySourceData safetySourceData) {
+ boolean sourceDataDiffers =
+ !Objects.equals(safetySourceData, mSafetySourceData.get(safetySourceKey));
+ boolean removedSourceError = mSafetySourceErrors.remove(safetySourceKey);
if (sourceDataDiffers) {
- setSafetySourceDataInternal(key, safetySourceData);
+ setSafetySourceDataInternal(safetySourceKey, safetySourceData);
}
- setLastUpdatedNow(key);
+ setLastUpdatedNow(safetySourceKey);
return sourceDataDiffers || removedSourceError;
}
@@ -155,19 +140,33 @@ final class SafetySourceDataRepository {
}
/**
- * Reports the given {@link SafetySourceErrorDetails} for the given {@code safetySourceId} and
- * {@code userId}, and returns {@code true} if this changed the repository's data.
+ * Returns whether the repository has the given {@link SafetySourceData} for the given {@link
+ * SafetySourceKey}.
+ */
+ boolean sourceHasData(
+ SafetySourceKey safetySourceKey, @Nullable SafetySourceData safetySourceData) {
+ if (mSafetySourceErrors.contains(safetySourceKey)) {
+ // Any error will cause the SafetySourceData to be discarded in favor of an error
+ // message, so it can't possibly match the SafetySourceData passed in parameter.
+ return false;
+ }
+ return Objects.equals(safetySourceData, mSafetySourceData.get(safetySourceKey));
+ }
+
+ /**
+ * Reports the given {@link SafetySourceErrorDetails} for the given {@link SafetySourceKey}, and
+ * returns {@code true} if this changed the repository's data.
*
* <p>This method does not perform any validation, {@link
* SafetyCenterDataManager#reportSafetySourceError(SafetySourceErrorDetails, String, String,
* int)} should be called wherever validation is required.
*/
boolean reportSafetySourceError(
- SafetySourceErrorDetails safetySourceErrorDetails,
- String safetySourceId,
- @UserIdInt int userId) {
+ SafetySourceKey safetySourceKey, SafetySourceErrorDetails safetySourceErrorDetails) {
SafetyEvent safetyEvent = safetySourceErrorDetails.getSafetyEvent();
- Log.w(TAG, "Error reported from source: " + safetySourceId + ", for event: " + safetyEvent);
+ Log.w(
+ TAG,
+ "Error reported from source: " + safetySourceKey + ", for event: " + safetyEvent);
int safetyEventType = safetyEvent.getType();
if (safetyEventType == SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
@@ -175,9 +174,9 @@ final class SafetySourceDataRepository {
return false;
}
- SafetySourceKey sourceKey = SafetySourceKey.of(safetySourceId, userId);
- mSourceStates.put(sourceKey, SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR);
- return setSafetySourceError(sourceKey);
+ mSourceStates.put(
+ safetySourceKey, SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR);
+ return setSafetySourceError(safetySourceKey);
}
/**
@@ -339,9 +338,9 @@ final class SafetySourceDataRepository {
SafetySourceKey key = mSafetySourceErrors.valueAt(i);
fout.println("\t[" + i + "] " + key);
}
+ fout.println();
dumpArrayMap(fout, mSafetySourceLastUpdated, "LAST UPDATED");
dumpArrayMap(fout, mSourceStates, "SOURCE STATES");
- fout.println();
}
private static <K, V> void dumpArrayMap(PrintWriter fout, ArrayMap<K, V> map, String label) {
@@ -350,5 +349,6 @@ final class SafetySourceDataRepository {
for (int i = 0; i < count; i++) {
fout.println("\t[" + i + "] " + map.keyAt(i) + " -> " + map.valueAt(i));
}
+ fout.println();
}
}
diff --git a/service/java/com/android/safetycenter/data/SafetySourceDataValidator.java b/service/java/com/android/safetycenter/data/SafetySourceDataValidator.java
index cc265d7f9..942e4ce18 100644
--- a/service/java/com/android/safetycenter/data/SafetySourceDataValidator.java
+++ b/service/java/com/android/safetycenter/data/SafetySourceDataValidator.java
@@ -16,9 +16,6 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -29,7 +26,7 @@ import android.safetycenter.SafetySourceStatus;
import android.safetycenter.config.SafetySource;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
import com.android.permission.util.UserUtils;
@@ -48,11 +45,10 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* <p>This class isn't thread safe. Thread safety must be handled by the caller.
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetySourceDataValidator {
- private static final String TAG = "SafetySourceDataValidator";
+ private static final String TAG = "SafetySourceDataValidat";
private final Context mContext;
private final SafetyCenterConfigReader mSafetyCenterConfigReader;
@@ -74,9 +70,12 @@ final class SafetySourceDataValidator {
*
* @param safetySourceData being set, or {@code null} if retrieving or clearing data, or
* reporting an error
+ * @param callerCanAccessAnySource whether we should allow the caller to access any source, or
+ * restrict them to their own {@code packageName}
*/
boolean validateRequest(
@Nullable SafetySourceData safetySourceData,
+ boolean callerCanAccessAnySource,
String safetySourceId,
String packageName,
@UserIdInt int userId) {
@@ -87,7 +86,9 @@ final class SafetySourceDataValidator {
}
SafetySource safetySource = externalSafetySource.getSafetySource();
- validateCallingPackage(safetySource, packageName, safetySourceId);
+ if (!callerCanAccessAnySource) {
+ validateCallingPackage(safetySource, packageName, safetySourceId);
+ }
if (UserUtils.isManagedProfile(userId, mContext)
&& !SafetySources.supportsManagedProfiles(safetySource)) {
@@ -97,8 +98,8 @@ final class SafetySourceDataValidator {
boolean retrievingOrClearingData = safetySourceData == null;
if (retrievingOrClearingData) {
- return mSafetyCenterConfigReader.isExternalSafetySourceActive(
- safetySourceId, packageName);
+ return isExternalSafetySourceActive(
+ callerCanAccessAnySource, safetySourceId, packageName);
}
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
@@ -110,6 +111,8 @@ final class SafetySourceDataValidator {
}
if (safetySource.getType() == SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC
+ && safetySource.getInitialDisplayState()
+ != SafetySource.INITIAL_DISPLAY_STATE_HIDDEN
&& safetySourceStatus == null) {
throw new IllegalArgumentException(
"Missing status for dynamic safety source: " + safetySourceId);
@@ -164,7 +167,20 @@ final class SafetySourceDataValidator {
}
}
- return mSafetyCenterConfigReader.isExternalSafetySourceActive(safetySourceId, packageName);
+ return isExternalSafetySourceActive(callerCanAccessAnySource, safetySourceId, packageName);
+ }
+
+ private boolean isExternalSafetySourceActive(
+ boolean callerCanAccessAnySource, String safetySourceId, String callerPackageName) {
+ boolean isActive =
+ mSafetyCenterConfigReader.isExternalSafetySourceActive(
+ safetySourceId, callerCanAccessAnySource ? null : callerPackageName);
+ if (!isActive) {
+ Log.i(
+ TAG,
+ "Call ignored as safety source " + safetySourceId + " is not currently active");
+ }
+ return isActive;
}
private void validateCallingPackage(
@@ -192,13 +208,13 @@ final class SafetySourceDataValidator {
&& !checkCerts(
packageName,
SafetyCenterFlags.getAdditionalAllowedPackageCerts(packageName))) {
- Log.e(
+ Log.w(
TAG,
- "Package "
+ "Package: "
+ packageName
- + " for source "
+ + ", for source: "
+ safetySourceId
- + " signed with invalid signature");
+ + " is signed with invalid signature");
throw new IllegalArgumentException("Invalid signature for package " + packageName);
}
}
@@ -210,7 +226,7 @@ final class SafetySourceDataValidator {
byte[] certificate = new Signature(certHash).toByteArray();
if (mPackageManager.hasSigningCertificate(
packageName, certificate, PackageManager.CERT_INPUT_SHA256)) {
- Log.d(TAG, "Package " + packageName + " has expected signature");
+ Log.v(TAG, "Package: " + packageName + " has expected signature");
hasMatchingCert = true;
}
} catch (IllegalArgumentException e) {
diff --git a/service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java b/service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java
index b6bf280ae..e73459598 100644
--- a/service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java
+++ b/service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java
@@ -16,10 +16,7 @@
package com.android.safetycenter.data;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import android.annotation.ElapsedRealtimeLong;
-import android.annotation.Nullable;
import android.content.Context;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyEvent;
@@ -27,7 +24,7 @@ import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceIssue;
import android.safetycenter.SafetySourceStatus;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.permission.util.UserUtils;
import com.android.safetycenter.SafetySourceIssueInfo;
@@ -44,7 +41,6 @@ import javax.annotation.concurrent.NotThreadSafe;
* Collates information from various data-related classes and uses that information to log {@code
* SafetySourceStateCollected} atoms.
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
final class SafetySourceStateCollectedLogger {
@@ -132,10 +128,11 @@ final class SafetySourceStateCollectedLogger {
}
}
+ Integer severityLevel = maxSeverityLevel > Integer.MIN_VALUE ? maxSeverityLevel : null;
SafetyCenterStatsdLogger.writeSafetySourceStateCollected(
sourceKey.getSourceId(),
isManagedProfile,
- maxSeverityLevel > Integer.MIN_VALUE ? maxSeverityLevel : null,
+ severityLevel,
openIssuesCount,
dismissedIssuesCount,
getDuplicateCount(sourceKey),
diff --git a/service/java/com/android/safetycenter/data/package-info.java b/service/java/com/android/safetycenter/data/package-info.java
index 597847505..a125b3176 100644
--- a/service/java/com/android/safetycenter/data/package-info.java
+++ b/service/java/com/android/safetycenter/data/package-info.java
@@ -14,6 +14,11 @@
* limitations under the License.
*/
@NonNullByDefault
+@RequiresApi(TIRAMISU)
package com.android.safetycenter.data;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import android.annotation.RequiresApi;
+
import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java b/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java
index d9514f56e..168d73a0f 100644
--- a/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java
+++ b/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java
@@ -16,8 +16,6 @@
package com.android.safetycenter.logging;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static com.android.permission.PermissionStatsLog.SAFETY_STATE;
import android.annotation.UserIdInt;
@@ -30,8 +28,6 @@ import android.safetycenter.config.SafetySourcesGroup;
import android.util.Log;
import android.util.StatsEvent;
-import androidx.annotation.RequiresApi;
-
import com.android.internal.annotations.GuardedBy;
import com.android.modules.utils.build.SdkLevel;
import com.android.permission.PermissionStatsLog;
@@ -56,7 +52,6 @@ import java.util.List;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class SafetyCenterPullAtomCallback implements StatsPullAtomCallback {
private static final String TAG = "SafetyCenterPullAtom";
@@ -93,17 +88,17 @@ public final class SafetyCenterPullAtomCallback implements StatsPullAtomCallback
return StatsManager.PULL_SKIP;
}
if (!SafetyCenterFlags.getSafetyCenterEnabled()) {
- Log.w(TAG, "Attempt to pull SAFETY_STATE, but Safety Center is disabled");
+ Log.i(TAG, "Attempt to pull SAFETY_STATE, but Safety Center is disabled");
return StatsManager.PULL_SKIP;
}
List<UserProfileGroup> userProfileGroups =
UserProfileGroup.getAllUserProfileGroups(mContext);
synchronized (mApiLock) {
if (!SafetyCenterFlags.getAllowStatsdLogging()) {
- Log.w(TAG, "Skipping pulling and writing atoms due to logging being disabled");
+ Log.i(TAG, "Skipping pulling and writing atoms due to logging being disabled");
return StatsManager.PULL_SKIP;
}
- Log.i(TAG, "Pulling and writing atoms…");
+ Log.d(TAG, "Pulling and writing atoms…");
for (int i = 0; i < userProfileGroups.size(); i++) {
UserProfileGroup userProfileGroup = userProfileGroups.get(i);
List<SafetySourcesGroup> loggableGroups =
@@ -111,8 +106,8 @@ public final class SafetyCenterPullAtomCallback implements StatsPullAtomCallback
statsEvents.add(
createOverallSafetyStateAtomLocked(userProfileGroup, loggableGroups));
// The SAFETY_SOURCE_STATE_COLLECTED atoms are written instead of being pulled,
- // they do not support pull but we want to collect them at the same time as
- // the above pulled atom.
+ // as they do not support pull. We still want to collect them at the same time as
+ // the above pulled atom, which is why they're written here.
writeSafetySourceStateCollectedAtomsLocked(userProfileGroup, loggableGroups);
}
}
@@ -165,7 +160,8 @@ public final class SafetyCenterPullAtomCallback implements StatsPullAtomCallback
int[] managedIds = userProfileGroup.getManagedRunningProfilesUserIds();
for (int k = 0; k < managedIds.length; k++) {
- writeSafetySourceStateCollectedAtomLocked(loggableSource, managedIds[k], true);
+ writeSafetySourceStateCollectedAtomLocked(
+ loggableSource, managedIds[k], /* isUserManaged= */ true);
}
}
}
diff --git a/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java b/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java
index 8ca662d27..710c3f7ac 100644
--- a/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java
+++ b/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java
@@ -16,8 +16,6 @@
package com.android.safetycenter.logging;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED;
import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_PRIMARY_ACTION_CLICKED;
import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_SECONDARY_ACTION_CLICKED;
@@ -74,7 +72,6 @@ import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SE
import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
-import android.annotation.Nullable;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyCenterManager.RefreshRequestType;
import android.safetycenter.SafetyCenterStatus;
@@ -83,7 +80,7 @@ import android.safetycenter.SafetySourceData;
import android.util.Log;
import android.util.StatsEvent;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.permission.PermissionStatsLog;
import com.android.safetycenter.SafetyCenterFlags;
@@ -101,7 +98,6 @@ import java.time.Duration;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class SafetyCenterStatsdLogger {
private static final String TAG = "SafetyCenterStatsdLog";
diff --git a/service/java/com/android/safetycenter/logging/package-info.java b/service/java/com/android/safetycenter/logging/package-info.java
index dcc1828b4..79e504ebd 100644
--- a/service/java/com/android/safetycenter/logging/package-info.java
+++ b/service/java/com/android/safetycenter/logging/package-info.java
@@ -14,6 +14,11 @@
* limitations under the License.
*/
@NonNullByDefault
+@RequiresApi(TIRAMISU)
package com.android.safetycenter.logging;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import android.annotation.RequiresApi;
+
import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationChannels.java b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationChannels.java
index 5308cdae8..ccd2bfabc 100644
--- a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationChannels.java
+++ b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationChannels.java
@@ -16,11 +16,6 @@
package com.android.safetycenter.notifications;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.Nullable;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
@@ -31,10 +26,11 @@ import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceIssue;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.permission.util.UserUtils;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.SafetyCenterFlags;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import java.util.List;
@@ -43,7 +39,6 @@ import java.util.List;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class SafetyCenterNotificationChannels {
private static final String TAG = "SafetyCenterNC";
@@ -53,11 +48,10 @@ public final class SafetyCenterNotificationChannels {
private static final String CHANNEL_ID_RECOMMENDATION = "safety_center_recommendation";
private static final String CHANNEL_ID_CRITICAL_WARNING = "safety_center_critical_warning";
- private final SafetyCenterResourcesContext mResourcesContext;
+ private final SafetyCenterResourcesApk mSafetyCenterResourcesApk;
- public SafetyCenterNotificationChannels(
- SafetyCenterResourcesContext safetyCenterResourceContext) {
- mResourcesContext = safetyCenterResourceContext;
+ public SafetyCenterNotificationChannels(SafetyCenterResourcesApk safetyCenterResourcesApk) {
+ mSafetyCenterResourcesApk = safetyCenterResourcesApk;
}
/** Returns a {@link NotificationManager} which will send notifications to the given user. */
@@ -70,7 +64,10 @@ public final class SafetyCenterNotificationChannels {
? contextAsUser.getSystemService(NotificationManager.class)
: null;
if (notificationManager == null) {
- Log.w(TAG, "Could not retrieve NotificationManager for user " + userHandle);
+ Log.w(
+ TAG,
+ "Could not retrieve NotificationManager for user id: "
+ + userHandle.getIdentifier());
}
return notificationManager;
}
@@ -80,9 +77,9 @@ public final class SafetyCenterNotificationChannels {
// This call requires the INTERACT_ACROSS_USERS permission.
final long callingId = Binder.clearCallingIdentity();
try {
- return baseContext.createContextAsUser(userHandle, 0);
+ return baseContext.createContextAsUser(userHandle, /* flags= */ 0);
} catch (RuntimeException e) {
- Log.w(TAG, "Could not create Context as user " + userHandle, e);
+ Log.w(TAG, "Could not create Context as user id: " + userHandle.getIdentifier(), e);
return null;
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -106,10 +103,18 @@ public final class SafetyCenterNotificationChannels {
/**
* Creates all Safety Center {@link NotificationChannel}s instances and their group, for all
- * current users, dropping any calling identity so those channels can be unblockable. Throws a
- * {@link RuntimeException} if any channel is malformed and could not be created.
+ * current users, dropping any calling identity so those channels can be unblockable.
*/
public void createAllChannelsForAllUsers(Context context) {
+ if (!SafetyCenterFlags.getNotificationsEnabled()) {
+ // TODO(b/284271124): Decide what to do with existing channels if flag gets toggled.
+ Log.i(
+ TAG,
+ "Not creating notification channels because Safety Center notifications are"
+ + " disabled");
+ return;
+ }
+
List<UserHandle> users = UserUtils.getUserHandles(context);
for (int i = 0; i < users.size(); i++) {
createAllChannelsForUser(context, users.get(i));
@@ -119,31 +124,54 @@ public final class SafetyCenterNotificationChannels {
/**
* Creates all Safety Center {@link NotificationChannel}s instances and their group for the
* given {@link UserHandle}, dropping any calling identity so those channels can be unblockable.
- * Throws a {@link RuntimeException} if any channel is malformed and could not be created.
*/
public void createAllChannelsForUser(Context context, UserHandle user) {
+ if (!SafetyCenterFlags.getNotificationsEnabled()) {
+ // TODO(b/284271124): Decide what to do with existing channels if flag gets toggled.
+ Log.i(
+ TAG,
+ "Not creating notification channels because Safety Center notifications are"
+ + " disabled");
+ return;
+ }
+
+ NotificationManager notificationManager = getNotificationManagerForUser(context, user);
+ if (notificationManager == null) {
+ return;
+ }
+
try {
- NotificationManager notificationManager =
- requireNonNull(getNotificationManagerForUser(context, user));
createAllChannelsWithoutCallingIdentity(notificationManager);
} catch (RuntimeException e) {
- Log.w(TAG, "Error creating notification channels for user " + user.getIdentifier(), e);
+ Log.w(
+ TAG,
+ "Error creating notification channels for user id: " + user.getIdentifier(),
+ e);
}
}
@Nullable
private String getChannelIdForIssue(SafetySourceIssue issue) {
- switch (issue.getSeverityLevel()) {
+ int issueSeverityLevel = issue.getSeverityLevel();
+ switch (issueSeverityLevel) {
case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
return CHANNEL_ID_INFORMATION;
case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
return CHANNEL_ID_RECOMMENDATION;
case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
return CHANNEL_ID_CRITICAL_WARNING;
- default:
- Log.w(TAG, "No applicable notification channel for issue " + issue);
+ case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
+ Log.w(TAG, "SafetySourceData.SeverityLevel is unspecified for issue: " + issue);
return null;
}
+
+ Log.w(
+ TAG,
+ "Unexpected SafetySourceData.SeverityLevel: "
+ + issueSeverityLevel
+ + ", for issue: "
+ + issue);
+ return null;
}
/**
@@ -153,7 +181,8 @@ public final class SafetyCenterNotificationChannels {
* created.
*/
private void createAllChannelsWithoutCallingIdentity(NotificationManager notificationManager) {
- // Clearing calling identity to be able to make unblockable system notification channels
+ // Clearing calling identity to be able to make unblockable system notification channels and
+ // call this for other users with the INTERACT_ACROSS_USERS permission.
final long callingId = Binder.clearCallingIdentity();
try {
notificationManager.createNotificationChannelGroup(getChannelGroupDefinition());
@@ -165,6 +194,17 @@ public final class SafetyCenterNotificationChannels {
}
}
+ private void clearAllChannelsWithoutCallingIdentity(NotificationManager notificationManager) {
+ // Clearing calling identity to do this for other users with the INTERACT_ACROSS_USERS
+ // permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ notificationManager.deleteNotificationChannelGroup(CHANNEL_GROUP_ID);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
private NotificationChannelGroup getChannelGroupDefinition() {
return new NotificationChannelGroup(
CHANNEL_GROUP_ID, getString("notification_channel_group_name"));
@@ -204,6 +244,6 @@ public final class SafetyCenterNotificationChannels {
}
private String getString(String name) {
- return mResourcesContext.getStringByName(name);
+ return mSafetyCenterResourcesApk.getStringByName(name);
}
}
diff --git a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java
index a8da70cf0..84001f249 100644
--- a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java
+++ b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java
@@ -16,7 +16,6 @@
package com.android.safetycenter.notifications;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID;
import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID;
import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_USER_HANDLE;
@@ -24,7 +23,6 @@ import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_USER_
import static com.android.safetycenter.notifications.SafetyCenterNotificationChannels.getContextAsUser;
import android.annotation.ColorInt;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -32,7 +30,6 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.UserHandle;
@@ -40,14 +37,14 @@ import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceIssue;
import android.text.TextUtils;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
import com.android.safetycenter.PendingIntentFactory;
import com.android.safetycenter.internaldata.SafetyCenterIds;
import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import java.time.Duration;
import java.util.List;
@@ -56,24 +53,22 @@ import java.util.List;
* Factory that builds {@link Notification} objects from {@link SafetySourceIssue} instances with
* appropriate {@link PendingIntent}s for click and dismiss callbacks.
*/
-@RequiresApi(TIRAMISU)
final class SafetyCenterNotificationFactory {
- private static final String TAG = "SafetyCenterNF";
private static final int OPEN_SAFETY_CENTER_REQUEST_CODE = 1221;
private static final Duration SUCCESS_NOTIFICATION_TIMEOUT = Duration.ofSeconds(10);
private final Context mContext;
private final SafetyCenterNotificationChannels mNotificationChannels;
- private final SafetyCenterResourcesContext mResourcesContext;
+ private final SafetyCenterResourcesApk mSafetyCenterResourcesApk;
SafetyCenterNotificationFactory(
Context context,
SafetyCenterNotificationChannels notificationChannels,
- SafetyCenterResourcesContext resourcesContext) {
+ SafetyCenterResourcesApk safetyCenterResourcesApk) {
mContext = context;
mNotificationChannels = notificationChannels;
- mResourcesContext = resourcesContext;
+ mSafetyCenterResourcesApk = safetyCenterResourcesApk;
}
/**
@@ -89,6 +84,10 @@ final class SafetyCenterNotificationFactory {
SafetySourceIssue issue,
SafetySourceIssue.Action action,
@UserIdInt int userId) {
+ if (action.getSuccessMessage() == null) {
+ return null;
+ }
+
String channelId = mNotificationChannels.getCreatedChannelId(notificationManager, issue);
if (channelId == null) {
return null;
@@ -107,7 +106,8 @@ final class SafetyCenterNotificationFactory {
.setContentTitle(action.getSuccessMessage())
.setShowWhen(true)
.setTimeoutAfter(SUCCESS_NOTIFICATION_TIMEOUT.toMillis())
- .setContentIntent(contentIntent);
+ .setContentIntent(contentIntent)
+ .setAutoCancel(true);
Integer color = getNotificationColor(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
if (color != null) {
@@ -175,6 +175,10 @@ final class SafetyCenterNotificationFactory {
builder.addAction(notificationAction);
}
+ if (issue.getSeverityLevel() == SafetySourceData.SEVERITY_LEVEL_INFORMATION) {
+ builder.setAutoCancel(true);
+ }
+
return builder.build();
}
@@ -231,7 +235,7 @@ final class SafetyCenterNotificationFactory {
if (severityLevel == SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING) {
iconResName = "ic_notification_badge_critical";
}
- Icon icon = mResourcesContext.getIconByDrawableName(iconResName);
+ Icon icon = mSafetyCenterResourcesApk.getIconByDrawableName(iconResName);
if (icon == null) {
// In case it was impossible to fetch the above drawable for any reason use this
// fallback which should be present on all Android devices:
@@ -247,12 +251,13 @@ final class SafetyCenterNotificationFactory {
if (severityLevel == SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING) {
colorResName = "notification_tint_critical";
}
- return mResourcesContext.getColorByName(colorResName);
+ return mSafetyCenterResourcesApk.getColorByName(colorResName);
}
private Bundle getNotificationExtras() {
Bundle extras = new Bundle();
- String appName = mResourcesContext.getStringByName("notification_channel_group_name");
+ String appName =
+ mSafetyCenterResourcesApk.getStringByName("notification_channel_group_name");
if (!TextUtils.isEmpty(appName)) {
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appName);
}
@@ -262,7 +267,9 @@ final class SafetyCenterNotificationFactory {
private Notification.Action toNotificationAction(
SafetyCenterIssueKey issueKey, SafetySourceIssue.Action issueAction) {
PendingIntent pendingIntent = getPendingIntentForAction(issueKey, issueAction);
- return new Notification.Action.Builder(null, issueAction.getLabel(), pendingIntent).build();
+ return new Notification.Action.Builder(
+ /* icon= */ null, issueAction.getLabel(), pendingIntent)
+ .build();
}
private PendingIntent getPendingIntentForAction(
@@ -270,7 +277,7 @@ final class SafetyCenterNotificationFactory {
if (issueAction.willResolve()) {
return getReceiverPendingIntentForResolvingAction(issueKey, issueAction);
} else {
- return getDirectPendingIntentForNonResolvingAction(issueKey, issueAction);
+ return getDirectPendingIntentForNonResolvingAction(issueAction);
}
}
@@ -291,12 +298,7 @@ final class SafetyCenterNotificationFactory {
}
private PendingIntent getDirectPendingIntentForNonResolvingAction(
- SafetyCenterIssueKey issueKey, SafetySourceIssue.Action issueAction) {
+ SafetySourceIssue.Action issueAction) {
return issueAction.getPendingIntent();
}
-
- private static boolean isDarkTheme(Context context) {
- return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
- == Configuration.UI_MODE_NIGHT_YES;
- }
}
diff --git a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationReceiver.java b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationReceiver.java
index 0b4ac5ab3..ed0e95177 100644
--- a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationReceiver.java
+++ b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationReceiver.java
@@ -16,9 +16,6 @@
package com.android.safetycenter.notifications;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
-import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -27,7 +24,7 @@ import android.content.IntentFilter;
import android.safetycenter.SafetySourceIssue;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.GuardedBy;
import com.android.permission.util.UserUtils;
@@ -36,6 +33,7 @@ import com.android.safetycenter.PendingIntentFactory;
import com.android.safetycenter.SafetyCenterDataChangeNotifier;
import com.android.safetycenter.SafetyCenterFlags;
import com.android.safetycenter.SafetyCenterService;
+import com.android.safetycenter.SafetySourceIssues;
import com.android.safetycenter.UserProfileGroup;
import com.android.safetycenter.data.SafetyCenterDataManager;
import com.android.safetycenter.internaldata.SafetyCenterIds;
@@ -54,7 +52,6 @@ import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
public final class SafetyCenterNotificationReceiver extends BroadcastReceiver {
private static final String TAG = "SafetyCenterNR";
@@ -120,13 +117,13 @@ public final class SafetyCenterNotificationReceiver extends BroadcastReceiver {
private static SafetyCenterIssueActionId getIssueActionIdExtra(Intent intent) {
String issueActionIdString = intent.getStringExtra(EXTRA_ISSUE_ACTION_ID);
if (issueActionIdString == null) {
- Log.w(TAG, "Received notification action broadcast with null issue action ID");
+ Log.w(TAG, "Received notification action broadcast with null issue action id");
return null;
}
try {
return SafetyCenterIds.issueActionIdFromString(issueActionIdString);
} catch (IllegalArgumentException e) {
- Log.w(TAG, "Could not decode the issue action ID", e);
+ Log.w(TAG, "Could not decode the issue action id", e);
return null;
}
}
@@ -162,22 +159,28 @@ public final class SafetyCenterNotificationReceiver extends BroadcastReceiver {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_NOTIFICATION_DISMISSED);
filter.addAction(ACTION_NOTIFICATION_ACTION_CLICKED);
- context.registerReceiver(this, filter, Context.RECEIVER_NOT_EXPORTED);
+ context.registerReceiver(/* receiver= */ this, filter, Context.RECEIVER_NOT_EXPORTED);
}
@Override
public void onReceive(Context context, Intent intent) {
- if (!SafetyCenterFlags.getSafetyCenterEnabled()
- || !SafetyCenterFlags.getNotificationsEnabled()) {
+ if (!SafetyCenterFlags.getSafetyCenterEnabled()) {
+ Log.i(TAG, "Received notification broadcast but Safety Center is disabled");
+ return;
+ }
+
+ if (!SafetyCenterFlags.getNotificationsEnabled()) {
+ // TODO(b/284271124): Decide what to do with existing notifications
+ Log.i(TAG, "Received notification broadcast but notifications are disabled");
return;
}
- Log.d(TAG, "Received broadcast with action " + intent.getAction());
String action = intent.getAction();
if (action == null) {
- Log.w(TAG, "Received broadcast with null action!");
+ Log.w(TAG, "Received broadcast with null action");
return;
}
+ Log.d(TAG, "Received broadcast with action: " + action);
switch (action) {
case ACTION_NOTIFICATION_DISMISSED:
@@ -240,16 +243,8 @@ public final class SafetyCenterNotificationReceiver extends BroadcastReceiver {
UserUtils.isManagedProfile(issueKey.getUserId(), context),
issue.getIssueTypeId(),
issue.getSeverityLevel(),
- isPrimaryAction(issue, issueActionId));
+ SafetySourceIssues.isPrimaryAction(
+ issue, issueActionId.getSafetySourceIssueActionId()));
}
}
-
- /** Returns {@code true} if {@code actionId} is the first action of {@code issue}. */
- private boolean isPrimaryAction(SafetySourceIssue issue, SafetyCenterIssueActionId actionId) {
- return !issue.getActions().isEmpty()
- && issue.getActions()
- .get(0)
- .getId()
- .equals(actionId.getSafetySourceIssueActionId());
- }
}
diff --git a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationSender.java b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationSender.java
index 72b1f0e95..d17090c34 100644
--- a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationSender.java
+++ b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationSender.java
@@ -16,13 +16,11 @@
package com.android.safetycenter.notifications;
-import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED;
import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString;
import android.annotation.IntDef;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Notification;
import android.app.NotificationManager;
@@ -36,18 +34,19 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
import com.android.permission.util.UserUtils;
import com.android.safetycenter.SafetyCenterFlags;
import com.android.safetycenter.SafetySourceIssueInfo;
+import com.android.safetycenter.SafetySourceIssues;
import com.android.safetycenter.UserProfileGroup;
import com.android.safetycenter.data.SafetyCenterDataManager;
import com.android.safetycenter.internaldata.SafetyCenterIds;
import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
-import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+import com.android.safetycenter.resources.SafetyCenterResourcesApk;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -66,7 +65,6 @@ import javax.annotation.concurrent.NotThreadSafe;
*
* @hide
*/
-@RequiresApi(TIRAMISU)
@NotThreadSafe
public final class SafetyCenterNotificationSender {
@@ -120,13 +118,13 @@ public final class SafetyCenterNotificationSender {
public static SafetyCenterNotificationSender newInstance(
Context context,
- SafetyCenterResourcesContext resourcesContext,
+ SafetyCenterResourcesApk safetyCenterResourcesApk,
SafetyCenterNotificationChannels notificationChannels,
SafetyCenterDataManager dataManager) {
return new SafetyCenterNotificationSender(
context,
new SafetyCenterNotificationFactory(
- context, notificationChannels, resourcesContext),
+ context, notificationChannels, safetyCenterResourcesApk),
dataManager);
}
@@ -137,7 +135,7 @@ public final class SafetyCenterNotificationSender {
* <p>The given {@link SafetyEvent} have type {@link
* SafetyEvent#SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} and include issue and action IDs
* that correspond to a {@link SafetySourceIssue} for which a notification is currently
- * displayed. Otherwise this method has no effect.
+ * displayed. Otherwise, this method has no effect.
*
* @param sourceId of the source which reported the issue
* @param safetyEvent the source provided upon successful action resolution
@@ -145,6 +143,12 @@ public final class SafetyCenterNotificationSender {
*/
public void notifyActionSuccess(
String sourceId, SafetyEvent safetyEvent, @UserIdInt int userId) {
+ if (!SafetyCenterFlags.getNotificationsEnabled()) {
+ // TODO(b/284271124): Decide what to do with existing notifications if flag gets
+ // toggled.
+ return;
+ }
+
if (safetyEvent.getType() != SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED) {
Log.w(TAG, "Received safety event of wrong type");
return;
@@ -174,12 +178,8 @@ public final class SafetyCenterNotificationSender {
return;
}
- SafetySourceIssue.Action successfulAction = null;
- for (int i = 0; i < notifiedIssue.getActions().size(); i++) {
- if (notifiedIssue.getActions().get(i).getId().equals(sourceIssueActionId)) {
- successfulAction = notifiedIssue.getActions().get(i);
- }
- }
+ SafetySourceIssue.Action successfulAction =
+ SafetySourceIssues.findAction(notifiedIssue, sourceIssueActionId);
if (successfulAction == null) {
Log.w(TAG, "Successful action not found");
return;
@@ -224,6 +224,7 @@ public final class SafetyCenterNotificationSender {
*/
public void updateNotifications(@UserIdInt int userId) {
if (!SafetyCenterFlags.getNotificationsEnabled()) {
+ // TODO(b/284271124): Decide what to do with existing notifications
return;
}
@@ -286,7 +287,7 @@ public final class SafetyCenterNotificationSender {
fout.println();
}
- /** Get all of the key-issue pairs for which notifications should be posted or updated now. */
+ /** Gets all the key-issue pairs for which notifications should be posted or updated now. */
private ArrayMap<SafetyCenterIssueKey, SafetySourceIssue> getIssuesToNotify(
@UserIdInt int userId) {
ArrayMap<SafetyCenterIssueKey, SafetySourceIssue> result = new ArrayMap<>();
@@ -325,14 +326,20 @@ public final class SafetyCenterNotificationSender {
@NotificationBehaviorInternal
private int getBehavior(SafetySourceIssue issue, SafetyCenterIssueKey issueKey) {
if (SdkLevel.isAtLeastU()) {
- switch (issue.getNotificationBehavior()) {
+ int notificationBehavior = issue.getNotificationBehavior();
+ switch (notificationBehavior) {
case SafetySourceIssue.NOTIFICATION_BEHAVIOR_NEVER:
return NOTIFICATION_BEHAVIOR_INTERNAL_NEVER;
case SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED:
return NOTIFICATION_BEHAVIOR_INTERNAL_DELAYED;
case SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY:
return NOTIFICATION_BEHAVIOR_INTERNAL_IMMEDIATELY;
+ case SafetySourceIssue.NOTIFICATION_BEHAVIOR_UNSPECIFIED:
+ return getBehaviorForIssueWithUnspecifiedBehavior(issue, issueKey);
}
+ Log.w(
+ TAG,
+ "Unexpected SafetySourceIssue.NotificationBehavior: " + notificationBehavior);
}
// On Android T all issues are assumed to have "unspecified" behavior
return getBehaviorForIssueWithUnspecifiedBehavior(issue, issueKey);
diff --git a/service/java/com/android/safetycenter/notifications/package-info.java b/service/java/com/android/safetycenter/notifications/package-info.java
index 85b487b30..83d886fe1 100644
--- a/service/java/com/android/safetycenter/notifications/package-info.java
+++ b/service/java/com/android/safetycenter/notifications/package-info.java
@@ -14,6 +14,11 @@
* limitations under the License.
*/
@NonNullByDefault
+@RequiresApi(TIRAMISU)
package com.android.safetycenter.notifications;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import android.annotation.RequiresApi;
+
import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/service/java/com/android/safetycenter/package-info.java b/service/java/com/android/safetycenter/package-info.java
index 0bccf89fa..57142c658 100644
--- a/service/java/com/android/safetycenter/package-info.java
+++ b/service/java/com/android/safetycenter/package-info.java
@@ -14,6 +14,11 @@
* limitations under the License.
*/
@NonNullByDefault
+@RequiresApi(TIRAMISU)
package com.android.safetycenter;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import android.annotation.RequiresApi;
+
import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/service/lint-baseline.xml b/service/lint-baseline.xml
index 90ea8d411..226175e91 100644
--- a/service/lint-baseline.xml
+++ b/service/lint-baseline.xml
@@ -1,15 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.os.UserHandle#getUid`"
- errorLine1=" return UserHandle.of(userId).getUid(appId);"
- errorLine2=" ~~~~~~">
+ message="Call requires API level 34 (current min is 33): `getDeduplicationGroup`"
+ errorLine1=" String deduplicationGroup = issueInfo.getSafetySource().getDeduplicationGroup();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Permission/service/java/com/android/permission/compat/UserHandleCompat.java"
- line="57"
- column="38"/>
+ file="packages/modules/Permission/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java"
+ line="316"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 34 (current min is 33): `getDeduplicationId`"
+ errorLine1=" String deduplicationId = issueInfo.getSafetySourceIssue().getDeduplicationId();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java"
+ line="317"
+ column="67"/>
</issue>
<issue
@@ -19,8 +30,19 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="packages/modules/Permission/service/java/com/android/safetycenter/SafetyCenterService.java"
- line="660"
+ line="732"
column="40"/>
</issue>
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.os.UserHandle#getUid`"
+ errorLine1=" return UserHandle.of(userId).getUid(appId);"
+ errorLine2=" ~~~~~~">
+ <location
+ file="packages/modules/Permission/service/java/com/android/permission/compat/UserHandleCompat.java"
+ line="57"
+ column="38"/>
+ </issue>
+
</issues> \ No newline at end of file
diff --git a/service/proguard.flags b/service/proguard.flags
new file mode 100644
index 000000000..a504239a1
--- /dev/null
+++ b/service/proguard.flags
@@ -0,0 +1,4 @@
+# Keep classes that implements RoleBehavior, which are used by reflection.
+-keep class * implements com.android.role.controller.model.RoleBehavior {
+ *;
+} \ No newline at end of file
diff --git a/service/proto/role_service.proto b/service/proto/role_service.proto
index 79c422992..f982ead5b 100644
--- a/service/proto/role_service.proto
+++ b/service/proto/role_service.proto
@@ -53,4 +53,7 @@ message RoleProto {
// The package names of the holders of this role.
repeated string holders = 2;
+
+ // Whether fallback holders are enabled for this role.
+ optional bool fallback_enabled = 3;
}
diff --git a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
index d90ffade9..6500b3926 100644
--- a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
+++ b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
@@ -20,7 +20,6 @@ import android.content.ApexEnvironment
import android.content.Context
import android.os.Process
import android.os.UserHandle
-import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.google.common.truth.Truth.assertThat
@@ -29,6 +28,7 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
@@ -37,27 +37,36 @@ import org.mockito.MockitoAnnotations.initMocks
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-@RunWith(AndroidJUnit4::class)
+@RunWith(Parameterized::class)
class RolesPersistenceTest {
private val context = InstrumentationRegistry.getInstrumentation().context
private lateinit var mockDataDirectory: File
-
private lateinit var mockitoSession: MockitoSession
@Mock lateinit var apexEnvironment: ApexEnvironment
+ @Parameterized.Parameter(0) lateinit var stateVersion: StateVersion
+ private lateinit var state: RolesState
private val persistence = RolesPersistenceImpl {}
- private val state = RolesState(1, "packagesHash", mapOf("role" to setOf("holder1", "holder2")))
+ private val defaultRoles = mapOf(ROLE_NAME to setOf(HOLDER_1, HOLDER_2))
+ private val stateVersionUndefined = RolesState(VERSION_UNDEFINED, PACKAGE_HASH, defaultRoles)
+ private val stateVersionFallbackMigrated =
+ RolesState(VERSION_FALLBACK_MIGRATED, PACKAGE_HASH, defaultRoles, setOf(ROLE_NAME))
private val user = Process.myUserHandle()
@Before
- fun createMockDataDirectory() {
+ fun setUp() {
+ createMockDataDirectory()
+ mockApexEnvironment()
+ state = getState()
+ }
+
+ private fun createMockDataDirectory() {
mockDataDirectory = context.getDir("mock_data", Context.MODE_PRIVATE)
mockDataDirectory.listFiles()!!.forEach { assertThat(it.deleteRecursively()).isTrue() }
}
- @Before
- fun mockApexEnvironment() {
+ private fun mockApexEnvironment() {
initMocks(this)
mockitoSession =
mockitoSession()
@@ -80,7 +89,7 @@ class RolesPersistenceTest {
persistence.writeForUser(state, user)
val persistedState = persistence.readForUser(user)
- checkPersistedState(persistedState)
+ assertThat(persistedState).isEqualTo(state)
}
@Test
@@ -91,7 +100,7 @@ class RolesPersistenceTest {
.writeText("<roles version=\"-1\"><role name=\"com.foo.bar\"><holder")
val persistedState = persistence.readForUser(user)
- checkPersistedState(persistedState)
+ assertThat(persistedState).isEqualTo(state)
}
@Test
@@ -103,14 +112,28 @@ class RolesPersistenceTest {
assertThat(persistedState).isNull()
}
- private fun checkPersistedState(persistedState: RolesState?) {
- assertThat(persistedState).isEqualTo(state)
- assertThat(persistedState?.version).isEqualTo(state.version)
- assertThat(persistedState?.packagesHash).isEqualTo(state.packagesHash)
- assertThat(persistedState?.roles).isEqualTo(state.roles)
+ private fun getState(): RolesState =
+ when (stateVersion) {
+ StateVersion.VERSION_UNDEFINED -> stateVersionUndefined
+ StateVersion.VERSION_FALLBACK_MIGRATED -> stateVersionFallbackMigrated
+ }
+
+ enum class StateVersion {
+ VERSION_UNDEFINED,
+ VERSION_FALLBACK_MIGRATED
}
companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun data(): Array<StateVersion> = StateVersion.values()
+
+ private const val VERSION_UNDEFINED = -1
+ private const val VERSION_FALLBACK_MIGRATED = 1
private const val APEX_MODULE_NAME = "com.android.permission"
+ private const val PACKAGE_HASH = "packagesHash"
+ private const val ROLE_NAME = "roleName"
+ private const val HOLDER_1 = "holder1"
+ private const val HOLDER_2 = "holder2"
}
}
diff --git a/tests/cts/permission/Android.bp b/tests/cts/permission/Android.bp
new file mode 100644
index 000000000..ed7fcea25
--- /dev/null
+++ b/tests/cts/permission/Android.bp
@@ -0,0 +1,130 @@
+//
+// Copyright (C) 2008 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsPermissionTestCases",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ "mcts-permission",
+ ],
+ // Include both the 32 and 64 bit versions
+ compile_multilib: "both",
+ static_libs: [
+ "ctstestrunner-axt",
+ "guava",
+ "android-ex-camera2",
+ "compatibility-device-util-axt",
+ "truth",
+ "androidx.annotation_annotation",
+ "platformprotosnano",
+ "permission-test-util-lib",
+ "nativetesthelper",
+ // TODO(b/175251166): remove once Android migrates to JUnit 4.12,
+ // which provides assertThrows
+ "testng",
+ "bluetooth-test-util-lib",
+ "CtsAccessibilityCommon",
+ "safety-center-internal-data",
+ "sts-device-util",
+ "platform-test-rules",
+ "CtsVirtualDeviceCommonLib",
+ "android.permission.flags-aconfig-java",
+ "androidx.test.rules",
+ ],
+ jni_libs: [
+ "libctspermission_jni",
+ "libpermissionmanager_native_test",
+ "libnativehelper_compat_libc++",
+ ],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.aidl",
+ "src/**/*.kt",
+ ],
+ sdk_version: "test_current",
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ data: [
+ ":AppThatDefinesUndefinedPermissionGroupElement",
+ ":AppThatDoesNotHaveBgLocationAccess",
+ ":CtsAdversarialPermissionDefinerApp",
+ ":CtsAdversarialPermissionUserApp",
+ ":CtsAppThatAccessesLocationOnCommand",
+ ":CtsAppThatAlsoDefinesPermissionA",
+ ":CtsAppThatAlsoDefinesPermissionADifferentCert",
+ ":CtsAppThatAlsoDefinesPermissionGroupADifferentCert",
+ ":CtsAppThatAlsoDefinesPermissionGroupADifferentCert30",
+ ":CtsAppThatDefinesPermissionA",
+ ":CtsAppThatDefinesPermissionInPlatformGroup",
+ ":CtsAppThatDefinesPermissionWithInvalidGroup",
+ ":CtsAppThatDefinesPermissionWithInvalidGroup30",
+ ":CtsAppThatHasNotificationListener",
+ ":CtsAppThatRequestsBluetoothPermission30",
+ ":CtsAppThatRequestsCalendarContactsBodySensorCustomPermission",
+ ":CtsAppThatRequestsBluetoothPermission31",
+ ":CtsAppThatRequestsBluetoothPermissionNeverForLocation31",
+ ":CtsAppThatRequestsContactsAndCallLogPermission16",
+ ":CtsAppThatRequestsContactsPermission15",
+ ":CtsAppThatRequestsContactsPermission16",
+ ":CtsAppThatRequestsLocationAndBackgroundPermission28",
+ ":CtsAppThatRequestsLocationAndBackgroundPermission29",
+ ":CtsAppThatRequestsBluetoothPermissionNeverForLocationNoProvider",
+ ":CtsAppThatRequestsLocationPermission22",
+ ":CtsAppThatRequestsLocationPermission28",
+ ":CtsAppThatRequestsLocationPermission29",
+ ":CtsAppThatRequestsLocationPermission29v4",
+ ":CtsAppThatRequestsOneTimePermission",
+ ":CtsAppThatRequestsPermissionAandB",
+ ":CtsAppThatRequestsPermissionAandC",
+ ":CtsAppThatRequestsStoragePermission28",
+ ":CtsAppThatRequestsStoragePermission29",
+ ":CtsAppThatRunsRationaleTests",
+ ":CtsAppToTestRevokeSelfPermission",
+ ":CtsAppWithSharedUidThatRequestsLocationPermission28",
+ ":CtsAppWithSharedUidThatRequestsLocationPermission29",
+ ":CtsAppWithSharedUidThatRequestsNoPermissions",
+ ":CtsAppWithSharedUidThatRequestsPermissions",
+ ":CtsInstallPermissionDefinerApp",
+ ":CtsInstallPermissionEscalatorApp",
+ ":CtsInstallPermissionUserApp",
+ ":CtsRuntimePermissionDefinerApp",
+ ":CtsRuntimePermissionUserApp",
+ ":CtsStorageEscalationApp28",
+ ":CtsStorageEscalationApp29Full",
+ ":CtsStorageEscalationApp29Scoped",
+ ":CtsVictimPermissionDefinerApp",
+ ":CtsAppThatRequestsMultiplePermissionsWithMinMaxSdk",
+ ":CtsAppThatRequestsSystemAlertWindow22",
+ ":CtsAppThatRequestsSystemAlertWindow23",
+ ":CtsAppThatRequestCustomCameraPermission",
+ ":CtsAppThatRequestsDevicePermissions",
+ ],
+ per_testcase_directory: true,
+}
diff --git a/tests/cts/permission/AndroidManifest.xml b/tests/cts/permission/AndroidManifest.xml
new file mode 100644
index 000000000..43fd97bb2
--- /dev/null
+++ b/tests/cts/permission/AndroidManifest.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts"
+ android:targetSandboxVersion="2">
+
+ <!-- for android.permission.cts.PermissionGroupChange -->
+ <permission android:name="android.permission.cts.B"
+ android:protectionLevel="dangerous"
+ android:label="@string/perm_b"
+ android:permissionGroup="android.permission.cts.groupB"
+ android:description="@string/perm_b"/>
+
+ <!-- for android.permission.cts.PermissionGroupChange -->
+ <permission android:name="android.permission.cts.C"
+ android:protectionLevel="dangerous"
+ android:label="@string/perm_c"
+ android:permissionGroup="android.permission.cts.groupC"
+ android:description="@string/perm_c"/>
+
+ <!-- for android.permission.cts.LocationAccessCheckTest -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
+
+ <!-- for android.permission.cts.NearbyDevicesRenouncePermissionTest -->
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
+
+ <!-- for android.permission.cts.PermissionGroupChange -->
+ <permission-group android:description="@string/perm_group_b"
+ android:label="@string/perm_group_b"
+ android:name="android.permission.cts.groupB"/>
+
+ <!-- for android.permission.cts.PermissionGroupChange -->
+ <permission-group android:description="@string/perm_group_c"
+ android:label="@string/perm_group_c"
+ android:name="android.permission.cts.groupC"/>
+
+ <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="android.permission.cts.PermissionStubActivity"
+ android:label="PermissionStubActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+ </intent-filter>
+ </activity>
+
+ <service android:name="android.permission.cts.CtsNotificationListenerService"
+ android:exported="true"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService"/>
+ </intent-filter>
+ </service>
+ <service android:name=".AccessibilityTestService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/test_accessibilityservice"/>
+ </service>
+ </application>
+
+ <!--
+ The CTS stubs package cannot be used as the target application here,
+ since that requires many permissions to be set. Instead, specify this
+ package itself as the target and include any stub activities needed.
+
+ This test package uses the default InstrumentationTestRunner, because
+ the InstrumentationCtsTestRunner is only available in the stubs
+ package. That runner cannot be added to this package either, since it
+ relies on hidden APIs.
+ -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.permission.cts"
+ android:label="CTS tests of android.permission">
+ </instrumentation>
+
+</manifest>
diff --git a/tests/cts/permission/AndroidTest.xml b/tests/cts/permission/AndroidTest.xml
new file mode 100644
index 000000000..de9504dc7
--- /dev/null
+++ b/tests/cts/permission/AndroidTest.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Permission test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
+ <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" />
+ <option name="config-descriptor:metadata" key="parameter" value="run_on_sdk_sandbox" />
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+
+ <!-- Keep screen on for Bluetooth scanning -->
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ <option name="screen-always-on" value="on" />
+ <option name="disable-device-config-sync" value="true" />
+ </target_preparer>
+
+ <!-- Install main test suite apk -->
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPermissionTestCases.apk" />
+ </target_preparer>
+
+ <!-- Create place to store apks -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/cts-permission" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/cts-permission"/>
+ </target_preparer>
+
+ <!-- Collect screen recordings -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/user/0/android.permission.cts/files" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+
+ <!-- Load additional APKs onto device -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="CtsAppThatRequestsPermissionAandB.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsPermissionAandB.apk" />
+ <option name="push" value="CtsAppThatRequestsPermissionAandC.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsPermissionAandC.apk" />
+ <option name="push" value="CtsAppThatRequestsBluetoothPermission30.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsBluetoothPermission30.apk" />
+ <option name="push" value="CtsAppThatRequestsBluetoothPermission31.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsBluetoothPermission31.apk" />
+ <option name="push" value="CtsAppThatRequestsBluetoothPermissionNeverForLocation31.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsBluetoothPermissionNeverForLocation31.apk" />
+ <option name="push" value="CtsAppThatRequestsBluetoothPermissionNeverForLocationNoProvider.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsBluetoothPermissionNeverForLocationNoProvider.apk" />
+ <option name="push" value="CtsAppThatRequestsContactsPermission16.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsContactsPermission16.apk" />
+ <option name="push" value="CtsAppThatRequestsContactsPermission15.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsContactsPermission15.apk" />
+ <option name="push" value="CtsAppThatRequestsContactsAndCallLogPermission16.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsContactsAndCallLogPermission16.apk" />
+ <option name="push" value="CtsAppThatRequestsLocationPermission29.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsLocationPermission29.apk" />
+ <option name="push" value="CtsAppThatRequestsLocationPermission29v4.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsLocationPermission29v4.apk" />
+ <option name="push" value="CtsAppThatRequestsLocationPermission28.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsLocationPermission28.apk" />
+ <option name="push" value="CtsAppThatRequestsLocationPermission22.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsLocationPermission22.apk" />
+ <option name="push" value="CtsAppThatRequestsStoragePermission29.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsStoragePermission29.apk" />
+ <option name="push" value="CtsAppThatRequestsStoragePermission28.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsStoragePermission28.apk" />
+ <option name="push" value="CtsAppThatRequestsLocationAndBackgroundPermission28.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsLocationAndBackgroundPermission28.apk" />
+ <option name="push" value="CtsAppThatRequestsLocationAndBackgroundPermission29.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsLocationAndBackgroundPermission29.apk" />
+ <option name="push" value="CtsAppThatAccessesLocationOnCommand.apk->/data/local/tmp/cts-permission/CtsAppThatAccessesLocationOnCommand.apk" />
+ <option name="push" value="AppThatDoesNotHaveBgLocationAccess.apk->/data/local/tmp/cts-permission/AppThatDoesNotHaveBgLocationAccess.apk" />
+ <option name="push" value="CtsAppWithSharedUidThatRequestsPermissions.apk->/data/local/tmp/cts-permission/CtsAppWithSharedUidThatRequestsPermissions.apk" />
+ <option name="push" value="CtsAppWithSharedUidThatRequestsNoPermissions.apk->/data/local/tmp/cts-permission/CtsAppWithSharedUidThatRequestsNoPermissions.apk" />
+ <option name="push" value="CtsAppWithSharedUidThatRequestsLocationPermission28.apk->/data/local/tmp/cts-permission/CtsAppWithSharedUidThatRequestsLocationPermission28.apk" />
+ <option name="push" value="CtsAppWithSharedUidThatRequestsLocationPermission29.apk->/data/local/tmp/cts-permission/CtsAppWithSharedUidThatRequestsLocationPermission29.apk" />
+ <option name="push" value="CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk" />
+ <option name="push" value="CtsAppThatRunsRationaleTests.apk->/data/local/tmp/cts-permission/CtsAppThatRunsRationaleTests.apk" />
+ <option name="push" value="CtsAdversarialPermissionUserApp.apk->/data/local/tmp/cts-permission/CtsAdversarialPermissionUserApp.apk" />
+ <option name="push" value="CtsAdversarialPermissionDefinerApp.apk->/data/local/tmp/cts-permission/CtsAdversarialPermissionDefinerApp.apk" />
+ <option name="push" value="CtsVictimPermissionDefinerApp.apk->/data/local/tmp/cts-permission/CtsVictimPermissionDefinerApp.apk" />
+ <option name="push" value="CtsRuntimePermissionDefinerApp.apk->/data/local/tmp/cts-permission/CtsRuntimePermissionDefinerApp.apk" />
+ <option name="push" value="CtsRuntimePermissionUserApp.apk->/data/local/tmp/cts-permission/CtsRuntimePermissionUserApp.apk" />
+ <option name="push" value="CtsInstallPermissionDefinerApp.apk->/data/local/tmp/cts-permission/CtsInstallPermissionDefinerApp.apk" />
+ <option name="push" value="CtsInstallPermissionUserApp.apk->/data/local/tmp/cts-permission/CtsInstallPermissionUserApp.apk" />
+ <option name="push" value="CtsInstallPermissionEscalatorApp.apk->/data/local/tmp/cts-permission/CtsInstallPermissionEscalatorApp.apk" />
+ <option name="push" value="CtsAppThatRequestsOneTimePermission.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsOneTimePermission.apk" />
+ <option name="push" value="CtsAppToTestRevokeSelfPermission.apk->/data/local/tmp/cts-permission/CtsAppToTestRevokeSelfPermission.apk" />
+ <option name="push" value="AppThatDefinesUndefinedPermissionGroupElement.apk->/data/local/tmp/cts-permission/AppThatDefinesUndefinedPermissionGroupElement.apk" />
+ <option name="push" value="CtsAppThatDefinesPermissionA.apk->/data/local/tmp/cts-permission/CtsAppThatDefinesPermissionA.apk" />
+ <option name="push" value="CtsAppThatAlsoDefinesPermissionA.apk->/data/local/tmp/cts-permission/CtsAppThatAlsoDefinesPermissionA.apk" />
+ <option name="push" value="CtsAppThatAlsoDefinesPermissionADifferentCert.apk->/data/local/tmp/cts-permission/CtsAppThatAlsoDefinesPermissionADifferentCert.apk" />
+ <option name="push" value="CtsAppThatAlsoDefinesPermissionGroupADifferentCert.apk->/data/local/tmp/cts-permission/CtsAppThatAlsoDefinesPermissionGroupADifferentCert.apk" />
+ <option name="push" value="CtsAppThatDefinesPermissionInPlatformGroup.apk->/data/local/tmp/cts-permission/CtsAppThatDefinesPermissionInPlatformGroup.apk" />
+ <option name="push" value="CtsAppThatAlsoDefinesPermissionGroupADifferentCert30.apk->/data/local/tmp/cts-permission/CtsAppThatAlsoDefinesPermissionGroupADifferentCert30.apk" />
+ <option name="push" value="CtsAppThatDefinesPermissionWithInvalidGroup.apk->/data/local/tmp/cts-permission/CtsAppThatDefinesPermissionWithInvalidGroup.apk" />
+ <option name="push" value="CtsAppThatDefinesPermissionWithInvalidGroup30.apk->/data/local/tmp/cts-permission/CtsAppThatDefinesPermissionWithInvalidGroup30.apk" />
+ <option name="push" value="CtsStorageEscalationApp28.apk->/data/local/tmp/cts-permission/CtsStorageEscalationApp28.apk" />
+ <option name="push" value="CtsStorageEscalationApp29Full.apk->/data/local/tmp/cts-permission/CtsStorageEscalationApp29Full.apk" />
+ <option name="push" value="CtsStorageEscalationApp29Scoped.apk->/data/local/tmp/cts-permission/CtsStorageEscalationApp29Scoped.apk" />
+ <option name="push" value="CtsAppThatHasNotificationListener.apk->/data/local/tmp/cts-permission/CtsAppThatHasNotificationListener.apk" />
+ <option name="push" value="CtsAppThatRequestsMultiplePermissionsWithMinMaxSdk.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsMultiplePermissionsWithMinMaxSdk.apk" />
+ <option name="push" value="CtsAppThatRequestsSystemAlertWindow22.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsSystemAlertWindow22.apk" />
+ <option name="push" value="CtsAppThatRequestsSystemAlertWindow23.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsSystemAlertWindow23.apk" />
+ <option name="push" value="CtsAppThatRequestCustomCameraPermission.apk->/data/local/tmp/cts-permission/CtsAppThatRequestCustomCameraPermission.apk" />
+ <option name="push" value="CtsAppThatRequestsDevicePermissions.apk->/data/local/tmp/cts-permission/CtsAppThatRequestsDevicePermissions.apk" />
+ </target_preparer>
+
+ <!-- Remove additional apps if installed -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <!-- disable DeprecatedAbi warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_abi_dialog 1" />
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.appthatrequestpermission" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.appthatrequestnopermission" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.AdversarialPermissionDefinerApp" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.VictimPermissionDefinerApp" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.userapp" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.runtimepermissiondefinerapp" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.runtimepermissionuserapp" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.appthathasnotificationlistener" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.permission.cts" />
+ <option name="runtime-hint" value="13m" />
+ </test>
+
+ <system_checker class="com.android.tradefed.suite.checker.UserChecker" >
+ <option name="user-cleanup" value="true" />
+ </system_checker>
+</configuration>
diff --git a/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp b/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp
new file mode 100644
index 000000000..fdb0be452
--- /dev/null
+++ b/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsCalendarContactsBodySensorCustomPermission",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ sdk_version: "current",
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml b/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml
new file mode 100644
index 000000000..ece3ba1c7
--- /dev/null
+++ b/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestcustompermission"
+ android:versionCode="1">
+
+ <permission-group
+ android:name="android.permission.cts.appthatrequestcustompermission.TEST_GROUP"
+ android:label="test permission group"
+ android:protectionLevel="dangerous" />
+
+ <permission
+ android:name="android.permission.cts.appthatrequestcustompermission.TEST_PERMISSION"
+ android:label="test permission"
+ android:permissionGroup="android.permission.cts.appthatrequestcustompermission.TEST_GROUP"
+ android:protectionLevel="dangerous" />
+
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.BODY_SENSORS" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.cts.appthatrequestcustompermission.TEST_PERMISSION" />
+
+ <application />
+</manifest>
diff --git a/tests/cts/permission/AppThatAccessesLocationOnCommand/Android.bp b/tests/cts/permission/AppThatAccessesLocationOnCommand/Android.bp
new file mode 100644
index 000000000..2bb3dd3ab
--- /dev/null
+++ b/tests/cts/permission/AppThatAccessesLocationOnCommand/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatAccessesLocationOnCommand",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ sdk_version: "current",
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.aidl"
+ ],
+}
diff --git a/tests/cts/permission/AppThatAccessesLocationOnCommand/AndroidManifest.xml b/tests/cts/permission/AppThatAccessesLocationOnCommand/AndroidManifest.xml
new file mode 100644
index 000000000..93836d389
--- /dev/null
+++ b/tests/cts/permission/AppThatAccessesLocationOnCommand/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthataccesseslocation">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
+
+ <application android:label="CtsLocationAccess" android:debuggable="true">
+ <service android:name=".AccessLocationOnCommand"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/AccessLocationOnCommand.java b/tests/cts/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/AccessLocationOnCommand.java
new file mode 100644
index 000000000..75f4a0ce5
--- /dev/null
+++ b/tests/cts/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/AccessLocationOnCommand.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthataccesseslocation;
+
+import static android.location.Criteria.ACCURACY_FINE;
+
+import android.app.Service;
+import android.content.Intent;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+
+public class AccessLocationOnCommand extends Service {
+ private IAccessLocationOnCommand.Stub mBinder = new IAccessLocationOnCommand.Stub() {
+ public void accessLocation() {
+ Criteria crit = new Criteria();
+ crit.setAccuracy(ACCURACY_FINE);
+
+ AccessLocationOnCommand.this.getSystemService(LocationManager.class)
+ .requestSingleUpdate(crit, new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status,
+ Bundle extras) {
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ }
+ }, Looper.getMainLooper());
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ return true;
+ }
+}
diff --git a/tests/cts/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/IAccessLocationOnCommand.aidl b/tests/cts/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/IAccessLocationOnCommand.aidl
new file mode 100644
index 000000000..be92ed160
--- /dev/null
+++ b/tests/cts/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/IAccessLocationOnCommand.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthataccesseslocation;
+
+interface IAccessLocationOnCommand {
+ /** Access location on command */
+ void accessLocation();
+} \ No newline at end of file
diff --git a/tests/cts/permission/AppThatAlsoDefinesPermissionA/Android.bp b/tests/cts/permission/AppThatAlsoDefinesPermissionA/Android.bp
new file mode 100644
index 000000000..46b7aecd3
--- /dev/null
+++ b/tests/cts/permission/AppThatAlsoDefinesPermissionA/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatAlsoDefinesPermissionA",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ certificate: ":cts-testkey1",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatAlsoDefinesPermissionA/AndroidManifest.xml b/tests/cts/permission/AppThatAlsoDefinesPermissionA/AndroidManifest.xml
new file mode 100644
index 000000000..2a803017b
--- /dev/null
+++ b/tests/cts/permission/AppThatAlsoDefinesPermissionA/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatalsodefinespermissiona">
+
+ <permission android:name="com.android.cts.duplicatepermission.permA"
+ android:permissionGroup="com.android.cts.duplicatepermission.groupA"/>
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatAlsoDefinesPermissionADifferentCert/Android.bp b/tests/cts/permission/AppThatAlsoDefinesPermissionADifferentCert/Android.bp
new file mode 100644
index 000000000..c88d0f7fe
--- /dev/null
+++ b/tests/cts/permission/AppThatAlsoDefinesPermissionADifferentCert/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatAlsoDefinesPermissionADifferentCert",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ certificate: ":cts-testkey2",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatAlsoDefinesPermissionADifferentCert/AndroidManifest.xml b/tests/cts/permission/AppThatAlsoDefinesPermissionADifferentCert/AndroidManifest.xml
new file mode 100644
index 000000000..d333bf6df
--- /dev/null
+++ b/tests/cts/permission/AppThatAlsoDefinesPermissionADifferentCert/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatdefinespermissiona.differentcert">
+
+ <permission android:name="com.android.cts.duplicatepermission.permA"/>
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/Android.bp b/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/Android.bp
new file mode 100644
index 000000000..b1ef695ac
--- /dev/null
+++ b/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatAlsoDefinesPermissionGroupADifferentCert",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ certificate: ":cts-testkey2",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/AndroidManifest.xml b/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/AndroidManifest.xml
new file mode 100644
index 000000000..59cd518c1
--- /dev/null
+++ b/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatdefinespermissiongroupa.differentcert">
+
+ <permission-group android:name="com.android.cts.duplicatepermission.groupA"
+ android:label="groupA"/>
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/Android.bp b/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/Android.bp
new file mode 100644
index 000000000..52900dfc3
--- /dev/null
+++ b/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatAlsoDefinesPermissionGroupADifferentCert30",
+ defaults: ["cts_defaults"],
+ sdk_version: "30",
+ certificate: ":cts-testkey2",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/AndroidManifest.xml b/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/AndroidManifest.xml
new file mode 100644
index 000000000..43ed9db58
--- /dev/null
+++ b/tests/cts/permission/AppThatAlsoDefinesPermissionGroupADifferentCert30/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatdefinespermissiongroupa.differentcert30">
+
+ <permission-group android:name="com.android.cts.duplicatepermission.groupA"
+ android:label="groupA"/>
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatDefinesPermissionA/Android.bp b/tests/cts/permission/AppThatDefinesPermissionA/Android.bp
new file mode 100644
index 000000000..54a575b4f
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesPermissionA/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatDefinesPermissionA",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ certificate: ":cts-testkey1",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatDefinesPermissionA/AndroidManifest.xml b/tests/cts/permission/AppThatDefinesPermissionA/AndroidManifest.xml
new file mode 100644
index 000000000..527618c7d
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesPermissionA/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatdefinespermissiona">
+ <permission-group android:name="com.android.cts.duplicatepermission.groupA"
+ android:label="groupA"/>
+
+ <permission android:name="com.android.cts.duplicatepermission.permA"
+ android:permissionGroup="com.android.cts.duplicatepermission.groupA"/>
+
+ <application/>
+</manifest>
+
diff --git a/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup/Android.bp b/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup/Android.bp
new file mode 100644
index 000000000..9029b3a98
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatDefinesPermissionWithInvalidGroup",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup/AndroidManifest.xml b/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup/AndroidManifest.xml
new file mode 100644
index 000000000..8abd4cc4a
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatdefinespermissionwithinvalidgroup">
+
+ <permission android:name="com.android.cts.duplicatepermission.permA"
+ android:permissionGroup="com.android.cts.duplicatepermission.invalid"/>
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup30/Android.bp b/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup30/Android.bp
new file mode 100644
index 000000000..04961e265
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup30/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatDefinesPermissionWithInvalidGroup30",
+ defaults: ["cts_defaults"],
+ sdk_version: "30",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup30/AndroidManifest.xml b/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup30/AndroidManifest.xml
new file mode 100644
index 000000000..2fc662c27
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesPermissionWithInvalidGroup30/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatdefinespermissionwithinvalidgroup30">
+
+ <permission android:name="com.android.cts.duplicatepermission.permA"
+ android:permissionGroup="com.android.cts.duplicatepermission.invalid"/>
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatDefinesPermissionWithPlatformGroup/Android.bp b/tests/cts/permission/AppThatDefinesPermissionWithPlatformGroup/Android.bp
new file mode 100644
index 000000000..687ad7488
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesPermissionWithPlatformGroup/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatDefinesPermissionInPlatformGroup",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatDefinesPermissionWithPlatformGroup/AndroidManifest.xml b/tests/cts/permission/AppThatDefinesPermissionWithPlatformGroup/AndroidManifest.xml
new file mode 100644
index 000000000..d4709eb9b
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesPermissionWithPlatformGroup/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatdefinespermissioninplatformgroup">
+
+ <permission android:name="com.android.cts.duplicatepermission.permA"
+ android:permissionGroup="android.permission-group.CAMERA"/>
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp b/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp
new file mode 100644
index 000000000..c00d26d3a
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "AppThatDefinesUndefinedPermissionGroupElement",
+ defaults: ["cts_defaults"],
+ sdk_version: "test_current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+ srcs: ["src/**/*.kt"],
+}
diff --git a/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/AndroidManifest.xml b/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/AndroidManifest.xml
new file mode 100644
index 000000000..ab2ef79b2
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="2">
+
+ <permission
+ android:name="android.permission.cts.appthatrequestpermission.TEST"
+ android:protectionLevel="dangerous"
+ android:permissionGroup="android.permission-group.UNDEFINED" />
+
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.cts.appthatrequestpermission.TEST" />
+
+ <application android:label="CtsPermissionUnknownGroup">
+ <activity
+ android:name=".RequestPermissions"
+ android:exported="true"
+ android:visibleToInstantApps="true"/>
+ </application>
+</manifest>
+
diff --git a/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/src/android/permission/cts/appthatrequestpermission/RequestPermissions.kt b/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/src/android/permission/cts/appthatrequestpermission/RequestPermissions.kt
new file mode 100644
index 000000000..bbf9066f2
--- /dev/null
+++ b/tests/cts/permission/AppThatDefinesUndefinedPermissionGroupElement/src/android/permission/cts/appthatrequestpermission/RequestPermissions.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permission.cts.appthatrequestpermission
+
+import android.app.Activity
+import android.os.Bundle
+import android.util.Log
+
+class RequestPermissions : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ Log.w(TAG, "Activity was recreated. (Perhaps due to a configuration change?)")
+ return
+ }
+
+ val permissions = intent.getStringArrayExtra(EXTRA_PERMISSIONS)!!
+ requestPermissions(permissions, 0)
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<String>,
+ grantResults: IntArray
+ ) {
+ finish()
+ }
+
+ companion object {
+ private const val EXTRA_PERMISSIONS =
+ "android.permission.cts.appthatrequestpermission.extra.PERMISSIONS"
+ private val TAG = RequestPermissions::class.simpleName
+ }
+}
diff --git a/tests/cts/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp b/tests/cts/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp
new file mode 100644
index 000000000..f9ff21c6f
--- /dev/null
+++ b/tests/cts/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "AppThatDoesNotHaveBgLocationAccess",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ sdk_version: "current",
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatDoesNotHaveBgLocationAccess/AndroidManifest.xml b/tests/cts/permission/AppThatDoesNotHaveBgLocationAccess/AndroidManifest.xml
new file mode 100644
index 000000000..8e883a4ad
--- /dev/null
+++ b/tests/cts/permission/AppThatDoesNotHaveBgLocationAccess/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthataccesseslocation">
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+ <application android:label="CtsLocationAccess" android:debuggable="true"/>
+</manifest>
+
diff --git a/tests/cts/permission/AppThatHasNotificationListener/Android.bp b/tests/cts/permission/AppThatHasNotificationListener/Android.bp
new file mode 100644
index 000000000..419ab5d66
--- /dev/null
+++ b/tests/cts/permission/AppThatHasNotificationListener/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatHasNotificationListener",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ sdk_version: "current",
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+}
diff --git a/tests/cts/permission/AppThatHasNotificationListener/AndroidManifest.xml b/tests/cts/permission/AppThatHasNotificationListener/AndroidManifest.xml
new file mode 100644
index 000000000..03d23dfb2
--- /dev/null
+++ b/tests/cts/permission/AppThatHasNotificationListener/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthathasnotificationlistener"
+ android:versionCode="1">
+
+ <application android:label="CtsNotificationListener">
+ <service
+ android:name=".CtsNotificationListenerService"
+ android:label="CtsNotificationListener"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService"/>
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatHasNotificationListener/src/android/permission/cts/appthathasnotificationlistener/CtsNotificationListenerService.java b/tests/cts/permission/AppThatHasNotificationListener/src/android/permission/cts/appthathasnotificationlistener/CtsNotificationListenerService.java
new file mode 100644
index 000000000..2bd423e1b
--- /dev/null
+++ b/tests/cts/permission/AppThatHasNotificationListener/src/android/permission/cts/appthathasnotificationlistener/CtsNotificationListenerService.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthathasnotificationlistener;
+
+import android.service.notification.NotificationListenerService;
+
+public class CtsNotificationListenerService extends NotificationListenerService {}
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermission30/Android.bp b/tests/cts/permission/AppThatRequestBluetoothPermission30/Android.bp
new file mode 100644
index 000000000..a3fe38109
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermission30/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "AppThatRequestBluetoothPermission",
+ srcs: [
+ "src/**/*.java",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsBluetoothPermission30",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ srcs: [":AppThatRequestBluetoothPermission"],
+}
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermission30/AndroidManifest.xml b/tests/cts/permission/AppThatRequestBluetoothPermission30/AndroidManifest.xml
new file mode 100644
index 000000000..d84e0d8f4
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermission30/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+
+ <application>
+ <provider
+ android:name=".AccessBluetoothOnCommand"
+ android:authorities="appthatrequestpermission"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermission30/src/android/permission/cts/appthatrequestpermission/AccessBluetoothOnCommand.java b/tests/cts/permission/AppThatRequestBluetoothPermission30/src/android/permission/cts/appthatrequestpermission/AccessBluetoothOnCommand.java
new file mode 100644
index 000000000..a27da0bdc
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermission30/src/android/permission/cts/appthatrequestpermission/AccessBluetoothOnCommand.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthatrequestpermission;
+
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanResult;
+import android.content.AttributionSource;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.ContextParams;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Base64;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class AccessBluetoothOnCommand extends ContentProvider {
+ private static final String TAG = "AccessBluetoothOnCommand";
+ private static final String DISAVOWAL_APP_PKG = "android.permission.cts.appneverforlocation";
+
+ private enum Result {
+ UNKNOWN, EXCEPTION, EMPTY, FILTERED, FULL
+ }
+
+ @Override
+ public Bundle call(String authority, String method, String arg, Bundle extras) {
+ final Bundle res = new Bundle();
+
+ BluetoothLeScanner scanner = null;
+ ScanCallback scanCallback = null;
+
+ try {
+ Context context = ("PROXY".equals(arg)) ? createProxyingContext() : getContext();
+ scanner = context.getSystemService(BluetoothManager.class)
+ .getAdapter().getBluetoothLeScanner();
+
+ final Set<String> observedScans = ConcurrentHashMap.newKeySet();
+ final AtomicInteger observedErrorCode = new AtomicInteger(0);
+
+ scanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ Log.v(TAG, "onScanResult() - result = " + result);
+ observedScans.add(Base64.encodeToString(result.getScanRecord().getBytes(), 0));
+ }
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ for (ScanResult result : results) {
+ onScanResult(0, result);
+ }
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ Log.v(TAG, "onScanFailed() - errorCode = " + errorCode);
+ observedErrorCode.set(errorCode);
+ }
+ };
+
+ scanner.startScan(scanCallback);
+
+ // Wait a few seconds to figure out what we actually observed
+ SystemClock.sleep(3000);
+
+ if (observedErrorCode.get() > 0) {
+ throw new RuntimeException("Scan returned error code: " + observedErrorCode.get());
+ }
+
+ switch (observedScans.size()) {
+ case 0:
+ res.putInt(Intent.EXTRA_INDEX, Result.EMPTY.ordinal());
+ break;
+ case 1:
+ res.putInt(Intent.EXTRA_INDEX, Result.FILTERED.ordinal());
+ break;
+ case 5:
+ res.putInt(Intent.EXTRA_INDEX, Result.FULL.ordinal());
+ break;
+ default:
+ res.putInt(Intent.EXTRA_INDEX, Result.UNKNOWN.ordinal());
+ break;
+ }
+ } catch (Throwable t) {
+ Log.v(TAG, "Failed to scan", t);
+ res.putInt(Intent.EXTRA_INDEX, Result.EXCEPTION.ordinal());
+ } finally {
+ try {
+ scanner.stopScan(scanCallback);
+ } catch (Exception e) {
+ }
+ }
+ return res;
+ }
+
+ private Context createProxyingContext() throws PackageManager.NameNotFoundException {
+ int disavowingAppUid =
+ getContext().getPackageManager().getPackageUid(DISAVOWAL_APP_PKG, 0);
+ AttributionSource attrib = new AttributionSource.Builder(disavowingAppUid)
+ .setPackageName(DISAVOWAL_APP_PKG)
+ .build();
+ return getContext().createContext(
+ new ContextParams.Builder().setNextAttributionSource(attrib).build());
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermission31/Android.bp b/tests/cts/permission/AppThatRequestBluetoothPermission31/Android.bp
new file mode 100644
index 000000000..7dc2e2445
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermission31/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsBluetoothPermission31",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ srcs: [":AppThatRequestBluetoothPermission"],
+}
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermission31/AndroidManifest.xml b/tests/cts/permission/AppThatRequestBluetoothPermission31/AndroidManifest.xml
new file mode 100644
index 000000000..70b381170
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermission31/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
+
+ <application>
+ <provider
+ android:name=".AccessBluetoothOnCommand"
+ android:authorities="appthatrequestpermission"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocation31/Android.bp b/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocation31/Android.bp
new file mode 100644
index 000000000..857f2e2f4
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocation31/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsBluetoothPermissionNeverForLocation31",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ srcs: [":AppThatRequestBluetoothPermission"],
+}
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocation31/AndroidManifest.xml b/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocation31/AndroidManifest.xml
new file mode 100644
index 000000000..446933d21
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocation31/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <uses-permission
+ android:name="android.permission.BLUETOOTH_ADVERTISE"
+ android:usesPermissionFlags="neverForLocation" />
+ <uses-permission
+ android:name="android.permission.BLUETOOTH_CONNECT"
+ android:usesPermissionFlags="neverForLocation" />
+ <uses-permission
+ android:name="android.permission.BLUETOOTH_SCAN"
+ android:usesPermissionFlags="neverForLocation" />
+
+ <application>
+ <provider
+ android:name=".AccessBluetoothOnCommand"
+ android:authorities="appthatrequestpermission"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocationNoProvider/Android.bp b/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocationNoProvider/Android.bp
new file mode 100644
index 000000000..6f635c0cc
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocationNoProvider/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsBluetoothPermissionNeverForLocationNoProvider",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocationNoProvider/AndroidManifest.xml b/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocationNoProvider/AndroidManifest.xml
new file mode 100644
index 000000000..6b4a991be
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestBluetoothPermissionNeverForLocationNoProvider/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appneverforlocation">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <uses-permission
+ android:name="android.permission.BLUETOOTH_ADVERTISE"
+ android:usesPermissionFlags="neverForLocation" />
+ <uses-permission
+ android:name="android.permission.BLUETOOTH_CONNECT"
+ android:usesPermissionFlags="neverForLocation" />
+ <uses-permission
+ android:name="android.permission.BLUETOOTH_SCAN"
+ android:usesPermissionFlags="neverForLocation" />
+
+ <application>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp b/tests/cts/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp
new file mode 100644
index 000000000..1a057d010
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsContactsAndCallLogPermission16",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestContactsAndCallLogPermission16/AndroidManifest.xml b/tests/cts/permission/AppThatRequestContactsAndCallLogPermission16/AndroidManifest.xml
new file mode 100644
index 000000000..08f014508
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestContactsAndCallLogPermission16/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="3">
+
+ <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16" />
+
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_CALL_LOG" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestContactsPermission15/Android.bp b/tests/cts/permission/AppThatRequestContactsPermission15/Android.bp
new file mode 100644
index 000000000..54618447e
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestContactsPermission15/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsContactsPermission15",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestContactsPermission15/AndroidManifest.xml b/tests/cts/permission/AppThatRequestContactsPermission15/AndroidManifest.xml
new file mode 100644
index 000000000..ab17c3668
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestContactsPermission15/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="2">
+
+ <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" />
+
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestContactsPermission16/Android.bp b/tests/cts/permission/AppThatRequestContactsPermission16/Android.bp
new file mode 100644
index 000000000..2dca5aa2c
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestContactsPermission16/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsContactsPermission16",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestContactsPermission16/AndroidManifest.xml b/tests/cts/permission/AppThatRequestContactsPermission16/AndroidManifest.xml
new file mode 100644
index 000000000..703bb3a75
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestContactsPermission16/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="1">
+
+ <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16" />
+
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestCustomCameraPermission/Android.bp b/tests/cts/permission/AppThatRequestCustomCameraPermission/Android.bp
new file mode 100644
index 000000000..873733d07
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestCustomCameraPermission/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestCustomCameraPermission",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "mts",
+ "sts",
+ "general-tests",
+ ],
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+}
diff --git a/tests/cts/permission/AppThatRequestCustomCameraPermission/AndroidManifest.xml b/tests/cts/permission/AppThatRequestCustomCameraPermission/AndroidManifest.xml
new file mode 100644
index 000000000..a8143a78e
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestCustomCameraPermission/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestcustomcamerapermission">
+
+ <permission android:name="appthatrequestcustomcamerapermission.CUSTOM"
+ android:permissionGroup="android.permission-group.CAMERA"
+ android:label="@string/permlab_custom"
+ android:description="@string/permdesc_custom"
+ android:protectionLevel="dangerous" />
+
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="appthatrequestcustomcamerapermission.CUSTOM" />
+
+ <application>
+ <activity android:name=".RequestCameraPermission" android:exported="true"
+ android:visibleToInstantApps="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatRequestCustomCameraPermission/res/values/strings.xml b/tests/cts/permission/AppThatRequestCustomCameraPermission/res/values/strings.xml
new file mode 100644
index 000000000..8de46384b
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestCustomCameraPermission/res/values/strings.xml
@@ -0,0 +1,20 @@
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<resources>
+ <string name="permlab_custom">Custom</string>
+ <string name="permdesc_custom">allows bypassing one-time permissions</string>
+</resources> \ No newline at end of file
diff --git a/tests/cts/permission/AppThatRequestCustomCameraPermission/src/android/permission/cts/appthatrequestcustomcamerapermission/RequestCameraPermission.java b/tests/cts/permission/AppThatRequestCustomCameraPermission/src/android/permission/cts/appthatrequestcustomcamerapermission/RequestCameraPermission.java
new file mode 100644
index 000000000..288e7e1b3
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestCustomCameraPermission/src/android/permission/cts/appthatrequestcustomcamerapermission/RequestCameraPermission.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthatrequestcustomcamerapermission;
+
+import static android.Manifest.permission.CAMERA;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+public class RequestCameraPermission extends Activity {
+ private static final String LOG_TAG = RequestCameraPermission.class.getSimpleName();
+
+ public static final String CUSTOM_PERMISSION = "appthatrequestcustomcamerapermission.CUSTOM";
+ private Handler mHandler;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ Log.w(LOG_TAG, "Activity was recreated. (Perhaps due to a configuration change?)");
+ return;
+ }
+
+ boolean cameraGranted =
+ checkSelfPermission(CAMERA) == PERMISSION_GRANTED;
+ boolean customGranted =
+ checkSelfPermission(CUSTOM_PERMISSION) == PERMISSION_GRANTED;
+
+ mHandler = new Handler(getMainLooper());
+
+ if (!cameraGranted && !customGranted) {
+ requestPermissions(new String[] {CAMERA}, 0);
+ } else {
+ Log.e(LOG_TAG, "Test app was opened with cameraGranted=" + cameraGranted
+ + " and customGranted=" + customGranted);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+
+ if (requestCode == 0) {
+ if (grantResults[0] != PERMISSION_GRANTED) {
+ Log.e(LOG_TAG, "permission wasn't granted, this test should fail,"
+ + " leaving test app open.");
+ } else {
+ // Delayed request because the immediate request might show the dialog again
+ mHandler.postDelayed(() ->
+ requestPermissions(new String[] {CUSTOM_PERMISSION}, 1), 500);
+ }
+ } else if (requestCode == 1) {
+ if (grantResults[0] != PERMISSION_GRANTED) {
+ Log.e(LOG_TAG, "permission wasn't granted, this test should fail,"
+ + " leaving test app open.");
+ } else {
+ // Here camera was granted and custom was autogranted, exit process and let test
+ // verify both are revoked.
+
+ // Delayed exit because b/254675301
+ mHandler.postDelayed(() -> System.exit(0), 1000);
+ }
+ }
+
+ }
+}
diff --git a/tests/cts/permission/AppThatRequestDevicePermissions/Android.bp b/tests/cts/permission/AppThatRequestDevicePermissions/Android.bp
new file mode 100644
index 000000000..c0a9f9914
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestDevicePermissions/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsDevicePermissions",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ srcs: ["src/**/*.kt"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestDevicePermissions/AndroidManifest.xml b/tests/cts/permission/AppThatRequestDevicePermissions/AndroidManifest.xml
new file mode 100644
index 000000000..a96342706
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestDevicePermissions/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <permission android:name="android.permission.cts.CUSTOM_SIGNATURE_PERMISSION"
+ android:protectionLevel="signature"/>
+ <uses-permission android:name="android.permission.cts.CUSTOM_SIGNATURE_PERMISSION" />
+
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <application>
+ <receiver
+ android:name="android.permission.cts.appthatrequestpermission.RevokeSelfPermissionReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.permission.cts.appthatrequestpermission.REVOKE_SELF_PERMISSION" />
+ </intent-filter>
+ </receiver>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatRequestDevicePermissions/src/android/permission/cts/appthatrequestpermission/RevokeSelfPermissionReceiver.kt b/tests/cts/permission/AppThatRequestDevicePermissions/src/android/permission/cts/appthatrequestpermission/RevokeSelfPermissionReceiver.kt
new file mode 100644
index 000000000..4ce6a2aaa
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestDevicePermissions/src/android/permission/cts/appthatrequestpermission/RevokeSelfPermissionReceiver.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permission.cts.appthatrequestpermission
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.os.Handler
+import android.os.Process
+
+/** Revokes permission for a device provided in the intent. */
+class RevokeSelfPermissionReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val permissionName = intent.getStringExtra("permissionName")!!
+ val deviceId = intent.getIntExtra("deviceID", Context.DEVICE_ID_INVALID)
+ val deviceContext = context.createDeviceContext(deviceId)
+ deviceContext.revokeSelfPermissionOnKill(permissionName)
+
+ // revokeSelfPermissionOnKill is an async API, and the work is executed by main
+ // thread, so we add the kill to the queue to be executed after revoke call.
+ val handler = Handler.createAsync(context.mainLooper)
+ handler.postDelayed({ Process.killProcess(Process.myPid()) }, 1000)
+ }
+}
diff --git a/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission28/Android.bp b/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission28/Android.bp
new file mode 100644
index 000000000..5a60a3fbd
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission28/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsLocationAndBackgroundPermission28",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission28/AndroidManifest.xml b/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission28/AndroidManifest.xml
new file mode 100644
index 000000000..626ee3d43
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission28/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="3">
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <!-- The ACCESS_BACKGROUND_LOCATION was added for API 29. But apps targeting lower APK levels
+ can still request it to signal that they are aware of this new behavior -->
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp b/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp
new file mode 100644
index 000000000..de6c3cbb2
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsLocationAndBackgroundPermission29",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ min_sdk_version: "29",
+ target_sdk_version: "29",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission29/AndroidManifest.xml b/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission29/AndroidManifest.xml
new file mode 100644
index 000000000..285502cb2
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationAndBackgroundPermission29/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="3">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestLocationPermission22/Android.bp b/tests/cts/permission/AppThatRequestLocationPermission22/Android.bp
new file mode 100644
index 000000000..25d9893ec
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationPermission22/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsLocationPermission22",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestLocationPermission22/AndroidManifest.xml b/tests/cts/permission/AppThatRequestLocationPermission22/AndroidManifest.xml
new file mode 100644
index 000000000..78251baea
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationPermission22/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="1">
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22" />
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestLocationPermission28/Android.bp b/tests/cts/permission/AppThatRequestLocationPermission28/Android.bp
new file mode 100644
index 000000000..bfeadbd58
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationPermission28/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsLocationPermission28",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestLocationPermission28/AndroidManifest.xml b/tests/cts/permission/AppThatRequestLocationPermission28/AndroidManifest.xml
new file mode 100644
index 000000000..c8cf95761
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationPermission28/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="2">
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestLocationPermission29/Android.bp b/tests/cts/permission/AppThatRequestLocationPermission29/Android.bp
new file mode 100644
index 000000000..ee3982ea4
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationPermission29/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsLocationPermission29",
+ defaults: ["cts_defaults"],
+ min_sdk_version: "29",
+ target_sdk_version: "29",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestLocationPermission29/AndroidManifest.xml b/tests/cts/permission/AppThatRequestLocationPermission29/AndroidManifest.xml
new file mode 100644
index 000000000..17a0e0d35
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationPermission29/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="1">
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestLocationPermission29v4/Android.bp b/tests/cts/permission/AppThatRequestLocationPermission29v4/Android.bp
new file mode 100644
index 000000000..b56bb25eb
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationPermission29v4/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsLocationPermission29v4",
+ defaults: ["cts_defaults"],
+ min_sdk_version: "29",
+ target_sdk_version: "29",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestLocationPermission29v4/AndroidManifest.xml b/tests/cts/permission/AppThatRequestLocationPermission29v4/AndroidManifest.xml
new file mode 100644
index 000000000..572222c49
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestLocationPermission29v4/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="4">
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestMultiplePermissionsWithMinMaxSdk/Android.bp b/tests/cts/permission/AppThatRequestMultiplePermissionsWithMinMaxSdk/Android.bp
new file mode 100644
index 000000000..5fcc6c8ba
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestMultiplePermissionsWithMinMaxSdk/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsMultiplePermissionsWithMinMaxSdk",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestMultiplePermissionsWithMinMaxSdk/AndroidManifest.xml b/tests/cts/permission/AppThatRequestMultiplePermissionsWithMinMaxSdk/AndroidManifest.xml
new file mode 100644
index 000000000..e75a7f5c9
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestMultiplePermissionsWithMinMaxSdk/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="2">
+
+ <uses-permission android:name="android.permission.cts.appthatrequestpermission.permissions.MINSDK_LT_DEVICESDK" android:minSdkVersion="32" />
+ <uses-permission android:name="android.permission.cts.appthatrequestpermission.permissions.MINSDK_GT_DEVICESDK" android:minSdkVersion="2147483647" />
+
+ <uses-permission android:name="android.permission.cts.appthatrequestpermission.permissions.MAXSDK_LT_DEVICESDK" android:maxSdkVersion="32" />
+ <uses-permission android:name="android.permission.cts.appthatrequestpermission.permissions.MAXSDK_GT_DEVICESDK" android:maxSdkVersion="2147483647" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestOneTimePermission/Android.bp b/tests/cts/permission/AppThatRequestOneTimePermission/Android.bp
new file mode 100644
index 000000000..c12a70871
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestOneTimePermission/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsOneTimePermission",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "mts-permission",
+ "general-tests",
+ ],
+ srcs: ["src/**/*.java"],
+}
diff --git a/tests/cts/permission/AppThatRequestOneTimePermission/AndroidManifest.xml b/tests/cts/permission/AppThatRequestOneTimePermission/AndroidManifest.xml
new file mode 100644
index 000000000..24fc537cf
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestOneTimePermission/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
+
+ <application>
+ <activity android:name=".RequestPermission" android:exported="true"
+ android:visibleToInstantApps="true" />
+ <service android:name=".KeepAliveForegroundService"
+ android:foregroundServiceType="specialUse"
+ android:exported="true"
+ android:visibleToInstantApps="true" >
+ <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="cts" />
+ </service>
+ </application>
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestOneTimePermission/src/android/permission/cts/appthatrequestpermission/KeepAliveForegroundService.java b/tests/cts/permission/AppThatRequestOneTimePermission/src/android/permission/cts/appthatrequestpermission/KeepAliveForegroundService.java
new file mode 100644
index 000000000..e41a47321
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestOneTimePermission/src/android/permission/cts/appthatrequestpermission/KeepAliveForegroundService.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthatrequestpermission;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+
+public class KeepAliveForegroundService extends Service {
+
+ private static final String EXTRA_FOREGROUND_SERVICE_LIFESPAN =
+ "android.permission.cts.OneTimePermissionTest.EXTRA_FOREGROUND_SERVICE_LIFESPAN";
+
+ private static final String EXTRA_FOREGROUND_SERVICE_STICKY =
+ "android.permission.cts.OneTimePermissionTest.EXTRA_FOREGROUND_SERVICE_STICKY";
+
+ private static final String CHANNEL_ID = "channelId";
+ private static final String CHANNEL_NAME = "channelName";
+
+ private static final long DEFAULT_LIFESPAN = 5000;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ long lifespan;
+ boolean sticky;
+ if (intent == null) {
+ lifespan = DEFAULT_LIFESPAN;
+ sticky = false;
+ } else {
+ lifespan = intent.getLongExtra(EXTRA_FOREGROUND_SERVICE_LIFESPAN, DEFAULT_LIFESPAN);
+ sticky = intent.getBooleanExtra(EXTRA_FOREGROUND_SERVICE_STICKY, false);
+ }
+ NotificationManager notificationManager = getSystemService(NotificationManager.class);
+ notificationManager.createNotificationChannel(
+ new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
+ NotificationManager.IMPORTANCE_LOW));
+ Notification notification = new Notification.Builder(this, CHANNEL_ID)
+ .setSmallIcon(android.R.drawable.ic_lock_lock)
+ .build();
+ startForeground(1, notification);
+ new Handler(Looper.getMainLooper()).postDelayed(
+ () -> stopForeground(Service.STOP_FOREGROUND_REMOVE), lifespan);
+ if (sticky) {
+ return START_STICKY;
+ }
+ return super.onStartCommand(intent, flags, startId);
+ }
+}
diff --git a/tests/cts/permission/AppThatRequestOneTimePermission/src/android/permission/cts/appthatrequestpermission/RequestPermission.java b/tests/cts/permission/AppThatRequestOneTimePermission/src/android/permission/cts/appthatrequestpermission/RequestPermission.java
new file mode 100644
index 000000000..f2910c391
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestOneTimePermission/src/android/permission/cts/appthatrequestpermission/RequestPermission.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthatrequestpermission;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class RequestPermission extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ requestPermissions(new String[] {"android.permission.ACCESS_FINE_LOCATION"}, 0);
+ }
+}
diff --git a/tests/cts/permission/AppThatRequestPermissionAandB/Android.bp b/tests/cts/permission/AppThatRequestPermissionAandB/Android.bp
new file mode 100644
index 000000000..6c037b456
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestPermissionAandB/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsPermissionAandB",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ srcs: ["src/**/*.java"],
+}
diff --git a/tests/cts/permission/AppThatRequestPermissionAandB/AndroidManifest.xml b/tests/cts/permission/AppThatRequestPermissionAandB/AndroidManifest.xml
new file mode 100644
index 000000000..4c85a262b
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestPermissionAandB/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission">
+
+ <permission android:name="android.permission.cts.appthatrequestpermission.A"
+ android:protectionLevel="dangerous"
+ android:label="@string/perm_a"
+ android:permissionGroup="android.permission.cts.groupB"
+ android:description="@string/perm_a" />
+
+ <uses-permission android:name="android.permission.cts.appthatrequestpermission.A" />
+ <uses-permission android:name="android.permission.cts.B" />
+
+ <application>
+ <activity android:name=".RequestPermission" android:exported="true"
+ android:visibleToInstantApps="true" />
+ </application>
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestPermissionAandB/res/values/strings.xml b/tests/cts/permission/AppThatRequestPermissionAandB/res/values/strings.xml
new file mode 100644
index 000000000..563009789
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestPermissionAandB/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="perm_a">Permission A</string>
+</resources>
diff --git a/tests/cts/permission/AppThatRequestPermissionAandB/src/android/permission/cts/appthatrequestpermission/RequestPermission.java b/tests/cts/permission/AppThatRequestPermissionAandB/src/android/permission/cts/appthatrequestpermission/RequestPermission.java
new file mode 100644
index 000000000..26671beb7
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestPermissionAandB/src/android/permission/cts/appthatrequestpermission/RequestPermission.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthatrequestpermission;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class RequestPermission extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ requestPermissions(new String[] {"android.permission.cts.appthatrequestpermission.A",
+ "android.permission.cts.B"}, 0);
+ }
+}
diff --git a/tests/cts/permission/AppThatRequestPermissionAandC/Android.bp b/tests/cts/permission/AppThatRequestPermissionAandC/Android.bp
new file mode 100644
index 000000000..b94965334
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestPermissionAandC/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsPermissionAandC",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ srcs: ["src/**/*.java"],
+}
diff --git a/tests/cts/permission/AppThatRequestPermissionAandC/AndroidManifest.xml b/tests/cts/permission/AppThatRequestPermissionAandC/AndroidManifest.xml
new file mode 100644
index 000000000..9b998311b
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestPermissionAandC/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission">
+
+ <permission android:name="android.permission.cts.appthatrequestpermission.A"
+ android:protectionLevel="dangerous"
+ android:label="@string/perm_a"
+ android:permissionGroup="android.permission.cts.groupC"
+ android:description="@string/perm_a" />
+
+ <uses-permission android:name="android.permission.cts.appthatrequestpermission.A" />
+ <uses-permission android:name="android.permission.cts.C" />
+
+ <application>
+ <activity android:name=".RequestPermission" android:exported="true"
+ android:visibleToInstantApps="true" />
+ </application>
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestPermissionAandC/res/values/strings.xml b/tests/cts/permission/AppThatRequestPermissionAandC/res/values/strings.xml
new file mode 100644
index 000000000..563009789
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestPermissionAandC/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="perm_a">Permission A</string>
+</resources>
diff --git a/tests/cts/permission/AppThatRequestPermissionAandC/src/android/permission/cts/appthatrequestpermission/RequestPermission.java b/tests/cts/permission/AppThatRequestPermissionAandC/src/android/permission/cts/appthatrequestpermission/RequestPermission.java
new file mode 100644
index 000000000..ad72c4db2
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestPermissionAandC/src/android/permission/cts/appthatrequestpermission/RequestPermission.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthatrequestpermission;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class RequestPermission extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ requestPermissions(new String[] {"android.permission.cts.appthatrequestpermission.A",
+ "android.permission.cts.C"}, 0);
+ }
+}
diff --git a/tests/cts/permission/AppThatRequestStoragePermission28/Android.bp b/tests/cts/permission/AppThatRequestStoragePermission28/Android.bp
new file mode 100644
index 000000000..50ae9209b
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestStoragePermission28/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsStoragePermission28",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestStoragePermission28/AndroidManifest.xml b/tests/cts/permission/AppThatRequestStoragePermission28/AndroidManifest.xml
new file mode 100644
index 000000000..a847f39bd
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestStoragePermission28/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="2">
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestStoragePermission29/Android.bp b/tests/cts/permission/AppThatRequestStoragePermission29/Android.bp
new file mode 100644
index 000000000..4663be9dc
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestStoragePermission29/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsStoragePermission29",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestStoragePermission29/AndroidManifest.xml b/tests/cts/permission/AppThatRequestStoragePermission29/AndroidManifest.xml
new file mode 100644
index 000000000..c783085a0
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestStoragePermission29/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="1">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppThatRequestSystemAlertWindow22/Android.bp b/tests/cts/permission/AppThatRequestSystemAlertWindow22/Android.bp
new file mode 100644
index 000000000..43cc9de97
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestSystemAlertWindow22/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsSystemAlertWindow22",
+ target_sdk_version: "22",
+ certificate: ":cts-testkey2",
+ min_sdk_version: "22",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml b/tests/cts/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml
new file mode 100644
index 000000000..bd13612d2
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.usesystemalertwindowpermission">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+</manifest>
diff --git a/tests/cts/permission/AppThatRequestSystemAlertWindow23/Android.bp b/tests/cts/permission/AppThatRequestSystemAlertWindow23/Android.bp
new file mode 100644
index 000000000..403257d45
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestSystemAlertWindow23/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsSystemAlertWindow23",
+ target_sdk_version: "23",
+ certificate: ":cts-testkey2",
+ min_sdk_version: "23",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml b/tests/cts/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml
new file mode 100644
index 000000000..bd13612d2
--- /dev/null
+++ b/tests/cts/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.usesystemalertwindowpermission">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+</manifest>
diff --git a/tests/cts/permission/AppThatRunsRationaleTests/Android.bp b/tests/cts/permission/AppThatRunsRationaleTests/Android.bp
new file mode 100644
index 000000000..30019fba5
--- /dev/null
+++ b/tests/cts/permission/AppThatRunsRationaleTests/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRunsRationaleTests",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "test_current",
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+
+ srcs: ["src/**/*.java"],
+}
diff --git a/tests/cts/permission/AppThatRunsRationaleTests/AndroidManifest.xml b/tests/cts/permission/AppThatRunsRationaleTests/AndroidManifest.xml
new file mode 100644
index 000000000..4b7214fd6
--- /dev/null
+++ b/tests/cts/permission/AppThatRunsRationaleTests/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrunsrationaletests">
+
+ <uses-permission android:name="android.permission.READ_CONTACTS"/>
+
+ <application android:label="CtsRationaleTests">
+ <activity android:name=".TestActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppThatRunsRationaleTests/src/android/permission/cts/appthatrunsrationaletests/TestActivity.java b/tests/cts/permission/AppThatRunsRationaleTests/src/android/permission/cts/appthatrunsrationaletests/TestActivity.java
new file mode 100644
index 000000000..7544890ff
--- /dev/null
+++ b/tests/cts/permission/AppThatRunsRationaleTests/src/android/permission/cts/appthatrunsrationaletests/TestActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthatrunsrationaletests;
+
+import android.Manifest;
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+
+public class TestActivity extends Activity {
+ private static final String CALLBACK_KEY = "testactivitycallback";
+ private static final String RESULT_KEY = "testactivityresult";
+ private static final String PERMISSION_NAME = Manifest.permission.READ_CONTACTS;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ RemoteCallback cb = (RemoteCallback) getIntent().getExtras().get(CALLBACK_KEY);
+
+ boolean result = shouldShowRequestPermissionRationale(PERMISSION_NAME);
+ Bundle res = new Bundle();
+ res.putBoolean(RESULT_KEY, result);
+
+ finish();
+ cb.sendResult(res);
+ }
+}
diff --git a/tests/cts/permission/AppToTestRevokeSelfPermission/Android.bp b/tests/cts/permission/AppToTestRevokeSelfPermission/Android.bp
new file mode 100644
index 000000000..6e200bf32
--- /dev/null
+++ b/tests/cts/permission/AppToTestRevokeSelfPermission/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppToTestRevokeSelfPermission",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "mts",
+ "general-tests",
+ ],
+ srcs: ["src/**/*.java"],
+}
diff --git a/tests/cts/permission/AppToTestRevokeSelfPermission/AndroidManifest.xml b/tests/cts/permission/AppToTestRevokeSelfPermission/AndroidManifest.xml
new file mode 100644
index 000000000..dbe58bfd5
--- /dev/null
+++ b/tests/cts/permission/AppToTestRevokeSelfPermission/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.apptotestrevokeselfpermission">
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />
+
+ <application>
+ <activity android:name=".RevokePermission" android:exported="true"
+ android:visibleToInstantApps="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permission/AppToTestRevokeSelfPermission/src/android/permission/cts/apptotestselfrevokepermission/RevokePermission.java b/tests/cts/permission/AppToTestRevokeSelfPermission/src/android/permission/cts/apptotestselfrevokepermission/RevokePermission.java
new file mode 100644
index 000000000..b9a0ed7bb
--- /dev/null
+++ b/tests/cts/permission/AppToTestRevokeSelfPermission/src/android/permission/cts/apptotestselfrevokepermission/RevokePermission.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.apptotestrevokeselfpermission;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Arrays;
+
+public class RevokePermission extends Activity {
+ private static final String TAG = "RevokePermission";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ Log.w(TAG, "Activity was recreated. (Perhaps due to a configuration change?)");
+ return;
+ }
+
+ Intent intent = getIntent();
+ String[] permissions = intent.getStringArrayExtra("permissions");
+ if (permissions == null) {
+ return;
+ }
+ if (permissions.length == 1) {
+ getApplicationContext().revokeSelfPermissionOnKill(permissions[0]);
+ } else {
+ getApplicationContext().revokeSelfPermissionsOnKill(Arrays.asList(permissions));
+ }
+ }
+}
diff --git a/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp b/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp
new file mode 100644
index 000000000..8214c425d
--- /dev/null
+++ b/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppWithSharedUidThatRequestsLocationPermission28",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission28/AndroidManifest.xml b/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission28/AndroidManifest.xml
new file mode 100644
index 000000000..ec69d1541
--- /dev/null
+++ b/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission28/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="2"
+ android:sharedUserId="android.permission.cts.appthatrequestpermission">
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp b/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp
new file mode 100644
index 000000000..3df5c9a7d
--- /dev/null
+++ b/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppWithSharedUidThatRequestsLocationPermission29",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission29/AndroidManifest.xml b/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission29/AndroidManifest.xml
new file mode 100644
index 000000000..234192259
--- /dev/null
+++ b/tests/cts/permission/AppWithSharedUidThatRequestLocationPermission29/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:versionCode="1"
+ android:sharedUserId="android.permission.cts.appthatrequestpermission">
+
+ <!-- STOPSHIP: Set to apk level that shipped the location tristate -->
+ <!-- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" /> -->
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp b/tests/cts/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp
new file mode 100644
index 000000000..7dd3ef638
--- /dev/null
+++ b/tests/cts/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppWithSharedUidThatRequestsNoPermissions",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppWithSharedUidThatRequestsNoPermissions/AndroidManifest.xml b/tests/cts/permission/AppWithSharedUidThatRequestsNoPermissions/AndroidManifest.xml
new file mode 100644
index 000000000..0b34036ec
--- /dev/null
+++ b/tests/cts/permission/AppWithSharedUidThatRequestsNoPermissions/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestnopermission"
+ android:sharedUserId="cts.permissions">
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/AppWithSharedUidThatRequestsPermissions/Android.bp b/tests/cts/permission/AppWithSharedUidThatRequestsPermissions/Android.bp
new file mode 100644
index 000000000..c58b3e81e
--- /dev/null
+++ b/tests/cts/permission/AppWithSharedUidThatRequestsPermissions/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppWithSharedUidThatRequestsPermissions",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permission/AppWithSharedUidThatRequestsPermissions/AndroidManifest.xml b/tests/cts/permission/AppWithSharedUidThatRequestsPermissions/AndroidManifest.xml
new file mode 100644
index 000000000..ce02f17e1
--- /dev/null
+++ b/tests/cts/permission/AppWithSharedUidThatRequestsPermissions/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthatrequestpermission"
+ android:sharedUserId="cts.permissions">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+
+ <application />
+</manifest>
+
diff --git a/tests/cts/permission/OWNERS b/tests/cts/permission/OWNERS
new file mode 100644
index 000000000..6b284590c
--- /dev/null
+++ b/tests/cts/permission/OWNERS
@@ -0,0 +1,12 @@
+# Bug component: 137825
+
+include platform/frameworks/base:/core/java/android/permission/OWNERS
+
+per-file PowerManagerServicePermissionTest.java = file: platform/frameworks/base:/services/core/java/com/android/server/power/OWNERS
+per-file RequestLocation.java = tgunn@google.com
+
+per-file NoAudioPermissionTest.java = elaurent@google.com
+per-file MainlineNetworkStackPermissionTest.java = file: platform/frameworks/base:/services/net/OWNERS
+per-file Camera2PermissionTest.java = file: platform/frameworks/av:/camera/OWNERS
+per-file NoRollbackPermissionTest.java = mpgroover@google.com
+per-file EthernetManagerPermissionTest.java = file: platform/frameworks/base:/services/net/OWNERS \ No newline at end of file
diff --git a/tests/cts/permission/README b/tests/cts/permission/README
new file mode 100644
index 000000000..1ffc81f96
--- /dev/null
+++ b/tests/cts/permission/README
@@ -0,0 +1,16 @@
+Copyright (C) 2008 The Android Open Source Project
+
+Licensed under the Apache Licence, 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.
+
+In the permissions test cases, we just test the negative cases. These tests are to test the behavior of accessing the APIs without the required permission.
+
diff --git a/tests/cts/permission/StorageEscalationApp28/Android.bp b/tests/cts/permission/StorageEscalationApp28/Android.bp
new file mode 100644
index 000000000..9ea70f565
--- /dev/null
+++ b/tests/cts/permission/StorageEscalationApp28/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStorageEscalationApp28",
+ certificate: ":cts-testkey2",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/StorageEscalationApp28/AndroidManifest.xml b/tests/cts/permission/StorageEscalationApp28/AndroidManifest.xml
new file mode 100644
index 000000000..7b468bbf1
--- /dev/null
+++ b/tests/cts/permission/StorageEscalationApp28/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.storageescalation">
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
+
+ <application android:hasCode="false" />
+</manifest>
diff --git a/tests/cts/permission/StorageEscalationApp29Full/Android.bp b/tests/cts/permission/StorageEscalationApp29Full/Android.bp
new file mode 100644
index 000000000..dcb64e68a
--- /dev/null
+++ b/tests/cts/permission/StorageEscalationApp29Full/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStorageEscalationApp29Full",
+ certificate: ":cts-testkey2",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/StorageEscalationApp29Full/AndroidManifest.xml b/tests/cts/permission/StorageEscalationApp29Full/AndroidManifest.xml
new file mode 100644
index 000000000..0ed8e0024
--- /dev/null
+++ b/tests/cts/permission/StorageEscalationApp29Full/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.storageescalation">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
+
+ <application android:hasCode="false" android:requestLegacyExternalStorage="true"/>
+</manifest>
diff --git a/tests/cts/permission/StorageEscalationApp29Scoped/Android.bp b/tests/cts/permission/StorageEscalationApp29Scoped/Android.bp
new file mode 100644
index 000000000..8a780c07b
--- /dev/null
+++ b/tests/cts/permission/StorageEscalationApp29Scoped/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStorageEscalationApp29Scoped",
+ certificate: ":cts-testkey2",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/cts/permission/StorageEscalationApp29Scoped/AndroidManifest.xml b/tests/cts/permission/StorageEscalationApp29Scoped/AndroidManifest.xml
new file mode 100644
index 000000000..0ce57c1b5
--- /dev/null
+++ b/tests/cts/permission/StorageEscalationApp29Scoped/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.storageescalation">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
+
+ <application android:hasCode="false" android:requestLegacyExternalStorage="false"/>
+</manifest>
diff --git a/tests/cts/permission/jni/Android.bp b/tests/cts/permission/jni/Android.bp
new file mode 100644
index 000000000..59f93a098
--- /dev/null
+++ b/tests/cts/permission/jni/Android.bp
@@ -0,0 +1,60 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test_library {
+ name: "libctspermission_jni",
+ sdk_version: "current",
+ srcs: [
+ "CtsPermissionsJniOnLoad.cpp",
+ "android_permission_cts_FileUtils.cpp",
+ ],
+ shared_libs: [
+ "libnativehelper_compat_libc++",
+ "liblog",
+ ],
+ stl: "c++_static",
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+ gtest: false,
+}
+
+cc_test_library {
+ name: "libpermissionmanager_native_test",
+ sdk_version: "current",
+ compile_multilib: "both",
+ srcs: [
+ "PermissionManagerNativeJniTest.cpp"
+ ],
+ shared_libs: [
+ "libandroid",
+ "liblog",
+ ],
+ static_libs: [
+ "libbase_ndk",
+ ],
+ whole_static_libs: [
+ "libnativetesthelper_jni"
+ ],
+ gtest: false,
+ stl: "libc++_static",
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/tests/cts/permission/jni/CtsPermissionsJniOnLoad.cpp b/tests/cts/permission/jni/CtsPermissionsJniOnLoad.cpp
new file mode 100644
index 000000000..fab33bdc7
--- /dev/null
+++ b/tests/cts/permission/jni/CtsPermissionsJniOnLoad.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <stdio.h>
+
+extern int register_android_permission_cts_FileUtils(JNIEnv*);
+
+jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+ JNIEnv *env = NULL;
+
+ if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
+ return JNI_ERR;
+ }
+
+ if (register_android_permission_cts_FileUtils(env)) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_4;
+}
diff --git a/tests/cts/permission/jni/PermissionManagerNativeJniTest.cpp b/tests/cts/permission/jni/PermissionManagerNativeJniTest.cpp
new file mode 100644
index 000000000..392007074
--- /dev/null
+++ b/tests/cts/permission/jni/PermissionManagerNativeJniTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "PermissionManagerNativeJniTest"
+
+#include <android/permission_manager.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+class PermissionManagerNativeJniTest : public ::testing::Test {
+public:
+ void SetUp() override { }
+ void TearDown() override { }
+};
+
+//-------------------------------------------------------------------------------------------------
+TEST_F(PermissionManagerNativeJniTest, testCheckPermission) {
+ pid_t selfPid = ::getpid();
+ uid_t selfUid = ::getuid();
+
+ LOG(INFO) << "testCheckPermission: uid " << selfUid << ", pid" << selfPid;
+
+ int32_t result;
+ // Check some permission(s) we should have.
+ EXPECT_EQ(APermissionManager_checkPermission("android.permission.ACCESS_FINE_LOCATION",
+ selfPid, selfUid, &result),
+ PERMISSION_MANAGER_STATUS_OK);
+ EXPECT_EQ(result, PERMISSION_MANAGER_PERMISSION_GRANTED);
+
+ // Check some permission(s) we should not have.
+ EXPECT_EQ(APermissionManager_checkPermission("android.permission.MANAGE_USERS",
+ selfPid, selfUid, &result),
+ PERMISSION_MANAGER_STATUS_OK);
+ EXPECT_EQ(result, PERMISSION_MANAGER_PERMISSION_DENIED);
+}
+
diff --git a/tests/cts/permission/jni/android_permission_cts_FileUtils.cpp b/tests/cts/permission/jni/android_permission_cts_FileUtils.cpp
new file mode 100644
index 000000000..68c3c76d3
--- /dev/null
+++ b/tests/cts/permission/jni/android_permission_cts_FileUtils.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/log.h>
+#include <jni.h>
+#include <stdio.h>
+#include <linux/xattr.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include <sys/capability.h>
+#include <grp.h>
+#include <pwd.h>
+#include <string.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+static jfieldID gFileStatusDevFieldID;
+static jfieldID gFileStatusInoFieldID;
+static jfieldID gFileStatusModeFieldID;
+static jfieldID gFileStatusNlinkFieldID;
+static jfieldID gFileStatusUidFieldID;
+static jfieldID gFileStatusGidFieldID;
+static jfieldID gFileStatusSizeFieldID;
+static jfieldID gFileStatusBlksizeFieldID;
+static jfieldID gFileStatusBlocksFieldID;
+static jfieldID gFileStatusAtimeFieldID;
+static jfieldID gFileStatusMtimeFieldID;
+static jfieldID gFileStatusCtimeFieldID;
+
+/*
+ * Native methods used by
+ * cts/tests/tests/permission/src/android/permission/cts/FileUtils.java
+ *
+ * Copied from hidden API: frameworks/base/core/jni/android_os_FileUtils.cpp
+ */
+
+jboolean android_permission_cts_FileUtils_getFileStatus(JNIEnv* env,
+ jobject /* thiz */, jstring path, jobject fileStatus, jboolean statLinks)
+{
+ ScopedUtfChars cPath(env, path);
+ jboolean ret = false;
+ struct stat s;
+
+ int res = statLinks == true ? lstat(cPath.c_str(), &s)
+ : stat(cPath.c_str(), &s);
+
+ if (res == 0) {
+ ret = true;
+ if (fileStatus != NULL) {
+ env->SetIntField(fileStatus, gFileStatusDevFieldID, s.st_dev);
+ env->SetIntField(fileStatus, gFileStatusInoFieldID, s.st_ino);
+ env->SetIntField(fileStatus, gFileStatusModeFieldID, s.st_mode);
+ env->SetIntField(fileStatus, gFileStatusNlinkFieldID, s.st_nlink);
+ env->SetIntField(fileStatus, gFileStatusUidFieldID, s.st_uid);
+ env->SetIntField(fileStatus, gFileStatusGidFieldID, s.st_gid);
+ env->SetLongField(fileStatus, gFileStatusSizeFieldID, s.st_size);
+ env->SetIntField(fileStatus, gFileStatusBlksizeFieldID, s.st_blksize);
+ env->SetLongField(fileStatus, gFileStatusBlocksFieldID, s.st_blocks);
+ env->SetLongField(fileStatus, gFileStatusAtimeFieldID, s.st_atime);
+ env->SetLongField(fileStatus, gFileStatusMtimeFieldID, s.st_mtime);
+ env->SetLongField(fileStatus, gFileStatusCtimeFieldID, s.st_ctime);
+ }
+ }
+
+ return ret;
+}
+
+jstring android_permission_cts_FileUtils_getUserName(JNIEnv* env,
+ jobject /* thiz */, jint uid)
+{
+ struct passwd *pwd = getpwuid(uid);
+ return env->NewStringUTF(pwd->pw_name);
+}
+
+jstring android_permission_cts_FileUtils_getGroupName(JNIEnv* env,
+ jobject /* thiz */, jint gid)
+{
+ struct group *grp = getgrgid(gid);
+ return env->NewStringUTF(grp->gr_name);
+}
+
+static jboolean isPermittedCapBitSet(JNIEnv* env, jstring path, size_t capId)
+{
+ struct vfs_cap_data capData;
+ memset(&capData, 0, sizeof(capData));
+
+ ScopedUtfChars cPath(env, path);
+ ssize_t result = getxattr(cPath.c_str(), XATTR_NAME_CAPS, &capData,
+ sizeof(capData));
+ if (result <= 0)
+ {
+ __android_log_print(ANDROID_LOG_DEBUG, NULL,
+ "isPermittedCapBitSet(): getxattr(\"%s\") call failed: "
+ "return %zd (error: %s (%d))\n",
+ cPath.c_str(), result, strerror(errno), errno);
+ return false;
+ }
+
+ return (capData.data[CAP_TO_INDEX(capId)].permitted &
+ CAP_TO_MASK(capId)) != 0;
+}
+
+jboolean android_permission_cts_FileUtils_hasSetUidCapability(JNIEnv* env,
+ jobject /* clazz */, jstring path)
+{
+ return isPermittedCapBitSet(env, path, CAP_SETUID);
+}
+
+jboolean android_permission_cts_FileUtils_hasSetGidCapability(JNIEnv* env,
+ jobject /* clazz */, jstring path)
+{
+ return isPermittedCapBitSet(env, path, CAP_SETGID);
+}
+
+static bool throwNamedException(JNIEnv* env, const char* className,
+ const char* message)
+{
+ ScopedLocalRef<jclass> eClazz(env, env->FindClass(className));
+ if (eClazz.get() == NULL)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, NULL,
+ "throwNamedException(): failed to find class %s, cannot throw",
+ className);
+ return false;
+ }
+
+ env->ThrowNew(eClazz.get(), message);
+ return true;
+}
+
+// fill vfs_cap_data's permitted caps given a Java int[] of cap ids
+static bool fillPermittedCaps(vfs_cap_data* capData, JNIEnv* env, jintArray capIds)
+{
+ ScopedIntArrayRO cCapIds(env, capIds);
+ const size_t capCount = cCapIds.size();
+
+ for (size_t i = 0; i < capCount; ++i)
+ {
+ const jint capId = cCapIds[i];
+ if (!cap_valid(capId))
+ {
+ char message[64];
+ snprintf(message, sizeof(message),
+ "capability id %d out of valid range", capId);
+ throwNamedException(env, "java/lang/IllegalArgumentException",
+ message);
+
+ return false;
+ }
+ capData->data[CAP_TO_INDEX(capId)].permitted |= CAP_TO_MASK(capId);
+ }
+ return true;
+}
+
+jboolean android_permission_cts_FileUtils_CapabilitySet_fileHasOnly(JNIEnv* env,
+ jobject /* clazz */, jstring path, jintArray capIds)
+{
+ struct vfs_cap_data expectedCapData;
+ memset(&expectedCapData, 0, sizeof(expectedCapData));
+
+ expectedCapData.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
+ if (!fillPermittedCaps(&expectedCapData, env, capIds))
+ {
+ // exception thrown
+ return false;
+ }
+
+ struct vfs_cap_data actualCapData;
+ memset(&actualCapData, 0, sizeof(actualCapData));
+
+ ScopedUtfChars cPath(env, path);
+ ssize_t result = getxattr(cPath.c_str(), XATTR_NAME_CAPS, &actualCapData,
+ sizeof(actualCapData));
+ if (result <= 0)
+ {
+ __android_log_print(ANDROID_LOG_DEBUG, NULL,
+ "fileHasOnly(): getxattr(\"%s\") call failed: "
+ "return %zd (error: %s (%d))\n",
+ cPath.c_str(), result, strerror(errno), errno);
+ return false;
+ }
+
+ return (memcmp(&expectedCapData, &actualCapData,
+ sizeof(struct vfs_cap_data)) == 0);
+}
+
+static JNINativeMethod gMethods[] = {
+ { "getFileStatus", "(Ljava/lang/String;Landroid/permission/cts/FileUtils$FileStatus;Z)Z",
+ (void *) android_permission_cts_FileUtils_getFileStatus },
+ { "getUserName", "(I)Ljava/lang/String;",
+ (void *) android_permission_cts_FileUtils_getUserName },
+ { "getGroupName", "(I)Ljava/lang/String;",
+ (void *) android_permission_cts_FileUtils_getGroupName },
+ { "hasSetUidCapability", "(Ljava/lang/String;)Z",
+ (void *) android_permission_cts_FileUtils_hasSetUidCapability },
+ { "hasSetGidCapability", "(Ljava/lang/String;)Z",
+ (void *) android_permission_cts_FileUtils_hasSetGidCapability },
+};
+
+static JNINativeMethod gCapabilitySetMethods[] = {
+ { "fileHasOnly", "(Ljava/lang/String;[I)Z",
+ (void *) android_permission_cts_FileUtils_CapabilitySet_fileHasOnly },
+};
+
+int register_android_permission_cts_FileUtils(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/permission/cts/FileUtils");
+
+ jclass fileStatusClass = env->FindClass("android/permission/cts/FileUtils$FileStatus");
+ gFileStatusDevFieldID = env->GetFieldID(fileStatusClass, "dev", "I");
+ gFileStatusInoFieldID = env->GetFieldID(fileStatusClass, "ino", "I");
+ gFileStatusModeFieldID = env->GetFieldID(fileStatusClass, "mode", "I");
+ gFileStatusNlinkFieldID = env->GetFieldID(fileStatusClass, "nlink", "I");
+ gFileStatusUidFieldID = env->GetFieldID(fileStatusClass, "uid", "I");
+ gFileStatusGidFieldID = env->GetFieldID(fileStatusClass, "gid", "I");
+ gFileStatusSizeFieldID = env->GetFieldID(fileStatusClass, "size", "J");
+ gFileStatusBlksizeFieldID = env->GetFieldID(fileStatusClass, "blksize", "I");
+ gFileStatusBlocksFieldID = env->GetFieldID(fileStatusClass, "blocks", "J");
+ gFileStatusAtimeFieldID = env->GetFieldID(fileStatusClass, "atime", "J");
+ gFileStatusMtimeFieldID = env->GetFieldID(fileStatusClass, "mtime", "J");
+ gFileStatusCtimeFieldID = env->GetFieldID(fileStatusClass, "ctime", "J");
+
+ jint result = env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+ if (result)
+ {
+ return result;
+ }
+
+ // register FileUtils.CapabilitySet native methods
+ jclass capClazz = env->FindClass("android/permission/cts/FileUtils$CapabilitySet");
+
+ return env->RegisterNatives(capClazz, gCapabilitySetMethods,
+ sizeof(gCapabilitySetMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/cts/permission/nativeTests/Android.bp b/tests/cts/permission/nativeTests/Android.bp
new file mode 100644
index 000000000..40f8b6e0d
--- /dev/null
+++ b/tests/cts/permission/nativeTests/Android.bp
@@ -0,0 +1,56 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "CtsPermissionManagerNativeTestCases",
+
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ srcs: ["src/PermissionManagerNativeTest.cpp"],
+
+ shared_libs: [
+ "liblog",
+ "libandroid",
+ ],
+
+ static_libs: [
+ "libgtest_ndk_c++",
+ "libbase_ndk",
+ ],
+ stl: "libc++_static",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permission/nativeTests/AndroidTest.xml b/tests/cts/permission/nativeTests/AndroidTest.xml
new file mode 100644
index 000000000..f477231ef
--- /dev/null
+++ b/tests/cts/permission/nativeTests/AndroidTest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS PermissionManager native test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="permissions" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <option name="force-root" value="false" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="CtsPermissionManagerNativeTestCases->/data/local/tmp/CtsPermissionManagerNativeTestCases" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="CtsPermissionManagerNativeTestCases" />
+ <option name="runtime-hint" value="15s" />
+ </test>
+
+ <!-- Controller that will skip the module if a native bridge situation is detected -->
+ <!-- For example: module wants to run arm and device is x86 -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
+</configuration>
diff --git a/tests/cts/permission/nativeTests/src/PermissionManagerNativeTest.cpp b/tests/cts/permission/nativeTests/src/PermissionManagerNativeTest.cpp
new file mode 100644
index 000000000..1b0dc06ea
--- /dev/null
+++ b/tests/cts/permission/nativeTests/src/PermissionManagerNativeTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "PermissionManagerNativeTest"
+
+#include <android/permission_manager.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+//-----------------------------------------------------------------
+class PermissionManagerNativeTest : public ::testing::Test {
+
+protected:
+ PermissionManagerNativeTest() { }
+
+ virtual ~PermissionManagerNativeTest() { }
+
+ /* Test setup*/
+ virtual void SetUp() { }
+
+ /* Test tear down */
+ virtual void TearDown() { }
+};
+
+//-------------------------------------------------------------------------------------------------
+TEST_F(PermissionManagerNativeTest, testCheckPermission) {
+ pid_t selfPid = ::getpid();
+ uid_t selfUid = ::getuid();
+
+ LOG(INFO) << "testCheckPermission: uid " << selfUid << ", pid" << selfPid;
+
+ // Test is set up to force unroot by RootTargetPreparer, so we should be running as SHELL.
+ // Check some permissions SHELL should definitely have or not have.
+ int32_t result;
+ EXPECT_EQ(APermissionManager_checkPermission("android.permission.DUMP",
+ selfPid, selfUid, &result),
+ PERMISSION_MANAGER_STATUS_OK);
+ EXPECT_EQ(result, PERMISSION_MANAGER_PERMISSION_GRANTED);
+
+ EXPECT_EQ(APermissionManager_checkPermission("android.permission.MANAGE_USERS",
+ selfPid, selfUid, &result),
+ PERMISSION_MANAGER_STATUS_OK);
+ EXPECT_EQ(result, PERMISSION_MANAGER_PERMISSION_DENIED);
+
+ EXPECT_EQ(APermissionManager_checkPermission("android.permission.NETWORK_STACK",
+ selfPid, selfUid, &result),
+ PERMISSION_MANAGER_STATUS_OK);
+ EXPECT_EQ(result, PERMISSION_MANAGER_PERMISSION_DENIED);
+}
diff --git a/tests/cts/permission/permissionTestUtilLib/Android.bp b/tests/cts/permission/permissionTestUtilLib/Android.bp
new file mode 100644
index 000000000..2f7004d5f
--- /dev/null
+++ b/tests/cts/permission/permissionTestUtilLib/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "permission-test-util-lib",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ "//cts:__subpackages__",
+ ],
+ static_libs: [
+ "androidx.test.uiautomator_uiautomator",
+ "compatibility-device-util-axt",
+ "androidx.test.ext.junit-nodeps",
+ ],
+
+ sdk_version: "test_current",
+}
diff --git a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerHelperRule.kt b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerHelperRule.kt
new file mode 100644
index 000000000..acdf55ef1
--- /dev/null
+++ b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerHelperRule.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.content.ComponentName
+import android.content.Context
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/** Rule that enables and disables the CTS NotificationListenerService */
+class CtsNotificationListenerHelperRule(context: Context) : TestRule {
+
+ private val notificationListenerComponentName =
+ ComponentName(context, CtsNotificationListenerService::class.java)
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ try {
+ // Allow NLS used to verify notifications sent
+ SystemUtil.runShellCommand(
+ ALLOW_NLS_COMMAND + notificationListenerComponentName.flattenToString()
+ )
+
+ base.evaluate()
+ } finally {
+ // Disallow NLS used to verify notifications sent
+ SystemUtil.runShellCommand(
+ DISALLOW_NLS_COMMAND + notificationListenerComponentName.flattenToString()
+ )
+ }
+ }
+ }
+ }
+
+ companion object {
+ private const val ALLOW_NLS_COMMAND = "cmd notification allow_listener "
+ private const val DISALLOW_NLS_COMMAND = "cmd notification disallow_listener "
+ }
+}
diff --git a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerService.java b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerService.java
new file mode 100644
index 000000000..6ffdd6fcf
--- /dev/null
+++ b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerService.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.service.notification.NotificationListenerService;
+import android.util.Log;
+
+/**
+ * Implementation of {@link NotificationListenerService} for CTS tests.
+ *
+ * <p>In order to use this service in a test suite, ensure this service is declared in the test
+ * suite's AndroidManifest.xml as follows:
+ *
+ * <pre>{@code
+ * <service android:name="android.permission.cts.CtsNotificationListenerService"
+ * android:exported="true"
+ * android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.service.notification.NotificationListenerService"/>
+ * </intent-filter>
+ * </service>
+ * }</pre>
+ */
+public class CtsNotificationListenerService extends NotificationListenerService {
+ private static final String LOG_TAG = CtsNotificationListenerService.class.getSimpleName();
+
+ private static final Object sLock = new Object();
+
+ private static CtsNotificationListenerService sService;
+
+ @Override
+ public void onListenerConnected() {
+ Log.i(LOG_TAG, "connected");
+ synchronized (sLock) {
+ sService = this;
+ sLock.notifyAll();
+ }
+ }
+
+ public static NotificationListenerService getInstance() throws Exception {
+ synchronized (sLock) {
+ if (sService == null) {
+ sLock.wait(5000);
+ }
+
+ return sService;
+ }
+ }
+
+ @Override
+ public void onListenerDisconnected() {
+ Log.i(LOG_TAG, "disconnected");
+
+ synchronized (sLock) {
+ sService = null;
+ }
+ }
+}
diff --git a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerServiceUtils.kt b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerServiceUtils.kt
new file mode 100644
index 000000000..15d091f72
--- /dev/null
+++ b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/CtsNotificationListenerServiceUtils.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.permission.cts.TestUtils.ensure
+import android.permission.cts.TestUtils.eventually
+import android.service.notification.StatusBarNotification
+import org.junit.Assert
+
+object CtsNotificationListenerServiceUtils {
+
+ private const val NOTIFICATION_CANCELLATION_TIMEOUT_MILLIS = 5000L
+ private const val NOTIFICATION_WAIT_MILLIS = 2000L
+
+ @JvmStatic
+ fun assertEmptyNotification(packageName: String, notificationId: Int) {
+ ensure(
+ {
+ Assert.assertNull(
+ "Expected no notification",
+ getNotification(packageName, notificationId)
+ )
+ },
+ NOTIFICATION_WAIT_MILLIS
+ )
+ }
+
+ @JvmStatic
+ fun assertNotificationExist(packageName: String, notificationId: Int) {
+ eventually(
+ {
+ Assert.assertNotNull(
+ "Expected notification, none found",
+ getNotification(packageName, notificationId)
+ )
+ },
+ NOTIFICATION_WAIT_MILLIS
+ )
+ }
+
+ @JvmStatic
+ fun cancelNotification(packageName: String, notificationId: Int) {
+ val notificationService = CtsNotificationListenerService.getInstance()
+ val notification = getNotification(packageName, notificationId)
+ if (notification != null) {
+ notificationService.cancelNotification(notification.key)
+ eventually(
+ { Assert.assertTrue(getNotification(packageName, notificationId) == null) },
+ NOTIFICATION_CANCELLATION_TIMEOUT_MILLIS
+ )
+ }
+ }
+
+ @JvmStatic
+ fun cancelNotifications(packageName: String) {
+ val notificationService = CtsNotificationListenerService.getInstance()
+ val notifications = getNotifications(packageName)
+ if (notifications.isNotEmpty()) {
+ notifications.forEach { notification ->
+ notificationService.cancelNotification(notification.key)
+ }
+ eventually(
+ { Assert.assertTrue(getNotifications(packageName).isEmpty()) },
+ NOTIFICATION_CANCELLATION_TIMEOUT_MILLIS
+ )
+ }
+ }
+
+ @JvmStatic
+ fun getNotification(packageName: String, notificationId: Int): StatusBarNotification? {
+ return getNotifications(packageName).firstOrNull { it.id == notificationId }
+ }
+
+ @JvmStatic
+ fun getNotifications(packageName: String): List<StatusBarNotification> {
+ val notifications: MutableList<StatusBarNotification> = ArrayList()
+ val notificationService = CtsNotificationListenerService.getInstance()
+ for (notification in notificationService.activeNotifications) {
+ if (notification.packageName == packageName) {
+ notifications.add(notification)
+ }
+ }
+ return notifications
+ }
+
+ /**
+ * Get a notification listener notification that is currently visible.
+ *
+ * @param cancelNotification if `true` the notification is canceled inside this method
+ * @return The notification or `null` if there is none
+ */
+ @JvmStatic
+ @Throws(Throwable::class)
+ fun getNotificationForPackageAndId(
+ pkg: String,
+ id: Int,
+ cancelNotification: Boolean
+ ): StatusBarNotification? {
+ val notifications: List<StatusBarNotification> = getNotifications(pkg)
+ if (notifications.isEmpty()) {
+ return null
+ }
+ for (notification in notifications) {
+ if (notification.id == id) {
+ if (cancelNotification) {
+ cancelNotification(pkg, id)
+ }
+ return notification
+ }
+ }
+ return null
+ }
+}
diff --git a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/MtsIgnore.java b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/MtsIgnore.java
new file mode 100644
index 000000000..54c0c9a9c
--- /dev/null
+++ b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/MtsIgnore.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface MtsIgnore {
+ /**
+ * An optional bug number associated with the test. -1 Means that no bug number is associated.
+ *
+ * @return int
+ */
+ int bugId() default -1;
+
+ /**
+ * Details, such as the reason of why we're ignoring the test.
+ *
+ * @return String
+ */
+ String detail() default "";
+}
diff --git a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
new file mode 100644
index 000000000..6bbf8b52e
--- /dev/null
+++ b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY;
+import static android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS;
+import static android.Manifest.permission.MANAGE_APP_OPS_MODES;
+import static android.Manifest.permission.PACKAGE_USAGE_STATS;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OPSTR_GET_USAGE_STATS;
+import static android.app.AppOpsManager.permissionToOp;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.permission.cts.TestUtils.awaitJobUntilRequestedState;
+
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.waitForBroadcastDispatch;
+
+import android.app.AppOpsManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.modules.utils.build.SdkLevel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Common utils for permission tests
+ */
+public class PermissionUtils {
+ private static final int TESTED_FLAGS = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED
+ | FLAG_PERMISSION_REVOKE_ON_UPGRADE | FLAG_PERMISSION_REVIEW_REQUIRED
+ | FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+
+ private static final String LOG_TAG = PermissionUtils.class.getSimpleName();
+ private static final Context sContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final UiAutomation sUiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
+ private PermissionUtils() {
+ // this class should never be instantiated
+ }
+
+ /**
+ * Get the state of an app-op.
+ *
+ * @param packageName The package the app-op belongs to
+ * @param permission The permission the app-op belongs to
+ *
+ * @return The mode the op is on
+ */
+ public static int getAppOp(@NonNull String packageName, @NonNull String permission)
+ throws Exception {
+ return sContext.getSystemService(AppOpsManager.class).unsafeCheckOpRaw(
+ permissionToOp(permission),
+ sContext.getPackageManager().getPackageUid(packageName, 0), packageName);
+ }
+
+ /**
+ * Install an APK.
+ *
+ * @param apkFile The apk to install
+ */
+ public static void install(@NonNull String apkFile) {
+ final int sdkVersion = Build.VERSION.SDK_INT
+ + (Build.VERSION.RELEASE_OR_CODENAME.equals("REL") ? 0 : 1);
+ boolean forceQueryable = sdkVersion > Build.VERSION_CODES.Q;
+ runShellCommandOrThrow("pm install -r --force-sdk "
+ + (SdkLevel.isAtLeastU() ? "--bypass-low-target-sdk-block " : "")
+ + (forceQueryable ? "--force-queryable " : "")
+ + apkFile);
+ }
+
+ /**
+ * Uninstall a package.
+ *
+ * @param packageName Name of package to be uninstalled
+ */
+ public static void uninstallApp(@NonNull String packageName) {
+ runShellCommand("pm uninstall " + packageName);
+ }
+
+ /**
+ * Set a new state for an app-op (using the permission-name)
+ *
+ * @param packageName The package the app-op belongs to
+ * @param permission The permission the app-op belongs to
+ * @param mode The new mode
+ */
+ public static void setAppOp(@NonNull String packageName, @NonNull String permission, int mode) {
+ setAppOpByName(packageName, permissionToOp(permission), mode);
+ }
+
+ /**
+ * Set a new state for an app-op (using the app-op-name)
+ *
+ * @param packageName The package the app-op belongs to
+ * @param op The name of the op
+ * @param mode The new mode
+ */
+ public static void setAppOpByName(@NonNull String packageName, @NonNull String op, int mode) {
+ runWithShellPermissionIdentity(
+ () -> sContext.getSystemService(AppOpsManager.class).setUidMode(op,
+ sContext.getPackageManager().getPackageUid(packageName, 0), mode),
+ MANAGE_APP_OPS_MODES);
+ }
+
+ /**
+ * Checks a permission. Does <u>not</u> check the appOp.
+ *
+ * <p>Users should use {@link #isGranted} instead.
+ *
+ * @param packageName The package that might have the permission granted
+ * @param permission The permission that might be granted
+ *
+ * @return {@code true} iff the permission is granted
+ */
+ public static boolean isPermissionGranted(@NonNull String packageName,
+ @NonNull String permission) throws Exception {
+ return sContext.checkPermission(permission, Process.myPid(),
+ sContext.getPackageManager().getPackageUid(packageName, 0))
+ == PERMISSION_GRANTED;
+ }
+
+ /**
+ * Checks if a permission is granted for a package.
+ *
+ * <p>This correctly handles pre-M apps by checking the app-ops instead.
+ * <p>This also correctly handles the location background permission, but does not handle any
+ * other background permission
+ *
+ * @param packageName The package that might have the permission granted
+ * @param permission The permission that might be granted
+ *
+ * @return {@code true} iff the permission is granted
+ */
+ public static boolean isGranted(@NonNull String packageName, @NonNull String permission)
+ throws Exception {
+ if (!isPermissionGranted(packageName, permission)) {
+ return false;
+ }
+
+ if (permission.equals(ACCESS_BACKGROUND_LOCATION)) {
+ // The app-op for background location is encoded into the mode of the foreground
+ // location
+ return getAppOp(packageName, ACCESS_COARSE_LOCATION) == MODE_ALLOWED;
+ } else {
+ int mode = getAppOp(packageName, permission);
+ return mode == MODE_ALLOWED || mode == MODE_FOREGROUND;
+ }
+ }
+
+ /**
+ * Grant a permission to an app.
+ *
+ * <p>This correctly handles pre-M apps by setting the app-ops.
+ * <p>This also correctly handles the location background permission, but does not handle any
+ * other background permission
+ *
+ * @param packageName The app that should have the permission granted
+ * @param permission The permission to grant
+ */
+ public static void grantPermission(@NonNull String packageName, @NonNull String permission)
+ throws Exception {
+ sUiAutomation.grantRuntimePermission(packageName, permission);
+
+ if (permission.equals(ACCESS_BACKGROUND_LOCATION)) {
+ // The app-op for background location is encoded into the mode of the foreground
+ // location
+ if (isPermissionGranted(packageName, ACCESS_COARSE_LOCATION)) {
+ setAppOp(packageName, ACCESS_COARSE_LOCATION, MODE_ALLOWED);
+ } else {
+ setAppOp(packageName, ACCESS_COARSE_LOCATION, MODE_FOREGROUND);
+ }
+ } else if (permission.equals(ACCESS_COARSE_LOCATION)) {
+ // The app-op for location depends on the state of the bg location
+ if (isPermissionGranted(packageName, ACCESS_BACKGROUND_LOCATION)) {
+ setAppOp(packageName, ACCESS_COARSE_LOCATION, MODE_ALLOWED);
+ } else {
+ setAppOp(packageName, ACCESS_COARSE_LOCATION, MODE_FOREGROUND);
+ }
+ } else if (permission.equals(PACKAGE_USAGE_STATS)) {
+ setAppOpByName(packageName, OPSTR_GET_USAGE_STATS, MODE_ALLOWED);
+ } else if (permissionToOp(permission) != null) {
+ setAppOp(packageName, permission, MODE_ALLOWED);
+ }
+ }
+
+ /**
+ * Revoke a permission from an app.
+ *
+ * <p>This correctly handles pre-M apps by setting the app-ops.
+ * <p>This also correctly handles the location background permission, but does not handle any
+ * other background permission
+ *
+ * @param packageName The app that should have the permission revoked
+ * @param permission The permission to revoke
+ */
+ public static void revokePermission(@NonNull String packageName, @NonNull String permission)
+ throws Exception {
+ sUiAutomation.revokeRuntimePermission(packageName, permission);
+
+ if (permission.equals(ACCESS_BACKGROUND_LOCATION)) {
+ // The app-op for background location is encoded into the mode of the foreground
+ // location
+ if (isGranted(packageName, ACCESS_COARSE_LOCATION)) {
+ setAppOp(packageName, ACCESS_COARSE_LOCATION, MODE_FOREGROUND);
+ }
+ } else if (permission.equals(PACKAGE_USAGE_STATS)) {
+ setAppOpByName(packageName, OPSTR_GET_USAGE_STATS, MODE_IGNORED);
+ } else if (permissionToOp(permission) != null) {
+ setAppOp(packageName, permission, MODE_IGNORED);
+ }
+ }
+
+ /**
+ * Clear permission state (not app-op state) of package.
+ *
+ * @param packageName Package to clear
+ */
+ public static void clearAppState(@NonNull String packageName) {
+ runShellCommand("pm clear --user current " + packageName);
+ }
+
+ /**
+ * Get all the flags of a permission.
+ *
+ * @param packageName Package the permission belongs to
+ * @param permission Name of the permission
+ *
+ * @return Permission flags
+ */
+ public static int getAllPermissionFlags(@NonNull String packageName,
+ @NonNull String permission) {
+ try {
+ return callWithShellPermissionIdentity(
+ () -> sContext.getPackageManager().getPermissionFlags(permission, packageName,
+ UserHandle.getUserHandleForUid(Process.myUid())),
+ GRANT_RUNTIME_PERMISSIONS);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Get the flags of a permission.
+ *
+ * @param packageName Package the permission belongs to
+ * @param permission Name of the permission
+ *
+ * @return Permission flags
+ */
+ public static int getPermissionFlags(@NonNull String packageName, @NonNull String permission) {
+ return getAllPermissionFlags(packageName, permission) & TESTED_FLAGS;
+ }
+
+ /**
+ * Set the flags of a permission.
+ *
+ * @param packageName Package the permission belongs to
+ * @param permission Name of the permission
+ * @param mask Mask of permissions to set
+ * @param flags Permissions to set
+ */
+ public static void setPermissionFlags(@NonNull String packageName, @NonNull String permission,
+ int mask, int flags) {
+ runWithShellPermissionIdentity(
+ () -> sContext.getPackageManager().updatePermissionFlags(permission, packageName,
+ mask, flags, UserHandle.getUserHandleForUid(Process.myUid())),
+ GRANT_RUNTIME_PERMISSIONS, ADJUST_RUNTIME_PERMISSIONS_POLICY);
+ }
+
+ /**
+ * Get all permissions an app requests. This includes the split permissions.
+ *
+ * @param packageName The package that requests the permissions.
+ *
+ * @return The permissions requested by the app
+ */
+ public static @NonNull List<String> getPermissions(@NonNull String packageName)
+ throws Exception {
+ PackageInfo appInfo = sContext.getPackageManager().getPackageInfo(packageName,
+ GET_PERMISSIONS);
+
+ return Arrays.asList(appInfo.requestedPermissions);
+ }
+
+ /**
+ * Get all runtime permissions that an app requests. This includes the split permissions.
+ *
+ * @param packageName The package that requests the permissions.
+ *
+ * @return The runtime permissions requested by the app
+ */
+ public static @NonNull List<String> getRuntimePermissions(@NonNull String packageName)
+ throws Exception {
+ ArrayList<String> runtimePermissions = new ArrayList<>();
+
+ for (String perm : getPermissions(packageName)) {
+ PermissionInfo info = sContext.getPackageManager().getPermissionInfo(perm, 0);
+ if ((info.getProtection() & PROTECTION_DANGEROUS) != 0) {
+ runtimePermissions.add(perm);
+ }
+ }
+
+ return runtimePermissions;
+ }
+
+ /**
+ * Reset permission controller state & re-schedule the job.
+ */
+ public static void resetPermissionControllerJob(@NonNull UiAutomation automation,
+ @NonNull String packageName, int jobId, long timeout, @NonNull String intentAction,
+ @NonNull String onBootReceiver) throws Exception {
+ clearAppState(packageName);
+ awaitJobUntilRequestedState(packageName, jobId, timeout, automation, "unknown");
+ scheduleJob(automation, packageName, jobId, timeout, intentAction, onBootReceiver);
+
+ runShellCommand("cmd jobscheduler reset-execution-quota -u "
+ + Process.myUserHandle().getIdentifier() + " " + packageName);
+ runShellCommand("cmd jobscheduler reset-schedule-quota");
+ }
+
+ /**
+ * schedules a job for the privacy signal in Permission Controller
+ */
+ public static void scheduleJob(@NonNull UiAutomation automation,
+ @NonNull String packageName, int jobId, long timeout, @NonNull String intentAction,
+ @NonNull String broadcastReceiver) throws Exception {
+ long startTime = System.currentTimeMillis();
+ String jobStatus = "";
+ simulateReboot(packageName, intentAction, broadcastReceiver);
+
+ while ((System.currentTimeMillis() - startTime) < timeout
+ && !jobStatus.contains("waiting")) {
+ String cmd =
+ "cmd jobscheduler get-job-state -u " + Process.myUserHandle().getIdentifier()
+ + " " + packageName + " " + jobId;
+ jobStatus = runShellCommand(automation, cmd).trim();
+ Log.v(LOG_TAG, "Job: " + jobId + ", job status " + jobStatus);
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ // ignore interrupt
+ }
+ }
+ if (!jobStatus.contains("waiting")) {
+ throw new IllegalStateException("The job didn't get scheduled in time.");
+ }
+ }
+
+ private static void simulateReboot(@NonNull String packageName, @NonNull String intentAction,
+ @NonNull String broadcastReceiver) {
+ Intent jobSetupReceiverIntent = new Intent(intentAction);
+ jobSetupReceiverIntent.setPackage(packageName);
+ jobSetupReceiverIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+
+ // Query for the setup broadcast receiver
+ List<ResolveInfo> resolveInfos =
+ sContext.getPackageManager().queryBroadcastReceivers(jobSetupReceiverIntent, 0);
+
+ if (resolveInfos.size() > 0) {
+ sContext.sendBroadcast(jobSetupReceiverIntent);
+ } else {
+ Intent intent = new Intent();
+ intent.setClassName(packageName, broadcastReceiver);
+ intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.setPackage(packageName);
+ sContext.sendBroadcast(intent);
+ }
+ waitForBroadcastDispatch(intentAction);
+ }
+}
diff --git a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java
new file mode 100644
index 000000000..48ccbe79f
--- /dev/null
+++ b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import android.app.UiAutomation;
+import android.os.Process;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assert;
+
+/** Common test utilities */
+public class TestUtils {
+ private static final String LOG_TAG = TestUtils.class.getSimpleName();
+
+ /**
+ * A {@link java.util.concurrent.Callable} that can throw a {@link Throwable}
+ */
+ public interface ThrowingCallable<T> {
+ T call() throws Throwable;
+ }
+
+ /**
+ * A {@link Runnable} that can throw a {@link Throwable}
+ */
+ public interface ThrowingRunnable {
+ void run() throws Throwable;
+ }
+
+ /**
+ * Make sure that a {@link ThrowingRunnable} finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingRunnable} to run.
+ * @param timeout the maximum time to wait
+ */
+ public static void ensure(@NonNull ThrowingRunnable r, long timeout) throws Throwable {
+ ensure(() -> {
+ r.run();
+ return 0;
+ }, timeout);
+ }
+
+ /**
+ * Make sure that a {@link ThrowingCallable} finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingCallable} to run.
+ * @param timeout the maximum time to wait
+ * @return the return value from the callable
+ * @throws NullPointerException If the return value never becomes non-null
+ */
+ public static <T> T ensure(@NonNull ThrowingCallable<T> r, long timeout) throws Throwable {
+ long start = System.currentTimeMillis();
+
+ while (true) {
+ T res = r.call();
+ if (res == null) {
+ throw new NullPointerException("No result");
+ }
+
+ if (System.currentTimeMillis() - start < timeout) {
+ Thread.sleep(500);
+ } else {
+ return res;
+ }
+ }
+ }
+
+ /**
+ * Make sure that a {@link ThrowingRunnable} eventually finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingRunnable} to run.
+ * @param timeout the maximum time to wait
+ */
+ public static void eventually(@NonNull ThrowingRunnable r, long timeout) throws Throwable {
+ eventually(() -> {
+ r.run();
+ return 0;
+ }, timeout);
+ }
+
+ /**
+ * Make sure that a {@link ThrowingCallable} eventually finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingCallable} to run.
+ * @param timeout the maximum time to wait
+ * @return the return value from the callable
+ * @throws NullPointerException If the return value never becomes non-null
+ */
+ public static <T> T eventually(@NonNull ThrowingCallable<T> r, long timeout) throws Throwable {
+ long start = System.currentTimeMillis();
+
+ while (true) {
+ try {
+ T res = r.call();
+ if (res == null) {
+ throw new NullPointerException("No result");
+ }
+
+ return res;
+ } catch (Throwable e) {
+ if (System.currentTimeMillis() - start < timeout) {
+ Log.d(LOG_TAG, "Ignoring exception, occurred within valid wait time", e);
+
+ Thread.sleep(500);
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Run the job and then wait for completion
+ */
+ public static void runJobAndWaitUntilCompleted(
+ String packageName,
+ int jobId, long timeout) {
+ runJobAndWaitUntilCompleted(packageName, jobId, timeout,
+ InstrumentationRegistry.getInstrumentation().getUiAutomation());
+ }
+
+ /**
+ * Run the job and then wait for completion
+ */
+ public static void runJobAndWaitUntilCompleted(
+ String packageName,
+ int jobId,
+ long timeout,
+ UiAutomation automation) {
+ String runJobCmd = "cmd jobscheduler run -u " + Process.myUserHandle().getIdentifier()
+ + " -f " + packageName + " " + jobId;
+ try {
+ String result = runShellCommand(automation, runJobCmd);
+ Log.v(LOG_TAG, "jobscheduler run job command output: " + result);
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ // waiting state is expected after completion for the periodic jobs.
+ awaitJobUntilRequestedState(packageName, jobId, timeout, automation, "waiting");
+ }
+
+ public static void awaitJobUntilRequestedState(
+ String packageName,
+ int jobId,
+ long timeout,
+ UiAutomation automation,
+ String requestedState) {
+ String statusCmd = "cmd jobscheduler get-job-state -u "
+ + Process.myUserHandle().getIdentifier() + " " + packageName + " " + jobId;
+ try {
+ eventually(() -> {
+ String jobState = runShellCommand(automation, statusCmd).trim();
+ Assert.assertTrue("The job doesn't have requested state " + requestedState
+ + " yet, current state: " + jobState, jobState.startsWith(requestedState));
+ }, timeout);
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void awaitJobUntilRequestedState(
+ String packageName,
+ int jobId,
+ long timeout,
+ UiAutomation automation,
+ String requestedState1,
+ String requestedState2) {
+ String statusCmd = "cmd jobscheduler get-job-state -u "
+ + Process.myUserHandle().getIdentifier() + " " + packageName + " " + jobId;
+ try {
+ eventually(() -> {
+ String jobState = runShellCommand(automation, statusCmd).trim();
+ boolean jobInEitherRequestedState = jobState.startsWith(requestedState1)
+ || jobState.startsWith(requestedState2);
+ Assert.assertTrue("The job doesn't have requested state "
+ + "(" + requestedState1 + " or " + requestedState2 + ")"
+ + " yet, current state: " + jobState, jobInEitherRequestedState);
+ }, timeout);
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/tests/cts/permission/res/drawable/robot.png b/tests/cts/permission/res/drawable/robot.png
new file mode 100644
index 000000000..8a9e6984b
--- /dev/null
+++ b/tests/cts/permission/res/drawable/robot.png
Binary files differ
diff --git a/tests/cts/permission/res/values/strings.xml b/tests/cts/permission/res/values/strings.xml
new file mode 100644
index 000000000..bebb179ec
--- /dev/null
+++ b/tests/cts/permission/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="perm_b">Permission B</string>
+ <string name="perm_c">Permission C</string>
+ <string name="perm_group_b">Permission group B</string>
+ <string name="perm_group_c">Permission group B</string>
+</resources>
diff --git a/tests/cts/permission/res/xml/test_accessibilityservice.xml b/tests/cts/permission/res/xml/test_accessibilityservice.xml
new file mode 100644
index 000000000..fa87e2e0f
--- /dev/null
+++ b/tests/cts/permission/res/xml/test_accessibilityservice.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accessibilityEventTypes="typeAllMask"
+ android:accessibilityFeedbackType="feedbackGeneric"
+ android:canRetrieveWindowContent="true"
+ android:accessibilityFlags="flagDefault"
+ android:notificationTimeout="0" />
diff --git a/tests/cts/permission/sdk28/Android.bp b/tests/cts/permission/sdk28/Android.bp
new file mode 100644
index 000000000..2bdffabe5
--- /dev/null
+++ b/tests/cts/permission/sdk28/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsPermissionTestCasesSdk28",
+ defaults: ["cts_defaults"],
+ sdk_version: "28",
+ srcs: ["src/**/*.java"],
+ static_libs: ["ctstestrunner-axt"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "mcts-permission",
+ ],
+}
diff --git a/tests/cts/permission/sdk28/AndroidManifest.xml b/tests/cts/permission/sdk28/AndroidManifest.xml
new file mode 100644
index 000000000..1714052f7
--- /dev/null
+++ b/tests/cts/permission/sdk28/AndroidManifest.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.sdk28">
+
+ <uses-sdk android:minSdkVersion="3"
+ android:targetSdkVersion="28"
+ android:maxSdkVersion="28"/>
+
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="android.permission.cts.PermissionStubActivity"
+ android:label="PermissionStubActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <!--
+ The CTS stubs package cannot be used as the target application here,
+ since that requires many permissions to be set. Instead, specify this
+ package itself as the target and include any stub activities needed.
+
+ This test package uses the default InstrumentationTestRunner, because
+ the InstrumentationCtsTestRunner is only available in the stubs
+ package. That runner cannot be added to this package either, since it
+ relies on hidden APIs.
+ -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.permission.cts.sdk28"
+ android:label="CTS tests of legacy android permissions as of API 28">
+ </instrumentation>
+
+</manifest>
diff --git a/tests/cts/permission/sdk28/AndroidTest.xml b/tests/cts/permission/sdk28/AndroidTest.xml
new file mode 100644
index 000000000..391142964
--- /dev/null
+++ b/tests/cts/permission/sdk28/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Permission test cases for TargetSdk 28">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="permissions" />
+ <option name="not-shardable" value="true" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPermissionTestCasesSdk28.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.permission.cts.sdk28" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+</configuration>
diff --git a/tests/cts/permission/sdk28/OWNERS b/tests/cts/permission/sdk28/OWNERS
new file mode 100644
index 000000000..98dc09e9e
--- /dev/null
+++ b/tests/cts/permission/sdk28/OWNERS
@@ -0,0 +1 @@
+# Bug component: 137825
diff --git a/tests/cts/permission/sdk28/TEST_MAPPING b/tests/cts/permission/sdk28/TEST_MAPPING
new file mode 100644
index 000000000..b98bbaf43
--- /dev/null
+++ b/tests/cts/permission/sdk28/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsPermissionTestCasesSdk28"
+ }
+ ]
+}
diff --git a/tests/cts/permission/sdk28/res/values/strings.xml b/tests/cts/permission/sdk28/res/values/strings.xml
new file mode 100644
index 000000000..9cc70f91a
--- /dev/null
+++ b/tests/cts/permission/sdk28/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="sdk28">SDK Level 28</string>
+</resources>
diff --git a/tests/cts/permission/sdk28/src/android/permission/cts/sdk28/RequestLocation.java b/tests/cts/permission/sdk28/src/android/permission/cts/sdk28/RequestLocation.java
new file mode 100644
index 000000000..8ba39cdfe
--- /dev/null
+++ b/tests/cts/permission/sdk28/src/android/permission/cts/sdk28/RequestLocation.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.sdk28;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.telephony.NeighboringCellInfo;
+import android.telephony.TelephonyManager;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class RequestLocation {
+
+ private TelephonyManager mTelephonyManager;
+ private boolean mHasTelephony;
+
+ @Before
+ public void setUp() throws Exception {
+ mHasTelephony = getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY);
+ mTelephonyManager = (TelephonyManager) getContext().getSystemService(
+ Context.TELEPHONY_SERVICE);
+ assertNotNull(mTelephonyManager);
+ }
+
+ /**
+ * Verify that a SecurityException is thrown when an app targeting SDK 28
+ * lacks the coarse location permission.
+ */
+ @Test
+ public void testGetNeighboringCellInfo() {
+ if (!mHasTelephony) return;
+ try {
+ List<NeighboringCellInfo> cellInfos = mTelephonyManager.getNeighboringCellInfo();
+ if (cellInfos != null && !cellInfos.isEmpty()) {
+ fail("Meaningful information returned from getNeighboringCellInfo!");
+ }
+ } catch (SecurityException expected) {
+ }
+ }
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt b/tests/cts/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
new file mode 100644
index 000000000..e7bad2b05
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService
+import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule
+import android.app.ActivityOptions
+import android.app.Instrumentation
+import android.app.UiAutomation
+import android.content.ComponentName
+import android.content.Context
+import android.os.Build
+import android.os.Process
+import android.permission.cts.CtsNotificationListenerServiceUtils.assertEmptyNotification
+import android.permission.cts.CtsNotificationListenerServiceUtils.assertNotificationExist
+import android.permission.cts.CtsNotificationListenerServiceUtils.cancelNotification
+import android.permission.cts.CtsNotificationListenerServiceUtils.cancelNotifications
+import android.permission.cts.CtsNotificationListenerServiceUtils.getNotification
+import android.permission.cts.SafetyCenterUtils.assertSafetyCenterIssueDoesNotExist
+import android.permission.cts.SafetyCenterUtils.assertSafetyCenterIssueExist
+import android.permission.cts.SafetyCenterUtils.assertSafetyCenterStarted
+import android.permission.cts.SafetyCenterUtils.deleteDeviceConfigPrivacyProperty
+import android.permission.cts.SafetyCenterUtils.deviceSupportsSafetyCenter
+import android.permission.cts.SafetyCenterUtils.setDeviceConfigPrivacyProperty
+import android.platform.test.annotations.AppModeFull
+import android.platform.test.rule.ScreenRecordRule
+import android.provider.DeviceConfig
+import android.safetycenter.SafetyCenterManager
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.modules.utils.build.SdkLevel
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@AppModeFull(
+ reason =
+ "Cannot set system settings as instant app. Also we never show an accessibility " +
+ "notification for instant apps."
+)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+@ScreenRecordRule.ScreenRecord
+@FlakyTest
+class AccessibilityPrivacySourceTest {
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context: Context = instrumentation.targetContext
+ private val permissionControllerPackage = context.packageManager.permissionControllerPackageName
+ private val accessibilityTestService =
+ ComponentName(context, AccessibilityTestService::class.java).flattenToString()
+ private val safetyCenterIssueId = "accessibility_$accessibilityTestService"
+ private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)
+
+ @get:Rule val screenRecordRule = ScreenRecordRule(false, false)
+
+ @get:Rule
+ val mAccessibilityServiceRule =
+ InstrumentedAccessibilityServiceTestRule(AccessibilityTestService::class.java, false)
+
+ @get:Rule
+ val deviceConfigSafetyCenterEnabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SAFETY_CENTER_ENABLED,
+ true.toString()
+ )
+
+ @get:Rule
+ val deviceConfigA11ySourceEnabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ ACCESSIBILITY_SOURCE_ENABLED,
+ true.toString()
+ )
+
+ @get:Rule
+ val deviceConfigA11yListenerDisabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ ACCESSIBILITY_LISTENER_ENABLED,
+ false.toString()
+ )
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(deviceSupportsSafetyCenter(context))
+ InstrumentedAccessibilityService.disableAllServices()
+ runShellCommand("input keyevent KEYCODE_WAKEUP")
+ resetPermissionController()
+ // Bypass battery saving restrictions
+ runShellCommand(
+ "cmd tare set-vip " +
+ "${Process.myUserHandle().identifier} $permissionControllerPackage true"
+ )
+ cancelNotifications(permissionControllerPackage)
+ assertEmptyNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ runWithShellPermissionIdentity { safetyCenterManager?.clearAllSafetySourceDataForTests() }
+ assertSafetyCenterIssueDoesNotExist(
+ SC_ACCESSIBILITY_SOURCE_ID,
+ safetyCenterIssueId,
+ SC_ACCESSIBILITY_ISSUE_TYPE_ID
+ )
+ }
+
+ @After
+ fun cleanup() {
+ cancelNotifications(permissionControllerPackage)
+ // Reset battery saving restrictions
+ runShellCommand(
+ "cmd tare set-vip " +
+ "${Process.myUserHandle().identifier} $permissionControllerPackage default"
+ )
+ runWithShellPermissionIdentity { safetyCenterManager?.clearAllSafetySourceDataForTests() }
+ }
+
+ @Test
+ fun testJobSendsNotification() {
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertNotificationExist(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ }
+
+ @Test
+ fun testJobSendsNotificationOnEnable() {
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertNotificationExist(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_LISTENER_ENABLED, true.toString())
+ cancelNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ InstrumentedAccessibilityService.disableAllServices()
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_LISTENER_ENABLED, false.toString())
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_JOB_INTERVAL_MILLIS, "0")
+
+ // enable service again and verify a notification
+ try {
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertNotificationExist(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ } finally {
+ deleteDeviceConfigPrivacyProperty(ACCESSIBILITY_JOB_INTERVAL_MILLIS)
+ }
+ }
+
+ @Test
+ fun testJobSendsIssuesToSafetyCenter() {
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertSafetyCenterIssueExist(
+ SC_ACCESSIBILITY_SOURCE_ID,
+ safetyCenterIssueId,
+ SC_ACCESSIBILITY_ISSUE_TYPE_ID
+ )
+ }
+
+ @Test
+ fun testJobDoesNotSendNotificationInSecondRunForSameService() {
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertNotificationExist(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+
+ cancelNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+
+ runJobAndWaitUntilCompleted()
+ assertEmptyNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ }
+
+ @Test
+ fun testAccessibilityListenerSendsIssueToSafetyCenter() {
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_LISTENER_ENABLED, true.toString())
+ try {
+ val automation = getAutomation()
+ mAccessibilityServiceRule.enableService()
+ TestUtils.eventually(
+ {
+ assertSafetyCenterIssueExist(
+ SC_ACCESSIBILITY_SOURCE_ID,
+ safetyCenterIssueId,
+ SC_ACCESSIBILITY_ISSUE_TYPE_ID,
+ automation
+ )
+ },
+ TIMEOUT_MILLIS
+ )
+ automation.destroy()
+ } finally {
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_LISTENER_ENABLED, false.toString())
+ }
+ }
+
+ @Test
+ fun testJobWithDisabledServiceDoesNotSendNotification() {
+ runJobAndWaitUntilCompleted()
+ assertEmptyNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ }
+
+ @Test
+ fun testJobWithDisabledServiceDoesNotSendIssueToSafetyCenter() {
+ runJobAndWaitUntilCompleted()
+ assertSafetyCenterIssueDoesNotExist(
+ SC_ACCESSIBILITY_SOURCE_ID,
+ safetyCenterIssueId,
+ SC_ACCESSIBILITY_ISSUE_TYPE_ID
+ )
+ }
+
+ @Test
+ fun testJobWithAccessibilityFeatureDisabledDoesNotSendNotification() {
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_SOURCE_ENABLED, false.toString())
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertEmptyNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ }
+
+ @Test
+ fun testJobWithAccessibilityFeatureDisabledDoesNotSendIssueToSafetyCenter() {
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_SOURCE_ENABLED, false.toString())
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertSafetyCenterIssueDoesNotExist(
+ SC_ACCESSIBILITY_SOURCE_ID,
+ safetyCenterIssueId,
+ SC_ACCESSIBILITY_ISSUE_TYPE_ID
+ )
+ }
+
+ @Test
+ fun testJobWithSafetyCenterDisabledDoesNotSendNotification() {
+ setDeviceConfigPrivacyProperty(SAFETY_CENTER_ENABLED, false.toString())
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertEmptyNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ }
+
+ @Test
+ fun testJobWithSafetyCenterDisabledDoesNotSendIssueToSafetyCenter() {
+ setDeviceConfigPrivacyProperty(SAFETY_CENTER_ENABLED, false.toString())
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertSafetyCenterIssueDoesNotExist(
+ SC_ACCESSIBILITY_SOURCE_ID,
+ safetyCenterIssueId,
+ SC_ACCESSIBILITY_ISSUE_TYPE_ID
+ )
+ }
+
+ @Test
+ fun testNotificationClickOpenSafetyCenter() {
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertNotificationExist(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ val statusBarNotification =
+ getNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ Assert.assertNotNull(statusBarNotification)
+ val contentIntent = statusBarNotification!!.notification.contentIntent
+ if (SdkLevel.isAtLeastU()) {
+ val options =
+ ActivityOptions.makeBasic()
+ .setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ )
+ contentIntent.send(
+ /* context = */ null,
+ /* code = */ 0,
+ /* intent = */ null,
+ /* onFinished = */ null,
+ /* handler = */ null,
+ /* requiredPermission = */ null,
+ /* options = */ options.toBundle()
+ )
+ } else {
+ contentIntent.send()
+ }
+ assertSafetyCenterStarted()
+ }
+
+ private fun getAutomation(): UiAutomation {
+ return instrumentation.getUiAutomation(
+ UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES
+ )
+ }
+
+ private fun runJobAndWaitUntilCompleted() {
+ TestUtils.runJobAndWaitUntilCompleted(
+ permissionControllerPackage,
+ ACCESSIBILITY_JOB_ID,
+ TIMEOUT_MILLIS,
+ getAutomation()
+ )
+ }
+
+ /** Reset the permission controllers state. */
+ @Throws(Throwable::class)
+ private fun resetPermissionController() {
+ PermissionUtils.resetPermissionControllerJob(
+ getAutomation(),
+ permissionControllerPackage,
+ ACCESSIBILITY_JOB_ID,
+ 45000,
+ ACTION_SET_UP_ACCESSIBILITY_CHECK,
+ AccessibilityOnBootReceiver
+ )
+ }
+
+ companion object {
+ private const val SC_ACCESSIBILITY_SOURCE_ID = "AndroidAccessibility"
+ private const val ACCESSIBILITY_SOURCE_ENABLED = "sc_accessibility_source_enabled"
+ private const val SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
+ private const val ACCESSIBILITY_LISTENER_ENABLED = "sc_accessibility_listener_enabled"
+ private const val ACCESSIBILITY_JOB_INTERVAL_MILLIS = "sc_accessibility_job_interval_millis"
+
+ private const val ACCESSIBILITY_JOB_ID = 6
+ private const val ACCESSIBILITY_NOTIFICATION_ID = 4
+ private const val TIMEOUT_MILLIS: Long = 10000
+
+ private const val SC_ACCESSIBILITY_ISSUE_TYPE_ID = "accessibility_privacy_issue"
+
+ private const val AccessibilityOnBootReceiver =
+ "com.android.permissioncontroller.privacysources.AccessibilityOnBootReceiver"
+ private const val ACTION_SET_UP_ACCESSIBILITY_CHECK =
+ "com.android.permissioncontroller.action.SET_UP_ACCESSIBILITY_CHECK"
+
+ @get:ClassRule
+ @JvmStatic
+ val ctsNotificationListenerHelper =
+ CtsNotificationListenerHelperRule(
+ InstrumentationRegistry.getInstrumentation().targetContext
+ )
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/AccessibilityTestService.kt b/tests/cts/permission/src/android/permission/cts/AccessibilityTestService.kt
new file mode 100644
index 000000000..74e8a74ae
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/AccessibilityTestService.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService
+
+/** Test Accessibility Service */
+class AccessibilityTestService : InstrumentedAccessibilityService()
diff --git a/tests/cts/permission/src/android/permission/cts/ActivityPermissionRationaleTest.java b/tests/cts/permission/src/android/permission/cts/ActivityPermissionRationaleTest.java
new file mode 100644
index 000000000..47f011a34
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/ActivityPermissionRationaleTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.Manifest;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@AppModeFull(reason = "Tests properties of other app. Instant apps cannot interact with other apps")
+@RunWith(AndroidJUnit4ClassRunner.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+public class ActivityPermissionRationaleTest {
+ private static final String APK =
+ "/data/local/tmp/cts-permission/CtsAppThatRunsRationaleTests.apk";
+ private static final String PACKAGE_NAME = "android.permission.cts.appthatrunsrationaletests";
+ private static final String PERMISSION_NAME = Manifest.permission.READ_CONTACTS;
+ private static final String CALLBACK_KEY = "testactivitycallback";
+ private static final String RESULT_KEY = "testactivityresult";
+ private static final int TIMEOUT = 5000;
+
+ private static Context sContext = InstrumentationRegistry.getInstrumentation().getContext();
+ private static UiAutomation sUiAuto =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
+ @BeforeClass
+ public static void setUp() {
+ runShellCommandOrThrow("pm install -r " + APK);
+ int flag = PackageManager.FLAG_PERMISSION_USER_SET;
+ PermissionUtils.setPermissionFlags(PACKAGE_NAME, PERMISSION_NAME, flag, flag);
+ }
+
+ @AfterClass
+ public static void unInstallApp() {
+ runShellCommand("pm uninstall " + PACKAGE_NAME);
+ }
+
+ private void assertAppShowRationaleIs(boolean expected) throws Exception {
+ CompletableFuture<Boolean> callbackReturn = new CompletableFuture<>();
+ RemoteCallback cb = new RemoteCallback((Bundle result) ->
+ callbackReturn.complete(result.getBoolean(RESULT_KEY)));
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".TestActivity"));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(CALLBACK_KEY, cb);
+
+ sContext.startActivity(intent);
+ assertThat(callbackReturn.get(TIMEOUT, TimeUnit.MILLISECONDS)).isEqualTo(expected);
+ }
+
+ @Before
+ public void clearData() {
+ runShellCommand("pm clear --user " + sContext.getUserId()
+ + " android.permission.cts.appthatrunsrationaletests");
+ PermissionUtils.setPermissionFlags(PACKAGE_NAME, PERMISSION_NAME,
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0);
+ }
+
+ @Test
+ public void permissionGrantedNoRationale() throws Exception {
+ sUiAuto.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME);
+
+ assertAppShowRationaleIs(false);
+ }
+
+ @Test
+ public void policyFixedNoRationale() throws Exception {
+ int flags = PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+ PermissionUtils.setPermissionFlags(PACKAGE_NAME, PERMISSION_NAME, flags, flags);
+
+ assertAppShowRationaleIs(false);
+ }
+
+ @Test
+ public void userFixedNoRationale() throws Exception {
+ int flags = PackageManager.FLAG_PERMISSION_USER_FIXED;
+ PermissionUtils.setPermissionFlags(PACKAGE_NAME, PERMISSION_NAME, flags, flags);
+
+ assertAppShowRationaleIs(false);
+ }
+
+ @Test
+ public void notUserSetNoRationale() throws Exception {
+ PermissionUtils.setPermissionFlags(PACKAGE_NAME, PERMISSION_NAME,
+ PackageManager.FLAG_PERMISSION_USER_SET, 0);
+
+ assertAppShowRationaleIs(false);
+ }
+
+ @Test
+ public void userSetNeedRationale() throws Exception {
+ int flags = PackageManager.FLAG_PERMISSION_USER_SET;
+ PermissionUtils.setPermissionFlags(PACKAGE_NAME, PERMISSION_NAME, flags, flags);
+
+ assertAppShowRationaleIs(true);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/AppIdleStatePermissionTest.java b/tests/cts/permission/src/android/permission/cts/AppIdleStatePermissionTest.java
new file mode 100644
index 000000000..bba996366
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/AppIdleStatePermissionTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permission.cts;
+
+import static org.junit.Assert.fail;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Build, install and run tests with following command:
+ * atest AppIdleStatePermissionTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppIdleStatePermissionTest {
+
+ /**
+ * Verify that the {@link android.Manifest.permission#CHANGE_APP_IDLE_STATE}
+ * permission is only held by at most one package.
+ */
+ @Test
+ public void testChangeAppIdleStatePermission() throws Exception {
+ final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+ final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[]{
+ android.Manifest.permission.CHANGE_APP_IDLE_STATE
+ }, PackageManager.MATCH_SYSTEM_ONLY);
+
+ int count = 0;
+ String pkgNames = "";
+ for (PackageInfo pkg : holding) {
+ int uid = pm.getApplicationInfo(pkg.packageName, 0).uid;
+ if (UserHandle.isApp(uid)) {
+ pkgNames += pkg.packageName + "\n";
+ count++;
+ }
+ }
+ if (count > 1) {
+ fail("Only one app may hold the CHANGE_APP_IDLE_STATE permission; found packages: \n"
+ + pkgNames);
+ }
+ }
+
+ /**
+ * Verify that the {@link android.Manifest.permission#CHANGE_APP_LAUNCH_TIME_ESTIMATE}
+ * permission is only held by at most one package.
+ */
+ @Test
+ public void testChangeAppLaunchEstimatePermission() throws Exception {
+ final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+ final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[]{
+ android.Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE
+ }, PackageManager.MATCH_SYSTEM_ONLY);
+
+ int count = 0;
+ String pkgNames = "";
+ for (PackageInfo pkg : holding) {
+ int uid = pm.getApplicationInfo(pkg.packageName, 0).uid;
+ if (UserHandle.isApp(uid)) {
+ pkgNames += pkg.packageName + "\n";
+ count++;
+ }
+ }
+ if (count > 1) {
+ fail("Only one app may hold the CHANGE_APP_LAUNCH_TIME_ESTIMATE permission;"
+ + " found packages: \n" + pkgNames);
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/cts/permission/src/android/permission/cts/AppWidgetManagerPermissionTest.java b/tests/cts/permission/src/android/permission/cts/AppWidgetManagerPermissionTest.java
new file mode 100644
index 000000000..fa43bfb18
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/AppWidgetManagerPermissionTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+* Test that protected AppWidgetManager APIs cannot be called without permissions
+*/
+public class AppWidgetManagerPermissionTest extends AndroidTestCase {
+
+ private AppWidgetManager mAppWidgetManager = null;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mAppWidgetManager = AppWidgetManager.getInstance(getContext());
+ }
+
+ /**
+ * Verify that calling
+ * {@link AppWidgetManager#bindAppWidgetId(int, android.content.ComponentName)}
+ * requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#BIND_APP_WIDGET}.
+ */
+ @SmallTest
+ public void testBindAppWidget() {
+ if (!getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+ return;
+ }
+ assertNotNull(mAppWidgetManager);
+
+ try {
+ final boolean bound = mAppWidgetManager.bindAppWidgetIdIfAllowed(1,
+ new ComponentName(mContext, "foo"));
+ assertFalse("Was able to call bindAppWidgetId", bound);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/BackgroundPermissionButtonLabelTest.java b/tests/cts/permission/src/android/permission/cts/BackgroundPermissionButtonLabelTest.java
new file mode 100644
index 000000000..004f8bc8c
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/BackgroundPermissionButtonLabelTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BackgroundPermissionButtonLabelTest {
+
+ // Name of the resource which provides background permission button string
+ public static final String APP_PERMISSION_BUTTON_ALLOW_ALWAYS =
+ "app_permission_button_allow_always";
+
+ private final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private final String mPermissionController =
+ mContext.getPackageManager().getPermissionControllerPackageName();
+
+ @Test
+ public void testBackgroundPermissionButtonLabel() {
+ try {
+ Context permissionControllerContext =
+ mContext.createPackageContext(mPermissionController, 0);
+ int stringId = permissionControllerContext.getResources().getIdentifier(
+ APP_PERMISSION_BUTTON_ALLOW_ALWAYS, "string",
+ "com.android.permissioncontroller");
+
+ Assert.assertEquals(mContext.getPackageManager().getBackgroundPermissionOptionLabel(),
+ permissionControllerContext.getString(stringId));
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+}
diff --git a/tests/cts/permission/src/android/permission/cts/BackgroundPermissionsTest.java b/tests/cts/permission/src/android/permission/cts/BackgroundPermissionsTest.java
new file mode 100644
index 000000000..f3f47631c
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/BackgroundPermissionsTest.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.content.pm.PermissionInfo.PROTECTION_INTERNAL;
+import static android.permission.cts.PermissionUtils.getAppOp;
+import static android.permission.cts.PermissionUtils.grantPermission;
+import static android.permission.cts.PermissionUtils.install;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.AppOpsManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.platform.test.annotations.AppModeFull;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class BackgroundPermissionsTest {
+ private static final String LOG_TAG = BackgroundPermissionsTest.class.getSimpleName();
+
+ /** The package name of all apps used in the test */
+ private static final String APP_PKG = "android.permission.cts.appthatrequestpermission";
+
+ private static final String TMP_DIR = "/data/local/tmp/cts-permission/";
+ private static final String APK_LOCATION_BACKGROUND_29 =
+ TMP_DIR + "CtsAppThatRequestsLocationAndBackgroundPermission29.apk";
+ private static final String APK_LOCATION_29v4 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission29v4.apk";
+
+ private static final Context sContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final UiAutomation sUiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
+ @After
+ public void uninstallTestApp() {
+ uninstallApp(APP_PKG);
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages")
+ public void verifybackgroundPermissionsProperties() throws Exception {
+ PackageInfo pkg = sContext.getPackageManager().getPackageInfo(
+ "android", PackageManager.GET_PERMISSIONS);
+ ArrayMap<String, String> potentialBackgroundPermissionsToGroup = new ArrayMap<>();
+
+ int numPermissions = pkg.permissions.length;
+ for (int i = 0; i < numPermissions; i++) {
+ PermissionInfo permission = pkg.permissions[i];
+
+ // background permissions must be dangerous or ungrantable or role
+ if ((permission.getProtection() & PROTECTION_DANGEROUS) != 0
+ || (permission.getProtection() == PROTECTION_INTERNAL
+ && (permission.getProtectionFlags() == 0
+ || permission.getProtectionFlags() == PermissionInfo.PROTECTION_FLAG_ROLE))) {
+ potentialBackgroundPermissionsToGroup.put(permission.name, permission.group);
+ }
+ }
+
+ for (int i = 0; i < numPermissions; i++) {
+ PermissionInfo permission = pkg.permissions[i];
+ String backgroundPermissionName = permission.backgroundPermission;
+
+ if (backgroundPermissionName != null) {
+ Log.i(LOG_TAG, permission.name + "->" + backgroundPermissionName);
+
+ // foreground permissions must be dangerous
+ assertNotEquals(0, permission.getProtection() & PROTECTION_DANGEROUS);
+
+ // All foreground permissions need an app op
+ assertNotNull(AppOpsManager.permissionToOp(permission.name));
+
+ // the background permission must exist
+ assertTrue(potentialBackgroundPermissionsToGroup
+ .containsKey(backgroundPermissionName));
+ }
+ }
+ }
+
+ /**
+ * If a bg permission is lost during an upgrade, the app-op should downgrade to foreground
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them. Also instant apps are never updated, hence the test "
+ + "is useless.")
+ public void appOpGetsDowngradedWhenBgPermIsNotRequestedAnymore() throws Exception {
+ install(APK_LOCATION_BACKGROUND_29);
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ install(APK_LOCATION_29v4);
+
+ eventually(() -> assertWithMessage("foreground app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
+ }
+
+ /**
+ * Make sure location switch-op is set if no location access is granted.
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them. Also instant apps are never updated, hence the test "
+ + "is useless.")
+ public void appOpIsSetIfNoLocPermIsGranted() {
+ install(APK_LOCATION_BACKGROUND_29);
+
+ // Wait until the system sets the app-op automatically
+ eventually(() -> assertWithMessage("loc app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_IGNORED));
+ }
+
+ /**
+ * Make sure location switch-op is set if only coarse location is granted
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them. Also instant apps are never updated, hence the test "
+ + "is useless.")
+ public void appOpIsSetIfOnlyCoarseLocPermIsGranted() {
+ install(APK_LOCATION_BACKGROUND_29);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ // Wait until the system sets the app-op automatically
+ eventually(() -> assertWithMessage("loc app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
+ }
+
+ /**
+ * Make sure location switch-op is set if coarse location with background access is granted.
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them. Also instant apps are never updated, hence the test "
+ + "is useless.")
+ public void appOpIsSetIfCoarseAndBgLocPermIsGranted() {
+ install(APK_LOCATION_BACKGROUND_29);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ // Wait until the system sets the app-op automatically
+ eventually(() -> assertWithMessage("loc app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED));
+ }
+
+ /**
+ * Make sure location switch-op is set if only fine location is granted
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them. Also instant apps are never updated, hence the test "
+ + "is useless.")
+ public void appOpIsSetIfOnlyFineLocPermIsGranted() {
+ install(APK_LOCATION_BACKGROUND_29);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION);
+
+ // Wait until the system sets the app-op automatically
+ // Fine location uses background location to limit access
+ eventually(() -> assertWithMessage("loc app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
+ }
+
+ /**
+ * Make sure location switch-op is set if fine location with background access is granted.
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them. Also instant apps are never updated, hence the test "
+ + "is useless.")
+ public void appOpIsSetIfFineAndBgLocPermIsGranted() {
+ install(APK_LOCATION_BACKGROUND_29);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ // Wait until the system sets the app-op automatically
+ eventually(() -> assertWithMessage("loc app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED));
+ }
+
+ /**
+ * Make sure location switch-op is set if fine and coarse location access is granted.
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them. Also instant apps are never updated, hence the test "
+ + "is useless.")
+ public void appOpIsSetIfFineAndCoarseLocPermIsGranted() {
+ install(APK_LOCATION_BACKGROUND_29);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ // Wait until the system sets the app-op automatically
+ eventually(() -> assertWithMessage("loc app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
+ }
+
+ /**
+ * Make sure location switch-op is set if fine and coarse location with background access is
+ * granted.
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them. Also instant apps are never updated, hence the test "
+ + "is useless.")
+ public void appOpIsSetIfFineCoarseAndBgLocPermIsGranted() {
+ install(APK_LOCATION_BACKGROUND_29);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ // Wait until the system sets the app-op automatically
+ eventually(() -> assertWithMessage("loc app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED));
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java b/tests/cts/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
new file mode 100644
index 000000000..42da8c830
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.os.Process.myUserHandle;
+import static android.permission.cts.TestUtils.eventually;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.app.NotificationManager;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.DeviceConfig;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+
+import java.util.List;
+
+/**
+ * Base test class used for {@code NotificationListenerCheckTest} and
+ * {@code NotificationListenerCheckWithSafetyCenterUnsupportedTest}
+ */
+public class BaseNotificationListenerCheckTest {
+ private static final String LOG_TAG = BaseNotificationListenerCheckTest.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ protected static final String TEST_APP_PKG =
+ "android.permission.cts.appthathasnotificationlistener";
+ private static final String TEST_APP_NOTIFICATION_SERVICE =
+ TEST_APP_PKG + ".CtsNotificationListenerService";
+ protected static final String TEST_APP_NOTIFICATION_LISTENER_APK =
+ "/data/local/tmp/cts-permission/CtsAppThatHasNotificationListener.apk";
+
+ private static final int NOTIFICATION_LISTENER_CHECK_JOB_ID = 4;
+
+ /**
+ * Device config property for whether notification listener check is enabled on the device
+ */
+ private static final String PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED =
+ "notification_listener_check_enabled";
+
+ /**
+ * Device config property for time period in milliseconds after which current enabled
+ * notification
+ * listeners are queried
+ */
+ protected static final String PROPERTY_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS =
+ "notification_listener_check_interval_millis";
+
+ protected static final Long OVERRIDE_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS =
+ SECONDS.toMillis(0);
+
+ private static final String ACTION_SET_UP_NOTIFICATION_LISTENER_CHECK =
+ "com.android.permissioncontroller.action.SET_UP_NOTIFICATION_LISTENER_CHECK";
+ private static final String NotificationListenerOnBootReceiver =
+ "com.android.permissioncontroller.privacysources.SetupPeriodicNotificationListenerCheck";
+
+ /**
+ * ID for notification shown by
+ * {@link com.android.permissioncontroller.privacysources.NotificationListenerCheck}.
+ */
+ public static final int NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID = 3;
+
+ protected static final long UNEXPECTED_TIMEOUT_MILLIS = 10000;
+ protected static final long ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS = 5000;
+
+ private static final Context sContext = InstrumentationRegistry.getTargetContext();
+ private static final PackageManager sPackageManager = sContext.getPackageManager();
+ private static final UiAutomation sUiAutomation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+
+ private static final String PERMISSION_CONTROLLER_PKG = sContext.getPackageManager()
+ .getPermissionControllerPackageName();
+
+ private static List<ComponentName> sPreviouslyEnabledNotificationListeners;
+
+ // Override SafetyCenter enabled flag
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigSafetyCenterEnabled =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SafetyCenterUtils.PROPERTY_SAFETY_CENTER_ENABLED,
+ Boolean.toString(true));
+
+ // Override NlsCheck enabled flag
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigNlsCheckEnabled =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED,
+ Boolean.toString(true));
+
+ // Override general notification interval from once every day to once ever 1 second
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigNlsCheckIntervalMillis =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS,
+ Long.toString(OVERRIDE_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS));
+
+ @Rule
+ public CtsNotificationListenerHelperRule ctsNotificationListenerHelper =
+ new CtsNotificationListenerHelperRule(sContext);
+
+ @BeforeClass
+ public static void beforeClassSetup() throws Exception {
+ // Bypass battery saving restrictions
+ runShellCommand("cmd tare set-vip "
+ + myUserHandle().getIdentifier() + " " + PERMISSION_CONTROLLER_PKG + " true");
+ // Disallow any OEM enabled NLS
+ disallowPreexistingNotificationListeners();
+ }
+
+ @AfterClass
+ public static void afterClassTearDown() throws Throwable {
+ // Reset battery saving restrictions
+ runShellCommand("cmd tare set-vip "
+ + myUserHandle().getIdentifier() + " " + PERMISSION_CONTROLLER_PKG + " default");
+ // Reallow any previously OEM allowed NLS
+ reallowPreexistingNotificationListeners();
+ }
+
+ protected static void setDeviceConfigPrivacyProperty(String propertyName, String value) {
+ runWithShellPermissionIdentity(() -> {
+ boolean valueWasSet = DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ /* name = */ propertyName,
+ /* value = */ value,
+ /* makeDefault = */ false);
+ if (!valueWasSet) {
+ throw new IllegalStateException("Could not set " + propertyName + " to " + value);
+ }
+ });
+ }
+
+ /**
+ * Enable or disable notification listener check
+ */
+ protected static void setNotificationListenerCheckEnabled(boolean enabled) {
+ setDeviceConfigPrivacyProperty(
+ PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED,
+ /* value = */ String.valueOf(enabled));
+ }
+
+ /**
+ * Allow or disallow a {@link NotificationListenerService} component for the current user
+ *
+ * @param listenerComponent {@link NotificationListenerService} component to allow or disallow
+ */
+ private static void setNotificationListenerServiceAllowed(ComponentName listenerComponent,
+ boolean allowed) {
+ String command = " cmd notification " + (allowed ? "allow_listener " : "disallow_listener ")
+ + listenerComponent.flattenToString();
+ runShellCommand(command);
+ }
+
+ private static void disallowPreexistingNotificationListeners() {
+ runWithShellPermissionIdentity(() -> {
+ NotificationManager notificationManager =
+ sContext.getSystemService(NotificationManager.class);
+ sPreviouslyEnabledNotificationListeners =
+ notificationManager.getEnabledNotificationListeners();
+ });
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Found " + sPreviouslyEnabledNotificationListeners.size()
+ + " previously allowed notification listeners. Disabling before test run.");
+ }
+ for (ComponentName listener : sPreviouslyEnabledNotificationListeners) {
+ setNotificationListenerServiceAllowed(listener, false);
+ }
+ }
+
+ private static void reallowPreexistingNotificationListeners() {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Re-allowing " + sPreviouslyEnabledNotificationListeners.size()
+ + " previously allowed notification listeners found before test run.");
+ }
+ for (ComponentName listener : sPreviouslyEnabledNotificationListeners) {
+ setNotificationListenerServiceAllowed(listener, true);
+ }
+ }
+
+ protected void allowTestAppNotificationListenerService() {
+ setNotificationListenerServiceAllowed(
+ new ComponentName(TEST_APP_PKG, TEST_APP_NOTIFICATION_SERVICE), true);
+ }
+
+ protected void disallowTestAppNotificationListenerService() {
+ setNotificationListenerServiceAllowed(
+ new ComponentName(TEST_APP_PKG, TEST_APP_NOTIFICATION_SERVICE), false);
+ }
+
+ /**
+ * Force a run of the notification listener check.
+ */
+ protected static void runNotificationListenerCheck() throws Throwable {
+ TestUtils.awaitJobUntilRequestedState(
+ PERMISSION_CONTROLLER_PKG,
+ NOTIFICATION_LISTENER_CHECK_JOB_ID,
+ UNEXPECTED_TIMEOUT_MILLIS,
+ sUiAutomation,
+ "waiting"
+ );
+
+ TestUtils.runJobAndWaitUntilCompleted(
+ PERMISSION_CONTROLLER_PKG,
+ NOTIFICATION_LISTENER_CHECK_JOB_ID,
+ UNEXPECTED_TIMEOUT_MILLIS,
+ sUiAutomation
+ );
+ }
+
+ /**
+ * Skip tests for if Safety Center not supported
+ */
+ protected void assumeDeviceSupportsSafetyCenter() {
+ assumeTrue(SafetyCenterUtils.deviceSupportsSafetyCenter(sContext));
+ }
+
+ /**
+ * Skip tests for if Safety Center IS supported
+ */
+ protected void assumeDeviceDoesNotSupportSafetyCenter() {
+ assumeFalse(SafetyCenterUtils.deviceSupportsSafetyCenter(sContext));
+ }
+
+ protected void wakeUpAndDismissKeyguard() {
+ runShellCommand("input keyevent KEYCODE_WAKEUP");
+ runShellCommand("wm dismiss-keyguard");
+ }
+
+ /**
+ * Reset the permission controllers state before each test
+ */
+ protected void resetPermissionControllerBeforeEachTest() throws Throwable {
+ resetPermissionController();
+
+ // ensure no posted notification listener notifications exits
+ eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ // Reset job scheduler stats (to allow more jobs to be run)
+ runShellCommand(
+ "cmd jobscheduler reset-execution-quota -u " + myUserHandle().getIdentifier() + " "
+ + PERMISSION_CONTROLLER_PKG);
+ runShellCommand("cmd jobscheduler reset-schedule-quota");
+ }
+
+ /**
+ * Reset the permission controllers state.
+ */
+ private static void resetPermissionController() throws Throwable {
+ PermissionUtils.resetPermissionControllerJob(sUiAutomation, PERMISSION_CONTROLLER_PKG,
+ NOTIFICATION_LISTENER_CHECK_JOB_ID, 45000,
+ ACTION_SET_UP_NOTIFICATION_LISTENER_CHECK, NotificationListenerOnBootReceiver);
+ }
+
+ /**
+ * Preshow/dismiss cts NotificationListener notification as it negatively affects test results
+ * (can result in unexpected test pass/failures)
+ */
+ protected void triggerAndDismissCtsNotificationListenerNotification() throws Throwable {
+ // CtsNotificationListenerService isn't enabled at this point, but NotificationListener
+ // should be. Mark as notified by showing and dismissing
+ runNotificationListenerCheck();
+
+ // Ensure notification shows and dismiss
+ eventually(() -> assertNotNull(getNotification(true)),
+ UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ /**
+ * Get a notification listener notification that is currently visible.
+ *
+ * @param cancelNotification if `true` the notification is canceled inside this method
+ * @return The notification or `null` if there is none
+ */
+ protected StatusBarNotification getNotification(boolean cancelNotification) throws Throwable {
+ return CtsNotificationListenerServiceUtils.getNotificationForPackageAndId(
+ PERMISSION_CONTROLLER_PKG,
+ NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID,
+ cancelNotification);
+ }
+
+ /**
+ * Clear any notifications related to NotificationListenerCheck to ensure clean test setup
+ */
+ protected void clearNotifications() throws Throwable {
+ // Clear notification if present
+ CtsNotificationListenerServiceUtils.cancelNotifications(PERMISSION_CONTROLLER_PKG);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/Camera2PermissionTest.java b/tests/cts/permission/src/android/permission/cts/Camera2PermissionTest.java
new file mode 100644
index 000000000..379f47815
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/Camera2PermissionTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraCharacteristics.Key;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.platform.test.annotations.Presubmit;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.ex.camera2.blocking.BlockingCameraManager;
+import com.android.ex.camera2.blocking.BlockingStateCallback;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for Camera2 API related Permissions. Currently, this means
+ * android.permission.CAMERA.
+ */
+public class Camera2PermissionTest extends AndroidTestCase {
+ private static final String TAG = "Camera2PermissionTest";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ private static final int CAMERA_CLOSE_TIMEOUT_MS = 2000;
+
+ private CameraManager mCameraManager;
+ private CameraDevice mCamera;
+ private BlockingStateCallback mCameraListener;
+ private String[] mCameraIds;
+ protected Handler mHandler;
+ protected HandlerThread mHandlerThread;
+
+ @Override
+ public void setContext(Context context) {
+ super.setContext(context);
+ mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+ assertNotNull("Can't connect to camera manager!", mCameraManager);
+ }
+
+ /**
+ * Set up the camera2 test case required environments, including CameraManager,
+ * HandlerThread, Camera IDs, and CameraStateCallback etc.
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mCameraIds = mCameraManager.getCameraIdList();
+ assertNotNull("Camera ids shouldn't be null", mCameraIds);
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ mCameraListener = new BlockingStateCallback();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mHandlerThread.quitSafely();
+ mHandler = null;
+
+ super.tearDown();
+ }
+
+ /**
+ * Attempt to open camera. Requires Permission:
+ * {@link android.Manifest.permission#CAMERA}.
+ */
+ public void testCameraOpen() throws Exception {
+ for (String id : mCameraIds) {
+ try {
+ openCamera(id);
+ fail("Was able to open camera " + id + " with no permission");
+ }
+ catch (SecurityException e) {
+ // expected
+ } finally {
+ closeCamera();
+ }
+ }
+ }
+
+ /**
+ * Check that no system cameras can be discovered without
+ * {@link android.Manifest.permission#CAMERA} and android.permission.SYSTEM_CAMERA
+ */
+ public void testSystemCameraDiscovery() throws Exception {
+ for (String id : mCameraIds) {
+ Log.i(TAG, "testSystemCameraDiscovery for camera id " + id);
+ CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
+ assertNotNull("Camera characteristics shouldn't be null", characteristics);
+ int[] availableCapabilities =
+ characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ assertTrue("Camera capabilities shouldn't be null", availableCapabilities != null);
+ List<Integer> capList = toList(availableCapabilities);
+ assertFalse("System camera device " + id + " should not be public",
+ capList.contains(
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA));
+ }
+ }
+
+ /**
+ * Check the absence of camera characteristics keys that require Permission:
+ * {@link android.Manifest.permission#CAMERA}.
+ */
+ public void testCameraCharacteristicsNeedingPermission() throws Exception {
+ for (String id : mCameraIds) {
+ CameraCharacteristics capabilities = mCameraManager.getCameraCharacteristics(id);
+ assertNotNull("Camera characteristics shouldn't be null", capabilities);
+ List<Key<?>> keysNeedingPermission = capabilities.getKeysNeedingPermission();
+ if (keysNeedingPermission == null) {
+ continue;
+ }
+ List<Key<?>> keys = capabilities.getKeys();
+ assertNotNull("Camera characteristics key list shouldn't be null", keys);
+ for (Key<?> key : keysNeedingPermission) {
+ assertEquals("Key " + key.getName() + " needing permission is part of the" +
+ " available characteristics keys", -1, keys.indexOf(key));
+ assertNull("Key " + key.getName() + " needing permission must not present" +
+ " in camera characteristics", capabilities.get(key));
+ }
+ }
+ }
+
+ /**
+ * Add and remove availability listeners should work without permission.
+ */
+ @Presubmit
+ public void testAvailabilityCallback() throws Exception {
+ DummyCameraListener availabilityListener = new DummyCameraListener();
+ // Remove a not-registered listener is a no-op.
+ mCameraManager.unregisterAvailabilityCallback(availabilityListener);
+ mCameraManager.registerAvailabilityCallback(availabilityListener, mHandler);
+ mCameraManager.unregisterAvailabilityCallback(availabilityListener);
+ mCameraManager.registerAvailabilityCallback(availabilityListener, mHandler);
+ mCameraManager.registerAvailabilityCallback(availabilityListener, mHandler);
+ mCameraManager.unregisterAvailabilityCallback(availabilityListener);
+ // Remove a previously-added listener second time is a no-op.
+ mCameraManager.unregisterAvailabilityCallback(availabilityListener);
+ }
+
+ private class DummyCameraListener extends CameraManager.AvailabilityCallback {
+ @Override
+ public void onCameraAvailable(String cameraId) {
+ }
+
+ @Override
+ public void onCameraUnavailable(String cameraId) {
+ }
+ }
+
+ private void openCamera(String cameraId) throws Exception {
+ mCamera = (new BlockingCameraManager(mCameraManager)).openCamera(
+ cameraId, mCameraListener, mHandler);
+ }
+
+ private static List<Integer> toList(int[] array) {
+ List<Integer> list = new ArrayList<Integer>();
+ for (int i : array) {
+ list.add(i);
+ }
+ return list;
+ }
+
+ private void closeCamera() {
+ if (mCamera != null) {
+ mCamera.close();
+ mCameraListener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
+ mCamera = null;
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/CameraPermissionTest.java b/tests/cts/permission/src/android/permission/cts/CameraPermissionTest.java
new file mode 100644
index 000000000..981735388
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/CameraPermissionTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.hardware.Camera;
+import android.os.Environment;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.MediumTest;
+
+import java.io.FileOutputStream;
+
+/**
+ * Tests for camera-related Permissions. Currently, this means
+ * android.permission.CAMERA.
+ */
+public class CameraPermissionTest extends AndroidTestCase {
+
+ private static String PATH_PREFIX = Environment.getExternalStorageDirectory().toString();
+ private static String CAMERA_IMAGE_PATH = PATH_PREFIX + "this-should-not-exist.jpg";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ class ShutterCallback implements Camera.ShutterCallback {
+ public void onShutter() { }
+ }
+
+ class RawPictureCallback implements Camera.PictureCallback {
+ public void onPictureTaken(byte [] rawData, Camera camera) { }
+ }
+
+ class JpegPictureCallback implements Camera.PictureCallback {
+ public void onPictureTaken(byte [] jpegData, Camera camera) {
+ if (jpegData == null) {
+ // TODO: Is this good (= expected, = correct), or weird, or bad?
+ return;
+ }
+
+ try {
+ FileOutputStream s = new FileOutputStream(CAMERA_IMAGE_PATH);
+ s.write(jpegData);
+ s.flush();
+ }
+ catch (SecurityException e) {
+ // Sure, NOW they tell us (NOTE: this could be a side effect
+ // of the upcoming WRITE_EXTERNAL_STORAGE permission).
+ } catch (Exception e) {
+ // We didn't really need to save it anyway, did we?
+ }
+
+ fail("Successfully captured an image of " + jpegData.length +
+ " bytes, and saved it to " + CAMERA_IMAGE_PATH);
+ }
+ }
+
+ /**
+ * Attempt to take a picture. Requires Permission:
+ * {@link android.Manifest.permission#CAMERA}.
+ */
+ @MediumTest
+ public void testCamera() {
+ try {
+ (Camera.open()).takePicture(new ShutterCallback(),
+ new RawPictureCallback(),
+ new JpegPictureCallback());
+ fail("Was able to take a picture with the camera with no permission");
+ }
+ catch (SecurityException e) {
+ // expected
+ } catch (RuntimeException e) {
+ // expected
+ // The JNI layer isn't translating the EPERM error status into
+ // a SecurityException.
+ }
+ }
+
+}
+
diff --git a/tests/cts/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java b/tests/cts/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java
new file mode 100644
index 000000000..0e8797d20
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.OemNetworkPreferences;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Executor;
+
+/**
+* Test that protected android.net.ConnectivityManager methods cannot be called without
+* permissions
+*/
+@RunWith(AndroidJUnit4.class)
+public class ConnectivityManagerPermissionTest {
+
+ private ConnectivityManager mConnectivityManager;
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
+ assertNotNull(mConnectivityManager);
+ }
+
+ /**
+ * Verify that calling {@link ConnectivityManager#getNetworkInfo(int))}
+ * requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ */
+ @Test
+ public void testGetNetworkInfo() {
+ try {
+ mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ fail("Was able to call getNetworkInfo");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that calling {@link ConnectivityManager#setOemNetworkPreference(OemNetworkPreferences,
+ * Executor, ConnectivityManager.OnSetOemNetworkPreferenceListener)}
+ * requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#CONTROL_OEM_PAID_NETWORK_PREFERENCE}.
+ */
+ @Test
+ public void testSetOemNetworkPreference() {
+ assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE));
+ try {
+ final String testPackage = "does.not.matter.com";
+ final int testPref = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
+ final OemNetworkPreferences preferences =
+ new OemNetworkPreferences.Builder()
+ .addNetworkPreference(testPackage, testPref)
+ .build();
+ mConnectivityManager.setOemNetworkPreference(preferences, null, null);
+ fail("Was able to call setOemNetworkPreference");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that calling {@link ConnectivityManager#setOemNetworkPreference(OemNetworkPreferences,
+ * Executor, ConnectivityManager.OnSetOemNetworkPreferenceListener)}
+ * requires automotive feature.
+ * <p>Tests Feature:
+ * {@link PackageManager#FEATURE_AUTOMOTIVE}.
+ */
+ @Test
+ public void testSetOemNetworkPreferenceHasAutomotiveFeature() {
+ assumeFalse(mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE));
+ try {
+ final String testPackage = "does.not.matter.com";
+ final int testPref = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
+ final OemNetworkPreferences preferences =
+ new OemNetworkPreferences.Builder()
+ .addNetworkPreference(testPackage, testPref)
+ .build();
+ mConnectivityManager.setOemNetworkPreference(preferences, null, null);
+ fail("Was able to call setOemNetworkPreference");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/ContactsProviderTest.java b/tests/cts/permission/src/android/permission/cts/ContactsProviderTest.java
new file mode 100644
index 000000000..69b64d790
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/ContactsProviderTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify permissions are enforced.
+ */
+public class ContactsProviderTest extends AndroidTestCase {
+
+ /**
+ * Verifies that query(ContactsContract.Contacts.CONTENT_URI) requires
+ * Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#READ_CONTACTS}.
+ */
+ @SmallTest
+ public void testQueryContacts() {
+ try {
+ getContext().getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
+ null, null, null, null);
+ fail("query(ContactsContract.Contacts.CONTENT_URI) did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that insert(ContactsContract.Contacts.CONTENT_URI) requires
+ * Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#WRITE_CONTACTS}.
+ */
+ @SmallTest
+ public void testInsertContacts() {
+ try {
+ getContext().getContentResolver().insert(ContactsContract.Contacts.CONTENT_URI,
+ new ContentValues());
+ fail("insert(ContactsContract.Contacts.CONTENT_URI) did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that query(ContactsContract.Profile.CONTENT_URI) requires
+ * Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#READ_CONTACTS}.
+ */
+ @SmallTest
+ public void testQueryProfile() {
+ try {
+ getContext().getContentResolver().query(ContactsContract.Profile.CONTENT_URI,
+ null, null, null, null);
+ fail("query(ContactsContract.Profile.CONTENT_URI) did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that insert(ContactsContract.Profile.CONTENT_URI) requires
+ * Permission. The provider doesn't actually let you do this even if you have the
+ * permission, but trying to do it without the permission should throw a
+ * SecurityException anyway.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#WRITE_CONTACTS}.
+ */
+ @SmallTest
+ public void testInsertProfile() {
+ try {
+ getContext().getContentResolver().insert(ContactsContract.Profile.CONTENT_URI,
+ new ContentValues(0));
+ fail("insert(ContactsContract.Profile.CONTENT_URI) did not throw SecurityException "
+ + "as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that update(ContactsContract.Profile.CONTENT_URI) requires
+ * Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#WRITE_CONTACTS}.
+ */
+ @SmallTest
+ public void testUpdateProfile() {
+ try {
+ getContext().getContentResolver().update(ContactsContract.Profile.CONTENT_URI,
+ new ContentValues(0), null, null);
+ fail("update(ContactsContract.Profile.CONTENT_URI) did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that query(ContactsContract.CommonDataKinds.Phone.ENTERPRISE_CONTENT_URI) requires
+ * Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
+ */
+ @SmallTest
+ public void testQueryPhoneEnterprise() {
+ try {
+ getContext().getContentResolver().query(
+ ContactsContract.CommonDataKinds.Phone.ENTERPRISE_CONTENT_URI,
+ null, null, null, null);
+ fail("query(ContactsContract.CommonDataKinds.Phone.ENTERPRISE_CONTENT_URI) did not"
+ + " throw SecurityException as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that query(ContactsContract.RawContactsEntity.CORP_CONTENT_URI) requires
+ * Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
+ */
+ @SmallTest
+ public void testRawContactsEntityCorp() {
+ try {
+ getContext().getContentResolver().query(
+ ContactsContract.RawContactsEntity.CORP_CONTENT_URI, null, null, null, null);
+ fail("query(ContactsContract.RawContactsEntity.CORP_CONTENT_URI) did not throw"
+ + " SecurityException as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/DebuggableTest.java b/tests/cts/permission/src/android/permission/cts/DebuggableTest.java
new file mode 100644
index 000000000..7ca734887
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/DebuggableTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Verify that pre-installed packages don't have the debuggable
+ * flag set. The debuggable flag allows should only be used during
+ * development, and never for shipping devices.
+ */
+public class DebuggableTest extends AndroidTestCase {
+
+ public void testNoDebuggable() {
+ Set<String> debuggableApps = new HashSet<String>();
+ List<ApplicationInfo> apps = getContext()
+ .getPackageManager()
+ .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
+ for (ApplicationInfo app : apps) {
+ if (!app.isSystemApp()) {
+ continue;
+ }
+ String appName = app.packageName;
+ if ((app.flags & ApplicationInfo.FLAG_DEBUGGABLE) == ApplicationInfo.FLAG_DEBUGGABLE) {
+ debuggableApps.add(appName);
+ }
+ }
+ assertTrue("Packages marked debuggable: " + debuggableApps, debuggableApps.isEmpty());
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt b/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt
new file mode 100644
index 000000000..ac02d53b5
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.Manifest
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE
+import android.app.Instrumentation
+import android.companion.virtual.VirtualDeviceManager
+import android.companion.virtual.VirtualDeviceManager.VirtualDevice
+import android.companion.virtual.VirtualDeviceParams
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME
+import android.content.pm.PackageManager.PERMISSION_DENIED
+import android.content.pm.PackageManager.PERMISSION_GRANTED
+import android.os.Build
+import android.os.UserHandle
+import android.permission.PermissionManager
+import android.platform.test.annotations.AppModeFull
+import android.virtualdevice.cts.common.FakeAssociationRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.AdoptShellPermissionsRule
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
+import com.android.compatibility.common.util.SystemUtil.waitForBroadcasts
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assume.assumeNotNull
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@AppModeFull(reason = " cannot be accessed by instant apps")
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = "VanillaIceCream")
+class DevicePermissionsTest {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val defaultDeviceContext = instrumentation.targetContext
+
+ private lateinit var virtualDevice: VirtualDevice
+ private lateinit var virtualDeviceContext: Context
+
+ private lateinit var permissionManager: PermissionManager
+
+ @get:Rule var mFakeAssociationRule = FakeAssociationRule()
+
+ @get:Rule
+ val mAdoptShellPermissionsRule =
+ AdoptShellPermissionsRule(
+ instrumentation.uiAutomation,
+ Manifest.permission.CREATE_VIRTUAL_DEVICE,
+ Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
+ )
+
+ @Before
+ fun setup() {
+ val virtualDeviceManager =
+ defaultDeviceContext.getSystemService(VirtualDeviceManager::class.java)
+ assumeNotNull(virtualDeviceManager)
+ virtualDevice =
+ virtualDeviceManager!!.createVirtualDevice(
+ mFakeAssociationRule.getAssociationInfo().getId(),
+ VirtualDeviceParams.Builder().build()
+ )
+ virtualDeviceContext = defaultDeviceContext.createDeviceContext(virtualDevice.deviceId)
+ permissionManager = virtualDeviceContext.getSystemService(PermissionManager::class.java)!!
+ runShellCommandOrThrow("pm install -r $TEST_APK")
+ }
+
+ @After
+ fun cleanup() {
+ runShellCommandOrThrow("pm uninstall $TEST_PACKAGE_NAME")
+ virtualDevice.close()
+ }
+
+ @Test
+ fun testDeviceAwareRuntimePermissionIsGranted() {
+ grantPermissionAndAssertGranted(Manifest.permission.CAMERA, virtualDeviceContext)
+ }
+
+ @Test
+ fun testDeviceAwareRuntimePermissionGrantIsInherited() {
+ grantPermissionAndAssertGranted(Manifest.permission.CAMERA, defaultDeviceContext)
+
+ assertPermission(Manifest.permission.CAMERA, PERMISSION_GRANTED, virtualDeviceContext)
+ }
+
+ @Test
+ fun testNonDeviceAwareRuntimePermissionGrantIsInherited() {
+ grantPermissionAndAssertGranted(Manifest.permission.READ_CONTACTS, defaultDeviceContext)
+
+ assertPermission(
+ Manifest.permission.READ_CONTACTS,
+ PERMISSION_GRANTED,
+ virtualDeviceContext
+ )
+ }
+
+ @Test
+ fun testDeviceAwareRuntimePermissionIsRevoked() {
+ grantPermissionAndAssertGranted(Manifest.permission.RECORD_AUDIO, virtualDeviceContext)
+
+ revokePermissionAndAssertDenied(Manifest.permission.RECORD_AUDIO, virtualDeviceContext)
+ }
+
+ @Test
+ fun testNonDeviceAwareRuntimePermissionIsRevokedForDefaultDevice() {
+ grantPermissionAndAssertGranted(Manifest.permission.READ_CONTACTS, defaultDeviceContext)
+ assertPermission(
+ Manifest.permission.READ_CONTACTS,
+ PERMISSION_GRANTED,
+ virtualDeviceContext
+ )
+ // Revoke call from virtualDeviceContext should revoke for default device as well.
+ revokePermissionAndAssertDenied(Manifest.permission.READ_CONTACTS, virtualDeviceContext)
+ assertPermission(Manifest.permission.READ_CONTACTS, PERMISSION_DENIED, defaultDeviceContext)
+ }
+
+ @Test
+ fun testNormalPermissionGrantIsInherited() {
+ assertPermission(Manifest.permission.INTERNET, PERMISSION_GRANTED, virtualDeviceContext)
+ }
+
+ @Test
+ fun testSignaturePermissionGrantIsInherited() {
+ assertPermission(CUSTOM_SIGNATURE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext)
+ }
+
+ @Test
+ fun testOneTimePermissionIsRevoked() {
+ grantPermissionAndAssertGranted(Manifest.permission.RECORD_AUDIO, virtualDeviceContext)
+ virtualDeviceContext.packageManager.updatePermissionFlags(
+ Manifest.permission.RECORD_AUDIO,
+ TEST_PACKAGE_NAME,
+ FLAG_PERMISSION_ONE_TIME,
+ FLAG_PERMISSION_ONE_TIME,
+ UserHandle.of(virtualDeviceContext.userId)
+ )
+
+ permissionManager.startOneTimePermissionSession(
+ TEST_PACKAGE_NAME,
+ 0,
+ 0,
+ IMPORTANCE_FOREGROUND,
+ IMPORTANCE_FOREGROUND_SERVICE
+ )
+ eventually {
+ assertPermission(
+ Manifest.permission.RECORD_AUDIO,
+ PERMISSION_DENIED,
+ virtualDeviceContext
+ )
+ }
+ }
+
+ @Test
+ fun testRevokeSelfPermissionOnKill() {
+ grantPermissionAndAssertGranted(Manifest.permission.RECORD_AUDIO, virtualDeviceContext)
+
+ revokeSelfPermission(Manifest.permission.RECORD_AUDIO, virtualDeviceContext)
+ eventually {
+ assertPermission(
+ Manifest.permission.RECORD_AUDIO,
+ PERMISSION_DENIED,
+ virtualDeviceContext
+ )
+ }
+ }
+
+ private fun revokeSelfPermission(permissionName: String, context: Context) {
+ val intent = Intent(PERMISSION_SELF_REVOKE_INTENT)
+ intent.setClassName(TEST_PACKAGE_NAME, PERMISSION_SELF_REVOKE_RECEIVER)
+ intent.putExtra("permissionName", permissionName)
+ intent.putExtra("deviceID", context.deviceId)
+ context.sendBroadcast(intent)
+ waitForBroadcasts()
+ }
+
+ private fun grantPermissionAndAssertGranted(permissionName: String, context: Context) {
+ context.packageManager.grantRuntimePermission(
+ TEST_PACKAGE_NAME,
+ permissionName,
+ UserHandle.of(context.userId)
+ )
+ assertPermission(permissionName, PERMISSION_GRANTED, context)
+ }
+
+ private fun revokePermissionAndAssertDenied(permissionName: String, context: Context) {
+ context.packageManager.revokeRuntimePermission(
+ TEST_PACKAGE_NAME,
+ permissionName,
+ 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)
+ }
+
+ companion object {
+ private const val TEST_PACKAGE_NAME = "android.permission.cts.appthatrequestpermission"
+ private const val TEST_APK =
+ "/data/local/tmp/cts-permission/CtsAppThatRequestsDevicePermissions.apk"
+
+ private const val CUSTOM_SIGNATURE_PERMISSION =
+ "android.permission.cts.CUSTOM_SIGNATURE_PERMISSION"
+
+ private const val PERMISSION_SELF_REVOKE_INTENT =
+ "android.permission.cts.appthatrequestpermission.REVOKE_SELF_PERMISSION"
+ private const val PERMISSION_SELF_REVOKE_RECEIVER =
+ "android.permission.cts.appthatrequestpermission.RevokeSelfPermissionReceiver"
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/DuplicatePermissionDefinitionsTest.kt b/tests/cts/permission/src/android/permission/cts/DuplicatePermissionDefinitionsTest.kt
new file mode 100644
index 000000000..ceb797b80
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/DuplicatePermissionDefinitionsTest.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.content.pm.PackageManager
+import android.content.pm.PermissionGroupInfo
+import android.content.pm.PermissionInfo
+import android.os.Build
+import android.platform.test.annotations.AppModeFull
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.SdkSuppress
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
+import com.android.compatibility.common.util.ShellUtils.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val APK_PATH = "/data/local/tmp/cts-permission/"
+
+private const val APK_DEFINING_PERM_A = "${APK_PATH}CtsAppThatDefinesPermissionA.apk"
+private const val APK_ALSO_DEFINING_PERM_A = "${APK_PATH}CtsAppThatAlsoDefinesPermissionA.apk"
+private const val APK_ALSO_DEFINING_PERM_A_DIFFERENT_CERT =
+ "${APK_PATH}CtsAppThatAlsoDefinesPermissionADifferentCert.apk"
+private const val APK_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT =
+ "${APK_PATH}CtsAppThatAlsoDefinesPermissionGroupADifferentCert.apk"
+private const val APK_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT_SDK_30 =
+ "${APK_PATH}CtsAppThatAlsoDefinesPermissionGroupADifferentCert30.apk"
+private const val APK_DEFINING_PERM_WITH_INVALID_GROUP =
+ "${APK_PATH}CtsAppThatDefinesPermissionWithInvalidGroup.apk"
+private const val APK_DEFINING_PERM_WITH_INVALID_GROUP_SDK_30 =
+ "${APK_PATH}CtsAppThatDefinesPermissionWithInvalidGroup30.apk"
+private const val APK_DEFINING_PERM_IN_PLATFORM_GROUP =
+ "${APK_PATH}CtsAppThatDefinesPermissionInPlatformGroup.apk"
+
+private const val APP_DEFINING_PERM_A = "android.permission.cts.appthatdefinespermissiona"
+private const val APP_ALSO_DEFINING_PERM_A = "android.permission.cts.appthatalsodefinespermissiona"
+private const val APP_ALSO_DEFINING_PERM_A_DIFFERENT_CERT =
+ "android.permission.cts.appthatdefinespermissiona.differentcert"
+private const val APP_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT =
+ "android.permission.cts.appthatdefinespermissiongroupa.differentcert"
+private const val APP_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT_SDK_30 =
+ "android.permission.cts.appthatdefinespermissiongroupa.differentcert30"
+private const val APP_DEFINING_PERM_IN_PLATFORM_GROUP =
+ "android.permission.cts.appthatdefinespermissioninplatformgroup"
+private const val APP_DEFINING_PERM_WITH_INVALID_GROUP =
+ "android.permission.cts.appthatdefinespermissionwithinvalidgroup"
+private const val APP_DEFINING_PERM_WITH_INVALID_GROUP_SDK_30 =
+ "android.permission.cts.appthatdefinespermissionwithinvalidgroup30"
+
+private const val PERM_A = "com.android.cts.duplicatepermission.permA"
+private const val GROUP_A = "com.android.cts.duplicatepermission.groupA"
+private const val INVALID_GROUP = "com.android.cts.duplicatepermission.invalid"
+
+/**
+ * Test cases where packages
+ * - define the same permission or
+ * - define the same permission group
+ * - define permissions in a group defined by another package
+ */
+@AppModeFull(reason = "Tests properties of other app. Instant apps cannot interact with other apps")
+@RunWith(AndroidJUnit4ClassRunner::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class DuplicatePermissionDefinitionsTest {
+ private val pm = InstrumentationRegistry.getTargetContext().packageManager
+
+ private fun install(apk: String) {
+ runShellCommandOrThrow("pm install $apk")
+ }
+
+ private fun uninstall(app: String) {
+ runShellCommand("pm uninstall $app")
+ }
+
+ private val allPackages: List<String>
+ get() = pm.getInstalledPackages(0).map { it.packageName }
+
+ private val permAInfo: PermissionInfo
+ get() = pm.getPermissionInfo(PERM_A, 0)!!
+
+ private val groupAInfo: PermissionGroupInfo
+ get() = pm.getPermissionGroupInfo(GROUP_A, 0)!!
+
+ @Test
+ fun canInstallAppsDefiningSamePermissionWhenSameCert() {
+ install(APK_DEFINING_PERM_A)
+ install(APK_ALSO_DEFINING_PERM_A)
+
+ assertThat(allPackages).containsAtLeast(APP_DEFINING_PERM_A, APP_ALSO_DEFINING_PERM_A)
+
+ assertThat(permAInfo.packageName).isEqualTo(APP_DEFINING_PERM_A)
+ }
+
+ @Test
+ fun cannotInstallAppsDefiningSamePermissionWhenDifferentCert() {
+ install(APK_DEFINING_PERM_A)
+ install(APK_ALSO_DEFINING_PERM_A_DIFFERENT_CERT)
+
+ assertThat(allPackages).contains(APP_DEFINING_PERM_A)
+ assertThat(allPackages).doesNotContain(APP_ALSO_DEFINING_PERM_A_DIFFERENT_CERT)
+
+ assertThat(permAInfo.packageName).isEqualTo(APP_DEFINING_PERM_A)
+ }
+
+ @Test
+ fun canInstallAppsDefiningSamePermissionGroupWhenDifferentCertIfSdk30() {
+ install(APK_DEFINING_PERM_A)
+ install(APK_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT_SDK_30)
+
+ assertThat(allPackages)
+ .containsAtLeast(
+ APP_DEFINING_PERM_A,
+ APP_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT_SDK_30
+ )
+
+ assertThat(groupAInfo.packageName).isEqualTo(APP_DEFINING_PERM_A)
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = [146211400])
+ fun cannotInstallAppsDefiningSamePermissionGroupWhenDifferentCert() {
+ install(APK_DEFINING_PERM_A)
+ install(APK_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT)
+
+ assertThat(allPackages).contains(APP_DEFINING_PERM_A)
+ assertThat(allPackages).doesNotContain(APP_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT)
+
+ assertThat(groupAInfo.packageName).isEqualTo(APP_DEFINING_PERM_A)
+ }
+
+ // This is the same as cannotInstallAppsDefiningSamePermissionGroupWhenDifferentCert but this
+ // case is allowed as the package that originally defined the group is a platform.
+ @Test
+ fun canInstallAppsDefiningPermissionInPlatformGroup() {
+ install(APK_DEFINING_PERM_IN_PLATFORM_GROUP)
+
+ assertThat(allPackages).contains(APP_DEFINING_PERM_IN_PLATFORM_GROUP)
+
+ assertThat(permAInfo.packageName).isEqualTo(APP_DEFINING_PERM_IN_PLATFORM_GROUP)
+ assertThat(permAInfo.group).isEqualTo(android.Manifest.permission_group.CAMERA)
+ assertThat(
+ pm.getPermissionGroupInfo(android.Manifest.permission_group.CAMERA, 0)!!.packageName
+ )
+ .isEqualTo("android")
+ }
+
+ @Test
+ fun canInstallAppsDefiningPermissionWithInvalidGroupSdk30() {
+ install(APK_DEFINING_PERM_WITH_INVALID_GROUP_SDK_30)
+
+ assertThat(allPackages).contains(APP_DEFINING_PERM_WITH_INVALID_GROUP_SDK_30)
+
+ assertThat(permAInfo.packageName).isEqualTo(APP_DEFINING_PERM_WITH_INVALID_GROUP_SDK_30)
+ assertThat(permAInfo.group).isEqualTo(INVALID_GROUP)
+ }
+
+ @Test(expected = PackageManager.NameNotFoundException::class)
+ @AsbSecurityTest(cveBugId = [146211400])
+ fun cannotInstallAppsDefiningPermissionWithInvalidGroup() {
+ install(APK_DEFINING_PERM_WITH_INVALID_GROUP)
+
+ assertThat(allPackages).doesNotContain(APP_DEFINING_PERM_WITH_INVALID_GROUP)
+
+ // throws a NameNotFoundException as perm info does not exist
+ permAInfo
+ }
+
+ @After
+ fun uninstallTestApps() {
+ uninstall(APP_DEFINING_PERM_A)
+ uninstall(APP_ALSO_DEFINING_PERM_A)
+ uninstall(APP_ALSO_DEFINING_PERM_A_DIFFERENT_CERT)
+ uninstall(APP_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT)
+ uninstall(APP_ALSO_DEFINING_PERM_GROUP_A_DIFFERENT_CERT_SDK_30)
+ uninstall(APP_DEFINING_PERM_IN_PLATFORM_GROUP)
+ uninstall(APP_DEFINING_PERM_WITH_INVALID_GROUP)
+ uninstall(APP_DEFINING_PERM_WITH_INVALID_GROUP_SDK_30)
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/EthernetManagerPermissionTest.java b/tests/cts/permission/src/android/permission/cts/EthernetManagerPermissionTest.java
new file mode 100644
index 000000000..3c99b34a9
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/EthernetManagerPermissionTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.EthernetManager;
+import android.net.EthernetNetworkUpdateRequest;
+import android.net.IpConfiguration;
+import android.net.NetworkCapabilities;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
+
+/**
+ * Test protected android.net.EthernetManager methods cannot be called without permissions.
+ */
+@RunWith(AndroidJUnit4.class)
+public class EthernetManagerPermissionTest {
+ private static final String TEST_IFACE = "test123abc789";
+ private EthernetManager mEthernetManager;
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mEthernetManager = mContext.getSystemService(EthernetManager.class);
+ // mEthernetManager may be null depending on the device's configuration.
+ assumeNotNull(mEthernetManager);
+ }
+
+ private EthernetNetworkUpdateRequest buildUpdateRequest() {
+ return new EthernetNetworkUpdateRequest.Builder()
+ .setIpConfiguration(new IpConfiguration.Builder().build())
+ .setNetworkCapabilities(new NetworkCapabilities.Builder().build())
+ .build();
+ }
+
+ private EthernetNetworkUpdateRequest buildUpdateRequestWithoutCapabilities() {
+ return new EthernetNetworkUpdateRequest.Builder()
+ .setIpConfiguration(new IpConfiguration.Builder().build())
+ .build();
+ }
+
+ /**
+ * Verify that calling {@link EthernetManager#updateConfiguration(String,
+ * EthernetNetworkUpdateRequest, Executor, BiConsumer)} requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#MANAGE_ETHERNET_NETWORKS}.
+ */
+ @Test
+ public void testUpdateConfigurationRequiresPermissionManageEthernetNetworks() {
+ assertThrows("Should not be able to call updateConfiguration without permission",
+ SecurityException.class,
+ () -> mEthernetManager.updateConfiguration(TEST_IFACE,
+ buildUpdateRequestWithoutCapabilities(), null, null));
+ }
+
+ /**
+ * Verify that calling {@link EthernetManager#enableInterface}
+ * requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#MANAGE_ETHERNET_NETWORKS}.
+ */
+ @Test
+ public void testEnableInterface() {
+ assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE));
+ assertThrows("Should not be able to call enableInterface without permission",
+ SecurityException.class,
+ () -> mEthernetManager.enableInterface(TEST_IFACE, null, null));
+ }
+
+ /**
+ * Verify that calling {@link EthernetManager#disableInterface}
+ * requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#MANAGE_ETHERNET_NETWORKS}.
+ */
+ @Test
+ public void testDisableInterface() {
+ assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE));
+ assertThrows("Should not be able to call disableInterface without permission",
+ SecurityException.class,
+ () -> mEthernetManager.disableInterface(TEST_IFACE, null, null));
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/cts/permission/src/android/permission/cts/FileSystemPermissionTest.java
new file mode 100644
index 000000000..94557464f
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -0,0 +1,1279 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStatVfs;
+import android.util.Pair;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.PropertyUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Verify certain permissions on the filesystem
+ *
+ * TODO: Combine this file with {@link android.os.cts.FileAccessPermissionTest}
+ */
+@RunWith(AndroidJUnit4.class)
+public class FileSystemPermissionTest {
+
+ private int dumpable;
+
+ @Before
+ public void setUp() throws Exception {
+ dumpable = Os.prctl(OsConstants.PR_GET_DUMPABLE, 0, 0, 0, 0);
+ Os.prctl(OsConstants.PR_SET_DUMPABLE, 1, 0, 0, 0);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Os.prctl(OsConstants.PR_SET_DUMPABLE, dumpable, 0, 0, 0);
+ }
+
+ @MediumTest
+ @Test
+ public void testCreateFileHasSanePermissions() throws Exception {
+ File myFile = new File(getContext().getFilesDir(), "hello");
+ FileOutputStream stream = new FileOutputStream(myFile);
+ stream.write("hello world".getBytes());
+ stream.close();
+ try {
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ FileUtils.getFileStatus(myFile.getAbsolutePath(), status, false);
+ int expectedPerms = FileUtils.S_IFREG
+ | FileUtils.S_IWUSR
+ | FileUtils.S_IRUSR;
+ assertEquals(
+ "Newly created files should have 0600 permissions",
+ Integer.toOctalString(expectedPerms),
+ Integer.toOctalString(status.mode));
+ } finally {
+ assertTrue(myFile.delete());
+ }
+ }
+
+ @MediumTest
+ @Test
+ public void testCreateDirectoryHasSanePermissions() throws Exception {
+ File myDir = new File(getContext().getFilesDir(), "helloDirectory");
+ assertTrue(myDir.mkdir());
+ try {
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ FileUtils.getFileStatus(myDir.getAbsolutePath(), status, false);
+ int expectedPerms = FileUtils.S_IFDIR
+ | FileUtils.S_IWUSR
+ | FileUtils.S_IRUSR
+ | FileUtils.S_IXUSR;
+ assertEquals(
+ "Newly created directories should have 0700 permissions",
+ Integer.toOctalString(expectedPerms),
+ Integer.toOctalString(status.mode));
+
+ } finally {
+ assertTrue(myDir.delete());
+ }
+ }
+
+ @MediumTest
+ @Test
+ public void testOtherApplicationDirectoriesAreNotWritable() throws Exception {
+ Set<File> writableDirs = new HashSet<File>();
+ List<ApplicationInfo> apps = getContext()
+ .getPackageManager()
+ .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
+ String myAppDirectory = getContext().getApplicationInfo().dataDir;
+ for (ApplicationInfo app : apps) {
+ if (app.dataDir != null && !myAppDirectory.equals(app.dataDir)) {
+ writableDirs.addAll(getWritableDirectoriesAndSubdirectoriesOf(new File(app.dataDir)));
+ }
+ }
+
+ assertTrue("Found writable directories: " + writableDirs.toString(),
+ writableDirs.isEmpty());
+ }
+
+ @MediumTest
+ @Test
+ public void testApplicationParentDirectoryNotWritable() throws Exception {
+ String myDataDir = getContext().getApplicationInfo().dataDir;
+ File parentDir = new File(myDataDir).getParentFile();
+ assertFalse(parentDir.toString(), isDirectoryWritable(parentDir));
+ }
+
+ @MediumTest
+ @Test
+ public void testDataDirectoryNotWritable() throws Exception {
+ assertFalse(isDirectoryWritable(Environment.getDataDirectory()));
+ }
+
+ @MediumTest
+ @Test
+ public void testAndroidRootDirectoryNotWritable() throws Exception {
+ assertFalse(isDirectoryWritable(Environment.getRootDirectory()));
+ }
+
+ @MediumTest
+ @Test
+ public void testDownloadCacheDirectoryNotWritable() throws Exception {
+ assertFalse(isDirectoryWritable(Environment.getDownloadCacheDirectory()));
+ }
+
+ @MediumTest
+ @Test
+ public void testRootDirectoryNotWritable() throws Exception {
+ assertFalse(isDirectoryWritable(new File("/")));
+ }
+
+ @MediumTest
+ @Test
+ public void testDevDirectoryNotWritable() throws Exception {
+ assertFalse(isDirectoryWritable(new File("/dev")));
+ }
+
+ @MediumTest
+ @Test
+ public void testProcDirectoryNotWritable() throws Exception {
+ assertFalse(isDirectoryWritable(new File("/proc")));
+ }
+
+ @MediumTest
+ @Test
+ public void testDevDiagSane() throws Exception {
+ File f = new File("/dev/diag");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+
+ /* b/26813932 */
+ @MediumTest
+ @Test
+ public void testProcInterruptsNotReadable() throws Exception {
+ File f = new File("/proc/interrupts");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+
+ /* b/26813932 */
+ @MediumTest
+ @Test
+ public void testProcStatNotReadable() throws Exception {
+ File f = new File("/proc/stat");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+
+ @MediumTest
+ @Test
+ public void testDevMemSane() throws Exception {
+ File f = new File("/dev/mem");
+ assertFalse(f.exists());
+ }
+
+ @MediumTest
+ @Test
+ public void testDevkmemSane() throws Exception {
+ File f = new File("/dev/kmem");
+ assertFalse(f.exists());
+ }
+
+ @MediumTest
+ @Test
+ public void testDevPortSane() throws Exception {
+ File f = new File("/dev/port");
+ assertFalse(f.exists());
+ }
+
+ @MediumTest
+ @Test
+ public void testPn544Sane() throws Exception {
+ File f = new File("/dev/pn544");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+
+ assertFileOwnedBy(f, "nfc");
+ assertFileOwnedByGroup(f, "nfc");
+ }
+
+ @MediumTest
+ @Test
+ public void testBcm2079xSane() throws Exception {
+ File f = new File("/dev/bcm2079x");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+
+ assertFileOwnedBy(f, "nfc");
+ assertFileOwnedByGroup(f, "nfc");
+ }
+
+ @MediumTest
+ @Test
+ public void testBcm2079xi2cSane() throws Exception {
+ File f = new File("/dev/bcm2079x-i2c");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+
+ assertFileOwnedBy(f, "nfc");
+ assertFileOwnedByGroup(f, "nfc");
+ }
+
+ @MediumTest
+ @Test
+ public void testDevQtaguidSane() throws Exception {
+ File f = new File("/dev/xt_qtaguid");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+
+ assertFileOwnedBy(f, "root");
+ assertFileOwnedByGroup(f, "root");
+ }
+
+ @MediumTest
+ @Test
+ public void testProcQtaguidCtrlSane() throws Exception {
+ File f = new File("/proc/net/xt_qtaguid/ctrl");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+
+ assertFileOwnedBy(f, "root");
+ assertFileOwnedByGroup(f, "net_bw_acct");
+ }
+
+ @MediumTest
+ @Test
+ public void testProcQtaguidStatsSane() throws Exception {
+ File f = new File("/proc/net/xt_qtaguid/stats");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+
+ assertFileOwnedBy(f, "root");
+ assertFileOwnedByGroup(f, "net_bw_stats");
+ }
+
+ private static List<String> procNetFiles = Arrays.asList("anycast6", "arp", "arp_tables_matches",
+ "arp_tables_names", "arp_tables_targets", "dev", "dev_mcast", "fib_trie", "fib_triestat",
+ "hci", "icmp", "icmp6", "if_inet6", "igmp", "igmp6", "ip6_flowlabel",
+ "ip6_tables_matches", "ip6_tables_names", "ip6_tables_targets", "ip_tables_matches",
+ "ip_tables_names", "ip_tables_targets", "ipv6_route", "l2cap", "mcfilter", "mcfilter6",
+ "netlink", "netstat", "nf_conntrack", "nf_conntrack_expect", "packet", "pfkey", "pnp",
+ "pppoe", "pppol2tp", "protocols", "psched", "ptype", "raw", "raw6", "route", "rt6_stats",
+ "rt_cache", "sco", "snmp", "snmp6", "sockstat", "sockstat6", "softnet_stat", "tcp",
+ "tcp6", "udp", "udp6", "udplite", "udplite6", "unix", "wireless", "xfrm_stat");
+
+ private static void procNetSane(String path) {
+ File f = new File(path);
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ assertFileOwnedBy(f, "root");
+ assertFileOwnedByGroup(f, "root");
+ }
+
+ @MediumTest
+ @Test
+ public void testProcNetSane() throws Exception {
+ if (PropertyUtil.isVendorApiLevelNewerThan(28)) {
+ for (String file : procNetFiles) {
+ procNetSane("/proc/net/" + file);
+ }
+ }
+ }
+
+ private static int readInt(File f) throws FileNotFoundException {
+ try (Scanner s = new Scanner(f)) {
+ return s.nextInt();
+ }
+ }
+
+ private static boolean writeInt(File f, int value) throws IOException {
+ try (FileOutputStream os = new FileOutputStream(f)) {
+ try {
+ os.write(Integer.toString(value).getBytes());
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ }
+
+ @MediumTest
+ @Test
+ public void testProcSelfOomAdjSane() throws IOException {
+ final int OOM_DISABLE = -17;
+
+ File f = new File("/proc/self/oom_adj");
+ assertTrue(f.canRead());
+ assertFalse(f.canExecute());
+
+ int oom_adj = readInt(f);
+ assertNotEquals("unprivileged processes should not be unkillable", OOM_DISABLE, oom_adj);
+ if (f.canWrite())
+ assertFalse("unprivileged processes should not be able to reduce their oom_adj value",
+ writeInt(f, oom_adj - 1));
+ }
+
+ @MediumTest
+ @Test
+ public void testProcSelfOomScoreAdjSane() throws IOException {
+ final int OOM_SCORE_ADJ_MIN = -1000;
+
+ File f = new File("/proc/self/oom_score_adj");
+ assertTrue(f.canRead());
+ assertFalse(f.canExecute());
+
+ int oom_score_adj = readInt(f);
+ assertNotEquals("unprivileged processes should not be unkillable", OOM_SCORE_ADJ_MIN, oom_score_adj);
+ if (f.canWrite()) {
+ assertFalse(
+ "unprivileged processes should not be able to reduce their oom_score_adj value",
+ writeInt(f, oom_score_adj - 1));
+ assertTrue(
+ "unprivileged processes should be able to increase their oom_score_adj value",
+ writeInt(f, oom_score_adj + 1));
+ assertTrue("unprivileged processes should be able to restore their oom_score_adj value",
+ writeInt(f, oom_score_adj));
+ }
+ }
+
+ private static List<Pair<Long, Long>> mappedPageRanges() throws IOException {
+ final BigInteger PAGE_SIZE = new BigInteger("4096");
+
+ final Pattern mapsPattern = Pattern.compile("^(\\p{XDigit}+)-(\\p{XDigit}+)");
+ List<Pair<Long, Long>> ret = new LinkedList<>();
+
+ BufferedReader reader = new BufferedReader(new FileReader("/proc/self/maps"));
+ String line;
+ try {
+ while ((line = reader.readLine()) != null) {
+ Matcher m = mapsPattern.matcher(line);
+ m.find();
+
+ long start = new BigInteger(m.group(1), 16).divide(PAGE_SIZE).longValue();
+ long end = new BigInteger(m.group(2), 16).divide(PAGE_SIZE).longValue();
+
+ ret.add(new Pair<>(start, end));
+ }
+
+ return ret;
+ } finally {
+ reader.close();
+ }
+ }
+
+ private static boolean pfnIsZero(FileDescriptor pagemap, long start, long end) throws ErrnoException, IOException {
+ // Note: reads from /proc/self/pagemap *must* be 64-bit aligned. Use low-level android.system.Os routines to
+ // ensure this.
+ final int SIZEOF_U64 = 8;
+ final long PAGE_PRESENT = 1L << 63;
+ final long PFN_MASK = (1L << 55) - 1;
+
+ for (long page = start; page < end; page++) {
+ long offset = page * SIZEOF_U64;
+ long seek = Os.lseek(pagemap, offset, OsConstants.SEEK_SET);
+ if (offset != seek)
+ throw new IOException("lseek(" + offset + ") returned " + seek);
+
+ byte bytes[] = new byte[SIZEOF_U64];
+ ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.nativeOrder());
+ int read = Os.read(pagemap, buf);
+
+ if (read == 0)
+ // /proc/[pid]/maps may contain entries that are outside the process's VM space,
+ // like the [vectors] page on 32-bit ARM devices. In this case, seek() succeeds but
+ // read() returns 0. The kernel is telling us that there are no more pagemap
+ // entries to read, so we can stop here.
+ break;
+ else if (read != bytes.length)
+ throw new IOException("read(" + bytes.length + ") returned " + read);
+
+ buf.position(0);
+ long entry = buf.getLong();
+ if ((entry & PAGE_PRESENT) == PAGE_PRESENT && (entry & PFN_MASK) != 0)
+ return false;
+ }
+
+ return true;
+ }
+
+ @MediumTest
+ @Test
+ public void testProcSelfPagemapSane() throws ErrnoException, IOException {
+ FileDescriptor pagemap = null;
+ try {
+ pagemap = Os.open("/proc/self/pagemap", OsConstants.O_RDONLY, 0);
+
+ for (Pair<Long, Long> range : mappedPageRanges())
+ if (!pfnIsZero(pagemap, range.first, range.second))
+ fail("Device is missing the following kernel security patch: "
+ + "https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ab676b7d6fbf4b294bf198fb27ade5b0e865c7ce");
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.EPERM)
+ // expected before 4.2
+ return;
+
+ throw e;
+ } finally {
+ if (pagemap != null)
+ Os.close(pagemap);
+ }
+ }
+
+ @MediumTest
+ @Test
+ public void testTcpDefaultRwndSane() throws Exception {
+ File f = new File("/proc/sys/net/ipv4/tcp_default_init_rwnd");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+
+ assertFileOwnedBy(f, "root");
+ assertFileOwnedByGroup(f, "root");
+ }
+
+ @MediumTest
+ @Test
+ public void testIdletimerDirectoryExistsAndSane() throws Exception {
+ File dir = new File("/sys/class/xt_idletimer");
+ assertTrue(dir.isDirectory());
+ assertFalse(dir.canWrite());
+ assertTrue(dir.canExecute());
+
+ assertFileOwnedBy(dir, "root");
+ assertFileOwnedByGroup(dir, "root");
+ }
+
+
+ @MediumTest
+ @Test
+ public void testProcfsMmapRndBitsExistsAndSane() throws Exception {
+ String arch = System.getProperty("os.arch");
+ boolean supported = false;
+ boolean supported_64 = false;
+
+ if (arch.equals("aarch64") || arch.equals("x86_64"))
+ supported_64 = true;
+ else if (arch.startsWith("arm") || arch.endsWith("86"))
+ supported = true;
+
+ /* 64-bit OS should support running 32-bit applications */
+ if (supported_64) {
+ File f = new File("/proc/sys/vm/mmap_rnd_compat_bits");
+ assertTrue(f.exists());
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+
+ if (supported_64 || supported) {
+ File f = new File("/proc/sys/vm/mmap_rnd_bits");
+ assertTrue(f.exists());
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+ }
+
+ /**
+ * Assert that a file is owned by a specific owner. This is a noop if the
+ * file does not exist.
+ *
+ * @param file The file to check.
+ * @param expectedOwner The owner of the file.
+ */
+ private static void assertFileOwnedBy(File file, String expectedOwner) {
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ String path = file.getAbsolutePath();
+ if (file.exists() && FileUtils.getFileStatus(path, status, true)) {
+ String actualOwner = FileUtils.getUserName(status.uid);
+ if (!expectedOwner.equals(actualOwner)) {
+ String msg = String.format("Wrong owner. Expected '%s', but found '%s' for %s.",
+ expectedOwner, actualOwner, path);
+ fail(msg);
+ }
+ }
+ }
+
+ /**
+ * Assert that a file is owned by a specific group. This is a noop if the
+ * file does not exist.
+ *
+ * @param file The file to check.
+ * @param expectedGroup The owner group of the file.
+ */
+ private static void assertFileOwnedByGroup(File file, String expectedGroup) {
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ String path = file.getAbsolutePath();
+ if (file.exists() && FileUtils.getFileStatus(path, status, true)) {
+ String actualGroup = FileUtils.getGroupName(status.gid);
+ if (!expectedGroup.equals(actualGroup)) {
+ String msg = String.format("Wrong group. Expected '%s', but found '%s' for %s.",
+ expectedGroup, actualGroup, path);
+ fail(msg);
+ }
+ }
+ }
+
+ @MediumTest
+ @Test
+ public void testTtyO3Sane() throws Exception {
+ File f = new File("/dev/ttyO3");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+
+ @MediumTest
+ @Test
+ public void testDataMediaSane() throws Exception {
+ final File f = new File("/data/media");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+
+ @MediumTest
+ @Test
+ public void testMntShellSane() throws Exception {
+ final File f = new File("/mnt/shell");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+
+ @MediumTest
+ @Test
+ public void testMntSecureSane() throws Exception {
+ final File f = new File("/mnt/secure");
+ assertFalse(f.canRead());
+ assertFalse(f.canWrite());
+ assertFalse(f.canExecute());
+ }
+
+ private static boolean isDirectoryWritable(File directory) {
+ File toCreate = new File(directory, "hello");
+ try {
+ toCreate.createNewFile();
+ return true;
+ } catch (IOException e) {
+ // It's expected we'll get a "Permission denied" exception.
+ } finally {
+ toCreate.delete();
+ }
+ return false;
+ }
+
+ /**
+ * Verify that any publicly readable directories reachable from
+ * the root directory are not writable. An application should only be
+ * able to write to it's own home directory. World writable directories
+ * are a security hole because they enable a number of different attacks.
+ * <ul>
+ * <li><a href="http://en.wikipedia.org/wiki/Symlink_race">Symlink Races</a></li>
+ * <li>Data destruction by deleting or renaming files you don't own</li>
+ * <li>Data substitution by replacing trusted files with untrusted files</li>
+ * </ul>
+ *
+ * Note: Because not all directories are readable, this is a best-effort
+ * test only. Writable directories within unreadable subdirectories
+ * will NOT be detected by this code.
+ */
+ @LargeTest
+ @Test
+ public void testAllOtherDirectoriesNotWritable() throws Exception {
+ File start = new File("/");
+ Set<File> writableDirs = getWritableDirectoriesAndSubdirectoriesOf(start);
+
+ assertTrue("Found writable directories: " + writableDirs.toString(),
+ writableDirs.isEmpty());
+ }
+
+ private static final Set<String> OTHER_RANDOM_DIRECTORIES = new HashSet<String>(
+ Arrays.asList(
+ "/app-cache",
+ "/app-cache/ciq/socket",
+ "/cache/fotapkg",
+ "/cache/fotapkg/tmp",
+ "/data/_SamsungBnR_",
+ "/data/_SamsungBnR_/BR",
+ "/data/2nd-init",
+ "/data/amit",
+ "/data/anr",
+ "/data/app",
+ "/data/app-private",
+ "/data/backup",
+ "/data/battd",
+ "/data/bootlogo",
+ "/data/btips",
+ "/data/btips/TI",
+ "/data/btips/TI/opp",
+ "/data/cache",
+ "/data/calibration",
+ "/data/clipboard",
+ "/data/clp",
+ "/data/dalvik-cache",
+ "/data/data",
+ "/data/data/.drm",
+ "/data/data/.drm/.wmdrm",
+ "/data/data/cw",
+ "/data/data/com.android.htcprofile",
+ "/data/data/com.android.providers.drm/rights",
+ "/data/data/com.htc.android.qxdm2sd",
+ "/data/data/com.htc.android.qxdm2sd/bin",
+ "/data/data/com.htc.android.qxdm2sd/data",
+ "/data/data/com.htc.android.qxdm2sd/tmp",
+ "/data/data/com.htc.android.netlogger/data",
+ "/data/data/com.htc.messagecs/att",
+ "/data/data/com.htc.messagecs/pdu",
+ "/data/data/com.htc.loggers/bin",
+ "/data/data/com.htc.loggers/data",
+ "/data/data/com.htc.loggers/htclog",
+ "/data/data/com.htc.loggers/tmp",
+ "/data/data/com.htc.loggers/htcghost",
+ "/data/data/com.lge.ers/android",
+ "/data/data/com.lge.ers/arm9",
+ "/data/data/com.lge.ers/kernel",
+ "/data/data/com.lge.wmc",
+ "/data/data/com.redbend.vdmc/lib",
+ "/data/data/recovery",
+ "/data/data/recovery/HTCFOTA",
+ "/data/data/recovery/OMADM",
+ "/data/data/shared",
+ "/data/diag_logs",
+ "/data/dontpanic",
+ "/data/drm",
+ "/data/drm/fwdlock",
+ "/data/drm/IDM",
+ "/data/drm/IDM/HTTP",
+ "/data/drm/rights",
+ "/data/dump",
+ "/data/efslog",
+ "/data/emt",
+ "/data/factory",
+ "/data/fics",
+ "/data/fics/dev",
+ "/data/fota",
+ "/data/gps",
+ "/data/gps/log",
+ "/data/gps/var",
+ "/data/gps/var/run",
+ "/data/gpscfg",
+ "/data/hwvefs",
+ "/data/htcfs",
+ "/data/img",
+ "/data/install",
+ "/data/internal-device",
+ "/data/internal-device/DCIM",
+ "/data/last_alog",
+ "/data/last_klog",
+ "/data/local",
+ "/data/local/logs",
+ "/data/local/logs/kernel",
+ "/data/local/logs/logcat",
+ "/data/local/logs/resetlog",
+ "/data/local/logs/smem",
+ "/data/local/mono",
+ "/data/local/mono/pulse",
+ "/data/local/purple",
+ "/data/local/purple/sound",
+ "/data/local/rights",
+ "/data/local/rwsystag",
+ "/data/local/skel",
+ "/data/local/skel/default",
+ "/data/local/skel/defualt", // Mispelled "defualt" is intentional
+ "/data/local/tmp",
+ "/data/local/tmp/com.nuance.android.vsuite.vsuiteapp",
+ "/data/log",
+ "/data/logger",
+ "/data/logs",
+ "/data/logs/core",
+ "/data/lost+found",
+ "/data/mdl",
+ "/data/misc",
+ "/data/misc/bluetooth",
+ "/data/misc/bluetooth/logs",
+ "/data/misc/dhcp",
+ "/data/misc/lockscreen",
+ "/data/misc/sensor",
+ "/data/misc/webwidgets",
+ "/data/misc/webwidgets/chess",
+ "/data/misc/widgets",
+ "/data/misc/wifi",
+ "/data/misc/wifi/sockets",
+ "/data/misc/wimax",
+ "/data/misc/wimax/sockets",
+ "/data/misc/wminput",
+ "/data/misc/wpa_supplicant",
+ "/data/nv",
+ "/data/nvcam",
+ "/data/panic",
+ "/data/panicreports",
+ "/data/preinstall_md5",
+ "/data/property",
+ "/data/radio",
+ "/data/secure",
+ "/data/security",
+ "/data/sensors",
+ "/data/shared",
+ "/data/simcom",
+ "/data/simcom/btadd",
+ "/data/simcom/simlog",
+ "/data/system",
+ "/data/tmp",
+ "/data/tombstones",
+ "/data/tombstones/ramdump",
+ "/data/tpapi",
+ "/data/tpapi/etc",
+ "/data/tpapi/etc/tpa",
+ "/data/tpapi/etc/tpa/persistent",
+ "/data/tpapi/user.bin",
+ "/data/vpnch",
+ "/data/wapi",
+ "/data/wifi",
+ "/data/wimax",
+ "/data/wimax/log",
+ "/data/wiper",
+ "/data/wpstiles",
+ "/data/xt9",
+ "/dbdata/databases",
+ "/efs/.android",
+ "/mnt/sdcard",
+ "/mnt/usbdrive",
+ "/mnt_ext",
+ "/mnt_ext/badablk2",
+ "/mnt_ext/badablk3",
+ "/mnt_ext/cache",
+ "/mnt_ext/data",
+ "/system/etc/security/drm",
+ "/synthesis/hades",
+ "/synthesis/chimaira",
+ "/synthesis/shdisp",
+ "/synthesis/hdmi",
+ "/tmp"
+ )
+ );
+
+ /**
+ * Verify that directories not discoverable by
+ * testAllOtherDirectoriesNotWritable are not writable. An application
+ * should only be able to write to it's own home directory. World
+ * writable directories are a security hole because they enable a
+ * number of different attacks.
+ * <ul>
+ * <li><a href="http://en.wikipedia.org/wiki/Symlink_race">Symlink Races</a></li>
+ * <li>Data destruction by deleting or renaming files you don't own</li>
+ * <li>Data substitution by replacing trusted files with untrusted files</li>
+ * </ul>
+ *
+ * Because /data and /data/data are not readable, we blindly try to
+ * poke around in there looking for bad directories. There has to be
+ * a better way...
+ */
+ @LargeTest
+ @Test
+ public void testOtherRandomDirectoriesNotWritable() throws Exception {
+ Set<File> writableDirs = new HashSet<File>();
+ for (String dir : OTHER_RANDOM_DIRECTORIES) {
+ File start = new File(dir);
+ writableDirs.addAll(getWritableDirectoriesAndSubdirectoriesOf(start));
+ }
+
+ assertTrue("Found writable directories: " + writableDirs.toString(),
+ writableDirs.isEmpty());
+ }
+
+ @LargeTest
+ @Test
+ public void testReadingSysFilesDoesntFail() throws Exception {
+ ExecutorService executor = Executors.newCachedThreadPool();
+ tryToReadFromAllIn(new File("/sys"), executor);
+ executor.shutdownNow();
+ }
+
+ private static void tryToReadFromAllIn(File dir, ExecutorService executor) throws IOException {
+ assertTrue(dir.isDirectory());
+
+ if (isSymbolicLink(dir)) {
+ // don't examine symbolic links.
+ return;
+ }
+
+ File[] files = dir.listFiles();
+
+ if (files != null) {
+ for (File f : files) {
+ if (f.isDirectory()) {
+ tryToReadFromAllIn(f, executor);
+ } else {
+ tryFileOpenRead(f, executor);
+ }
+ }
+ }
+ }
+
+ private static void tryFileOpenRead(final File f, ExecutorService executor) throws IOException {
+ // Callable requires stack variables to be final.
+ Callable<Boolean> readFile = new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return tryFileRead(f);
+ }
+ };
+
+ Boolean completed = false;
+ String fileName = null;
+ Future<Boolean> future = null;
+ try {
+ fileName = f.getCanonicalPath();
+
+ future = executor.submit(readFile);
+
+ // Block, waiting no more than set seconds.
+ completed = future.get(3, TimeUnit.SECONDS);
+ } catch (TimeoutException e) {
+ System.out.println("TIMEOUT: " + fileName);
+ } catch (InterruptedException e) {
+ System.out.println("INTERRUPTED: " + fileName);
+ } catch (ExecutionException e) {
+ System.out.println("TASK WAS ABORTED BY EXCEPTION: " + fileName);
+ } catch (IOException e) {
+ // File.getCanonicalPath() will throw this.
+ } finally {
+ if (future != null) {
+ future.cancel(true);
+ }
+ }
+ }
+
+ private static Boolean tryFileRead(File f) {
+ byte[] b = new byte[1024];
+ try {
+ System.out.println("looking at " + f.getCanonicalPath());
+
+ FileInputStream fis = new FileInputStream(f);
+ while((fis.available() != 0) && (fis.read(b) != -1)) {
+ // throw away data
+ }
+
+ fis.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ return true;
+ }
+
+ private static final Set<File> SYS_EXCEPTIONS = new HashSet<File>(
+ Arrays.asList(
+ new File("/sys/kernel/debug/tracing/trace_marker"),
+ new File("/sys/fs/selinux/member"),
+ new File("/sys/fs/selinux/user"),
+ new File("/sys/fs/selinux/relabel"),
+ new File("/sys/fs/selinux/create"),
+ new File("/sys/fs/selinux/access"),
+ new File("/sys/fs/selinux/context"),
+ new File("/sys/fs/selinux/validatetrans")
+ ));
+
+ @LargeTest
+ @Test
+ public void testAllFilesInSysAreNotWritable() throws Exception {
+ Set<File> writable = getAllWritableFilesInDirAndSubDir(new File("/sys"));
+ writable.removeAll(SYS_EXCEPTIONS);
+ assertTrue("Found writable: " + writable.toString(),
+ writable.isEmpty());
+ }
+
+ private static Set<File>
+ getAllWritableFilesInDirAndSubDir(File dir) throws Exception {
+ assertTrue(dir.isDirectory());
+ Set<File> retval = new HashSet<File>();
+
+ if (isSymbolicLink(dir)) {
+ // don't examine symbolic links.
+ return retval;
+ }
+
+ File[] subDirectories = dir.listFiles(new FileFilter() {
+ @Override public boolean accept(File pathname) {
+ return pathname.isDirectory();
+ }
+ });
+
+
+ /* recurse into subdirectories */
+ if (subDirectories != null) {
+ for (File f : subDirectories) {
+ retval.addAll(getAllWritableFilesInDirAndSubDir(f));
+ }
+ }
+
+ File[] filesInThisDirectory = dir.listFiles(new FileFilter() {
+ @Override public boolean accept(File pathname) {
+ return pathname.isFile();
+ }
+ });
+ if (filesInThisDirectory == null) {
+ return retval;
+ }
+
+ for (File f: filesInThisDirectory) {
+ if (f.canWrite()) {
+ retval.add(f.getCanonicalFile());
+ }
+ }
+ return retval;
+ }
+
+ @Test
+ public void testSystemMountedRO() throws Exception {
+ StructStatVfs vfs = Os.statvfs("/system");
+ assertTrue("/system is not mounted read-only", (vfs.f_flag & OsConstants.ST_RDONLY) != 0);
+ }
+
+ @Test
+ public void testRootMountedRO() throws Exception {
+ StructStatVfs vfs = Os.statvfs("/");
+ assertTrue("rootfs is not mounted read-only", (vfs.f_flag & OsConstants.ST_RDONLY) != 0);
+ }
+
+ @Test
+ public void testVendorMountedRO() throws Exception {
+ StructStatVfs vfs = Os.statvfs("/vendor");
+ assertTrue("/vendor is not mounted read-only", (vfs.f_flag & OsConstants.ST_RDONLY) != 0);
+ }
+
+ @Test
+ public void testOdmMountedRO() throws Exception {
+ StructStatVfs vfs = Os.statvfs("/odm");
+ assertTrue("/odm is not mounted read-only", (vfs.f_flag & OsConstants.ST_RDONLY) != 0);
+ }
+
+ @Test
+ public void testOemMountedRO() throws Exception {
+ StructStatVfs vfs = Os.statvfs("/oem");
+ assertTrue("/oem is not mounted read-only", (vfs.f_flag & OsConstants.ST_RDONLY) != 0);
+ }
+
+ @Test
+ public void testDataMountedNoSuidNoDev() throws Exception {
+ StructStatVfs vfs = Os.statvfs(getContext().getFilesDir().getAbsolutePath());
+ assertTrue("/data is not mounted NOSUID", (vfs.f_flag & OsConstants.ST_NOSUID) != 0);
+ assertTrue("/data is not mounted NODEV", (vfs.f_flag & OsConstants.ST_NODEV) != 0);
+ }
+
+ @Test
+ public void testAllBlockDevicesAreSecure() throws Exception {
+ Set<File> insecure = getAllInsecureDevicesInDirAndSubdir(new File("/dev"), FileUtils.S_IFBLK);
+ assertTrue("Found insecure block devices: " + insecure.toString(),
+ insecure.isEmpty());
+ }
+
+ @Test
+ public void testDevRandomWorldReadableAndWritable() throws Exception {
+ File f = new File("/dev/random");
+
+ assertTrue(f + " cannot be opened for reading", canOpenForReading(f));
+ assertTrue(f + " cannot be opened for writing", canOpenForWriting(f));
+
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ assertTrue(FileUtils.getFileStatus(f.getPath(), status, false));
+ assertTrue(
+ f + " not world-readable/writable. Actual mode: 0"
+ + Integer.toString(status.mode, 8),
+ (status.mode & 0666) == 0666);
+ }
+
+ @Test
+ public void testDevUrandomWorldReadableAndWritable() throws Exception {
+ File f = new File("/dev/urandom");
+
+ assertTrue(f + " cannot be opened for reading", canOpenForReading(f));
+ assertTrue(f + " cannot be opened for writing", canOpenForWriting(f));
+
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ assertTrue(FileUtils.getFileStatus(f.getPath(), status, false));
+ assertTrue(
+ f + " not world-readable/writable. Actual mode: 0"
+ + Integer.toString(status.mode, 8),
+ (status.mode & 0666) == 0666);
+ }
+
+ @Test
+ public void testProcUUIDReadable() throws Exception {
+ File f = new File("/proc/sys/kernel/random/uuid");
+
+ assertTrue(f + " cannot be opened for reading", canOpenForReading(f));
+ assertFalse(f + " can be opened for writing", canOpenForWriting(f));
+
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ assertTrue(FileUtils.getFileStatus(f.getPath(), status, false));
+ assertTrue(
+ f + " not 0444. Actual mode: 0"
+ + Integer.toString(status.mode, 8),
+ (status.mode & 0666) == 0444);
+ }
+
+ @Test
+ public void testDevHwRandomLockedDown() throws Exception {
+ File f = new File("/dev/hw_random");
+ if (!f.exists()) {
+ // HW RNG is not required to be exposed on all devices.
+ return;
+ }
+
+ // SELinux policy should ensure that the file isn't visible to apps at
+ // all.
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ assertFalse("stat permitted on " + f + " (SELinux issue?)",
+ FileUtils.getFileStatus(f.getPath(), status, false));
+
+ // Double-check that we really can't read/write the file.
+ assertFalse(f + " can be opened for reading (SELinux issue?)", canOpenForReading(f));
+ assertFalse(f + " can be opened for writing (SELinux issue?)", canOpenForWriting(f));
+ }
+
+ private static boolean canOpenForReading(File f) {
+ try (InputStream in = new FileInputStream(f)) {
+ return true;
+ } catch (IOException expected) {
+ return false;
+ }
+ }
+
+ private static boolean canOpenForWriting(File f) {
+ try (OutputStream out = new FileOutputStream(f)) {
+ return true;
+ } catch (IOException expected) {
+ return false;
+ }
+ }
+
+ @Test
+ public void testFileHasOnlyCapsThrowsOnInvalidCaps() throws Exception {
+ try {
+ // Ensure negative cap id fails.
+ new FileUtils.CapabilitySet()
+ .add(-1)
+ .fileHasOnly("/system/bin/run-as");
+ fail();
+ }
+ catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ // Ensure too-large cap throws.
+ new FileUtils.CapabilitySet()
+ .add(OsConstants.CAP_LAST_CAP + 1)
+ .fileHasOnly("/system/bin/run-as");
+ fail();
+ }
+ catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that the /system/bin/run-as command has setuid and setgid
+ * attributes set on the file. If these calls fail, debugger
+ * breakpoints for native code will not work as run-as will not
+ * be able to perform required elevated-privilege functionality.
+ */
+ @Test
+ public void testRunAsHasCorrectCapabilities() throws Exception {
+ // ensure file is user and group read/executable
+ String filename = "/system/bin/run-as";
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ assertTrue(FileUtils.getFileStatus(filename, status, false));
+ assertTrue(status.hasModeFlag(FileUtils.S_IRUSR | FileUtils.S_IXUSR));
+ assertTrue(status.hasModeFlag(FileUtils.S_IRGRP | FileUtils.S_IXGRP));
+
+ // ensure file owner/group is set correctly
+ File f = new File(filename);
+ assertFileOwnedBy(f, "root");
+ assertFileOwnedByGroup(f, "shell");
+
+ // ensure file has setuid/setgid enabled
+ assertTrue(FileUtils.hasSetUidCapability(filename));
+ assertTrue(FileUtils.hasSetGidCapability(filename));
+
+ // ensure file has *only* setuid/setgid attributes enabled
+ assertTrue(new FileUtils.CapabilitySet()
+ .add(OsConstants.CAP_SETUID)
+ .add(OsConstants.CAP_SETGID)
+ .fileHasOnly("/system/bin/run-as"));
+ }
+
+ private static Set<File>
+ getAllInsecureDevicesInDirAndSubdir(File dir, int type) throws Exception {
+ assertTrue(dir.isDirectory());
+ Set<File> retval = new HashSet<File>();
+
+ if (isSymbolicLink(dir)) {
+ // don't examine symbolic links.
+ return retval;
+ }
+
+ File[] subDirectories = dir.listFiles(new FileFilter() {
+ @Override public boolean accept(File pathname) {
+ return pathname.isDirectory();
+ }
+ });
+
+
+ /* recurse into subdirectories */
+ if (subDirectories != null) {
+ for (File f : subDirectories) {
+ retval.addAll(getAllInsecureDevicesInDirAndSubdir(f, type));
+ }
+ }
+
+ File[] filesInThisDirectory = dir.listFiles();
+ if (filesInThisDirectory == null) {
+ return retval;
+ }
+
+ for (File f: filesInThisDirectory) {
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ FileUtils.getFileStatus(f.getAbsolutePath(), status, false);
+ if (status.isOfType(type)) {
+ if (f.canRead() || f.canWrite() || f.canExecute()) {
+ retval.add(f);
+ }
+ if (status.uid == 2000) {
+ // The shell user should not own any devices
+ retval.add(f);
+ }
+
+ // Don't allow devices owned by GIDs
+ // accessible to non-privileged applications.
+ if ((status.gid == 1007) // AID_LOG
+ || (status.gid == 1015) // AID_SDCARD_RW
+ || (status.gid == 1023) // AID_MEDIA_RW
+ || (status.gid == 1028) // AID_SDCARD_R
+ || (status.gid == 2000)) // AID_SHELL
+ {
+ if (status.hasModeFlag(FileUtils.S_IRGRP)
+ || status.hasModeFlag(FileUtils.S_IWGRP)
+ || status.hasModeFlag(FileUtils.S_IXGRP))
+ {
+ retval.add(f);
+ }
+ }
+ }
+ }
+ return retval;
+ }
+
+ private Set<File> getWritableDirectoriesAndSubdirectoriesOf(File dir) throws Exception {
+ Set<File> retval = new HashSet<File>();
+ if (!dir.isDirectory()) {
+ return retval;
+ }
+
+ if (isSymbolicLink(dir)) {
+ // don't examine symbolic links.
+ return retval;
+ }
+
+ String myHome = getContext().getApplicationInfo().dataDir;
+ String thisDir = dir.getCanonicalPath();
+ if (thisDir.startsWith(myHome)) {
+ // Don't examine directories within our home directory.
+ // We expect these directories to be writable.
+ return retval;
+ }
+
+ if (isDirectoryWritable(dir)) {
+ retval.add(dir);
+ }
+
+ File[] subFiles = dir.listFiles();
+ if (subFiles == null) {
+ return retval;
+ }
+
+ for (File f : subFiles) {
+ retval.addAll(getWritableDirectoriesAndSubdirectoriesOf(f));
+ }
+
+ return retval;
+ }
+
+ private static boolean isSymbolicLink(File f) throws IOException {
+ return !f.getAbsolutePath().equals(f.getCanonicalPath());
+ }
+
+}
diff --git a/tests/cts/permission/src/android/permission/cts/FileUtils.java b/tests/cts/permission/src/android/permission/cts/FileUtils.java
new file mode 100644
index 000000000..0743cd30a
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/FileUtils.java
@@ -0,0 +1,128 @@
+package android.permission.cts;
+
+/*
+ * Copyright (C) 2010 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.
+ */
+
+import android.system.OsConstants;
+
+import com.google.common.primitives.Ints;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/** Bits and pieces copied from hidden API of android.os.FileUtils. */
+public class FileUtils {
+
+ public static final int S_IFMT = 0170000;
+ public static final int S_IFSOCK = 0140000;
+ public static final int S_IFLNK = 0120000;
+ public static final int S_IFREG = 0100000;
+ public static final int S_IFBLK = 0060000;
+ public static final int S_IFDIR = 0040000;
+ public static final int S_IFCHR = 0020000;
+ public static final int S_IFIFO = 0010000;
+
+ public static final int S_ISUID = 0004000;
+ public static final int S_ISGID = 0002000;
+ public static final int S_ISVTX = 0001000;
+
+ public static final int S_IRWXU = 00700;
+ public static final int S_IRUSR = 00400;
+ public static final int S_IWUSR = 00200;
+ public static final int S_IXUSR = 00100;
+
+ public static final int S_IRWXG = 00070;
+ public static final int S_IRGRP = 00040;
+ public static final int S_IWGRP = 00020;
+ public static final int S_IXGRP = 00010;
+
+ public static final int S_IRWXO = 00007;
+ public static final int S_IROTH = 00004;
+ public static final int S_IWOTH = 00002;
+ public static final int S_IXOTH = 00001;
+
+ static {
+ System.loadLibrary("ctspermission_jni");
+ }
+
+ public static class FileStatus {
+
+ public int dev;
+ public int ino;
+ public int mode;
+ public int nlink;
+ public int uid;
+ public int gid;
+ public int rdev;
+ public long size;
+ public int blksize;
+ public long blocks;
+ public long atime;
+ public long mtime;
+ public long ctime;
+
+ public boolean hasModeFlag(int flag) {
+ if (((S_IRWXU | S_IRWXG | S_IRWXO) & flag) != flag) {
+ throw new IllegalArgumentException("Inappropriate flag " + flag);
+ }
+ return (mode & flag) == flag;
+ }
+
+ public boolean isOfType(int type) {
+ if ((type & S_IFMT) != type) {
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ return (mode & S_IFMT) == type;
+ }
+ }
+
+ public static class CapabilitySet {
+
+ private final Set<Integer> mCapabilities = new HashSet<Integer>();
+
+ public CapabilitySet add(int capability) {
+ if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
+ throw new IllegalArgumentException(String.format(
+ "capability id %d out of valid range", capability));
+ }
+ mCapabilities.add(capability);
+ return this;
+ }
+
+ private native static boolean fileHasOnly(String path,
+ int[] capabilities);
+
+ public boolean fileHasOnly(String path) {
+ return fileHasOnly(path, Ints.toArray(mCapabilities));
+ }
+ }
+
+ /**
+ * @param path of the file to stat
+ * @param status object to set the fields on
+ * @param statLinks or don't stat links (lstat vs stat)
+ * @return whether or not we were able to stat the file
+ */
+ public native static boolean getFileStatus(String path, FileStatus status, boolean statLinks);
+
+ public native static String getUserName(int uid);
+
+ public native static String getGroupName(int gid);
+
+ public native static boolean hasSetUidCapability(String path);
+
+ public native static boolean hasSetGidCapability(String path);
+}
diff --git a/tests/cts/permission/src/android/permission/cts/IgnoreAllTestsRule.java b/tests/cts/permission/src/android/permission/cts/IgnoreAllTestsRule.java
new file mode 100644
index 000000000..45288bd48
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/IgnoreAllTestsRule.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import org.junit.rules.MethodRule;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+/**
+ * A {@link org.junit.Rule} that will cause all tests in the class
+ * to be ignored if the argument to the constructor is true.
+ */
+public class IgnoreAllTestsRule implements MethodRule {
+
+ private boolean mIgnore;
+
+ /**
+ * Creates a new IgnoreAllTestsRule
+ * @param ignore If true, all tests in the class will be ignored. If false, this rule will
+ * do nothing.
+ */
+ public IgnoreAllTestsRule(boolean ignore) {
+ mIgnore = ignore;
+ }
+
+ @Override
+ public Statement apply(Statement base, FrameworkMethod method, Object target) {
+ if (mIgnore) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ }
+ };
+ } else {
+ return base;
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/cts/permission/src/android/permission/cts/LocationAccessCheckTest.java
new file mode 100644
index 000000000..f59883921
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -0,0 +1,806 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.Context.BIND_NOT_FOREGROUND;
+import static android.location.Criteria.ACCURACY_FINE;
+import static android.os.Process.myUserHandle;
+import static android.provider.Settings.Secure.LOCATION_ACCESS_CHECK_DELAY_MILLIS;
+import static android.provider.Settings.Secure.LOCATION_ACCESS_CHECK_INTERVAL_MILLIS;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.waitForBroadcasts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.AppOpsManager;
+import android.app.PendingIntent;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Process;
+import android.permission.cts.appthataccesseslocation.IAccessLocationOnCommand;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.platform.test.annotations.SystemUserOnly;
+import android.platform.test.rule.ScreenRecordRule;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
+import com.android.compatibility.common.util.mainline.MainlineModule;
+import com.android.compatibility.common.util.mainline.ModuleDetector;
+import com.android.modules.utils.build.SdkLevel;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Tests the {@code LocationAccessCheck} in permission controller.
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Cannot set system settings as instant app. Also we never show a location "
+ + "access check notification for instant apps.")
+@ScreenRecordRule.ScreenRecord
+@FlakyTest
+public class LocationAccessCheckTest {
+
+ private static final String LOG_TAG = LocationAccessCheckTest.class.getSimpleName();
+
+ private static final String TEST_APP_PKG = "android.permission.cts.appthataccesseslocation";
+ private static final String TEST_APP_LABEL = "CtsLocationAccess";
+ private static final String TEST_APP_SERVICE = TEST_APP_PKG + ".AccessLocationOnCommand";
+ private static final String TEST_APP_LOCATION_BG_ACCESS_APK =
+ "/data/local/tmp/cts-permission/CtsAppThatAccessesLocationOnCommand.apk";
+ private static final String TEST_APP_LOCATION_FG_ACCESS_APK =
+ "/data/local/tmp/cts-permission/AppThatDoesNotHaveBgLocationAccess.apk";
+ private static final String ACTION_SET_UP_LOCATION_ACCESS_CHECK =
+ "com.android.permissioncontroller.action.SET_UP_LOCATION_ACCESS_CHECK";
+ private static final int LOCATION_ACCESS_CHECK_JOB_ID = 0;
+ private static final int LOCATION_ACCESS_CHECK_NOTIFICATION_ID = 0;
+
+ private static final String PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS =
+ "location_access_check_delay_millis";
+ private static final String PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS =
+ "location_access_check_periodic_interval_millis";
+ private static final String PROPERTY_BG_LOCATION_CHECK_ENABLED = "bg_location_check_is_enabled";
+
+ private static final long UNEXPECTED_TIMEOUT_MILLIS = 10000;
+ private static final long EXPECTED_TIMEOUT_MILLIS = 15000;
+ private static final long LOCATION_ACCESS_TIMEOUT_MILLIS = 15000;
+
+ private static final Context sContext = InstrumentationRegistry.getTargetContext();
+ private static final ActivityManager sActivityManager =
+ sContext.getSystemService(ActivityManager.class);
+ private static final PackageManager sPackageManager = sContext.getPackageManager();
+ private static final AppOpsManager sAppOpsManager =
+ sContext.getSystemService(AppOpsManager.class);
+ private static final LocationManager sLocationManager =
+ sContext.getSystemService(LocationManager.class);
+ private static final UiAutomation sUiAutomation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+
+ private static final String PERMISSION_CONTROLLER_PKG = sContext.getPackageManager()
+ .getPermissionControllerPackageName();
+ private static final String LocationAccessCheckOnBootReceiver =
+ "com.android.permissioncontroller.permission.service"
+ + ".LocationAccessCheck$SetupPeriodicBackgroundLocationAccessCheck";
+
+
+ /**
+ * The result of {@link #assumeCanGetFineLocation()}, so we don't have to run it over and over
+ * again.
+ */
+ private static Boolean sCanAccessFineLocation = null;
+
+ private static ServiceConnection sConnection;
+ private static IAccessLocationOnCommand sLocationAccessor;
+
+ private static void assumeNotPlayManaged() throws Exception {
+ assumeFalse(ModuleDetector.moduleIsPlayManaged(
+ sContext.getPackageManager(), MainlineModule.PERMISSION_CONTROLLER));
+ }
+
+ @Rule
+ public final ScreenRecordRule mScreenRecordRule = new ScreenRecordRule(false, false);
+
+ // Override SafetyCenter enabled flag
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigSafetyCenterEnabled =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SafetyCenterUtils.PROPERTY_SAFETY_CENTER_ENABLED,
+ Boolean.toString(true));
+
+ // Override BG location enabled flag
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigBgLocationCheckEnabled =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_BG_LOCATION_CHECK_ENABLED,
+ Boolean.toString(true));
+
+ // Override general notification interval
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigBgCheckIntervalMillis =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS,
+ "100");
+
+ // Override general delay interval
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigBgCheckDelayMillis =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS,
+ "50");
+
+ private static boolean sWasLocationEnabled = true;
+
+ @BeforeClass
+ public static void beforeClassSetup() throws Exception {
+ reduceDelays();
+ allowNotificationAccess();
+ installBackgroundAccessApp();
+ runWithShellPermissionIdentity(() -> {
+ sWasLocationEnabled = sLocationManager.isLocationEnabled();
+ if (!sWasLocationEnabled) {
+ sLocationManager.setLocationEnabledForUser(true, Process.myUserHandle());
+ }
+ });
+ }
+
+ /**
+ * Change settings so that permission controller can show location access notifications more
+ * often.
+ */
+ public static void reduceDelays() {
+ runWithShellPermissionIdentity(() -> {
+ ContentResolver cr = sContext.getContentResolver();
+ // New settings will be applied in when permission controller is reset
+ Settings.Secure.putLong(cr, LOCATION_ACCESS_CHECK_INTERVAL_MILLIS, 100);
+ Settings.Secure.putLong(cr, LOCATION_ACCESS_CHECK_DELAY_MILLIS, 50);
+ });
+ }
+
+ @AfterClass
+ public static void cleanupAfterClass() throws Throwable {
+ resetDelays();
+ uninstallTestApp();
+ disallowNotificationAccess();
+ runWithShellPermissionIdentity(() -> {
+ if (!sWasLocationEnabled) {
+ sLocationManager.setLocationEnabledForUser(false, Process.myUserHandle());
+ }
+ });
+ }
+
+ /**
+ * Reset settings so that permission controller runs normally.
+ */
+ public static void resetDelays() throws Throwable {
+ runWithShellPermissionIdentity(() -> {
+ ContentResolver cr = sContext.getContentResolver();
+ Settings.Secure.resetToDefaults(cr, LOCATION_ACCESS_CHECK_INTERVAL_MILLIS);
+ Settings.Secure.resetToDefaults(cr, LOCATION_ACCESS_CHECK_DELAY_MILLIS);
+ });
+ }
+
+ /**
+ * Connected to {@value #TEST_APP_PKG} and make it access the location in the background
+ */
+ private void accessLocation() throws Throwable {
+ if (sConnection == null || sLocationAccessor == null) {
+ bindService();
+ }
+
+ long beforeAccess = System.currentTimeMillis();
+ // Wait a little to avoid raciness in timing between threads
+ Thread.sleep(1000);
+
+ // Try again until binder call goes though. It might not go through if the sLocationAccessor
+ // is not bound yet
+ eventually(() -> {
+ assertNotNull(sLocationAccessor);
+ sLocationAccessor.accessLocation();
+ }, EXPECTED_TIMEOUT_MILLIS);
+
+ // Wait until the access is recorded
+ eventually(() -> {
+ List<AppOpsManager.PackageOps> ops = runWithShellPermissionIdentity(
+ () -> sAppOpsManager.getOpsForPackage(
+ sPackageManager.getPackageUid(TEST_APP_PKG, 0), TEST_APP_PKG,
+ OPSTR_FINE_LOCATION));
+
+ // Background access must have happened after "beforeAccess"
+ assertTrue(ops.get(0).getOps().get(0).getLastAccessBackgroundTime(OP_FLAGS_ALL_TRUSTED)
+ >= beforeAccess);
+ }, EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ /**
+ * A {@link java.util.concurrent.Callable} that can throw a {@link Throwable}
+ */
+ private interface ThrowingCallable<T> {
+ T call() throws Throwable;
+ }
+
+ /**
+ * A {@link Runnable} that can throw a {@link Throwable}
+ */
+ private interface ThrowingRunnable {
+ void run() throws Throwable;
+ }
+
+ /**
+ * Make sure that a {@link ThrowingRunnable} eventually finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingRunnable} to run.
+ * @param timeout the maximum time to wait
+ */
+ public static void eventually(@NonNull ThrowingRunnable r, long timeout) throws Throwable {
+ eventually(() -> {
+ r.run();
+ return 0;
+ }, timeout);
+ }
+
+ /**
+ * Make sure that a {@link ThrowingCallable} eventually finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingCallable} to run.
+ * @param timeout the maximum time to wait
+ * @return the return value from the callable
+ * @throws NullPointerException If the return value never becomes non-null
+ */
+ public static <T> T eventually(@NonNull ThrowingCallable<T> r, long timeout) throws Throwable {
+ long start = System.currentTimeMillis();
+
+ while (true) {
+ try {
+ T res = r.call();
+ if (res == null) {
+ throw new NullPointerException("No result");
+ }
+
+ return res;
+ } catch (Throwable e) {
+ if (System.currentTimeMillis() - start < timeout) {
+ Log.d(LOG_TAG, "Ignoring exception", e);
+
+ Thread.sleep(500);
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Clear all data of a package including permissions and files.
+ *
+ * @param pkg The name of the package to be cleared
+ */
+ private static void clearPackageData(@NonNull String pkg) {
+ unbindService();
+ runShellCommand("pm clear --user -2 " + pkg);
+ }
+
+ private static boolean isJobReady() {
+ String jobStatus = runShellCommand("cmd jobscheduler get-job-state -u "
+ + Process.myUserHandle().getIdentifier() + " " + PERMISSION_CONTROLLER_PKG
+ + " " + LOCATION_ACCESS_CHECK_JOB_ID);
+ return jobStatus.contains("waiting");
+ }
+
+ /**
+ * Force a run of the location check.
+ */
+ private static void runLocationCheck() throws Throwable {
+ if (!isJobReady()) {
+ PermissionUtils.scheduleJob(sUiAutomation, PERMISSION_CONTROLLER_PKG,
+ LOCATION_ACCESS_CHECK_JOB_ID, EXPECTED_TIMEOUT_MILLIS,
+ ACTION_SET_UP_LOCATION_ACCESS_CHECK, LocationAccessCheckOnBootReceiver);
+ }
+
+ TestUtils.awaitJobUntilRequestedState(
+ PERMISSION_CONTROLLER_PKG,
+ LOCATION_ACCESS_CHECK_JOB_ID,
+ EXPECTED_TIMEOUT_MILLIS,
+ sUiAutomation,
+ "waiting"
+ );
+
+ TestUtils.runJobAndWaitUntilCompleted(
+ PERMISSION_CONTROLLER_PKG,
+ LOCATION_ACCESS_CHECK_JOB_ID,
+ EXPECTED_TIMEOUT_MILLIS,
+ sUiAutomation
+ );
+ }
+
+ /**
+ * Get a location access notification that is currently visible.
+ *
+ * @param cancelNotification if {@code true} the notification is canceled inside this method
+ * @return The notification or {@code null} if there is none
+ */
+ private StatusBarNotification getNotification(boolean cancelNotification) throws Throwable {
+ return CtsNotificationListenerServiceUtils.getNotificationForPackageAndId(
+ PERMISSION_CONTROLLER_PKG, LOCATION_ACCESS_CHECK_NOTIFICATION_ID,
+ cancelNotification);
+ }
+
+ /**
+ * Grant a permission to the {@value #TEST_APP_PKG}.
+ *
+ * @param permission The permission to grant
+ */
+ private void grantPermissionToTestApp(@NonNull String permission) {
+ sUiAutomation.grantRuntimePermission(TEST_APP_PKG, permission);
+ }
+
+ /**
+ * Register {@link CtsNotificationListenerService}.
+ */
+ public static void allowNotificationAccess() {
+ runShellCommand("cmd notification allow_listener " + (new ComponentName(sContext,
+ CtsNotificationListenerService.class).flattenToString()));
+ }
+
+ public static void installBackgroundAccessApp() throws Exception {
+ String output =
+ runShellCommandOrThrow("pm install -r -g " + TEST_APP_LOCATION_BG_ACCESS_APK);
+ assertTrue(output.contains("Success"));
+ // Wait for user sensitive to be updated, which is checked by LocationAccessCheck.
+ Thread.sleep(5000);
+ }
+
+ public static void uninstallTestApp() {
+ unbindService();
+ runShellCommand("pm uninstall " + TEST_APP_PKG);
+ }
+
+ private static void unbindService() {
+ if (sConnection != null) {
+ sContext.unbindService(sConnection);
+ }
+ sConnection = null;
+ sLocationAccessor = null;
+ }
+
+ private static void installForegroundAccessApp() throws Exception {
+ unbindService();
+ runShellCommandOrThrow("pm install -r -g " + TEST_APP_LOCATION_FG_ACCESS_APK);
+ // Wait for user sensitive to be updated, which is checked by LocationAccessCheck.
+ Thread.sleep(5000);
+ }
+
+ /**
+ * Skip each test for low ram device
+ */
+ public void assumeIsNotLowRamDevice() {
+ assumeFalse(sActivityManager.isLowRamDevice());
+ }
+
+ public void wakeUpAndDismissKeyguard() {
+ runShellCommand("input keyevent KEYCODE_WAKEUP");
+ runShellCommand("wm dismiss-keyguard");
+ }
+
+ public void bindService() {
+ sConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ sLocationAccessor = IAccessLocationOnCommand.Stub.asInterface(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ sConnection = null;
+ sLocationAccessor = null;
+ }
+ };
+
+ Intent testAppService = new Intent();
+ testAppService.setComponent(new ComponentName(TEST_APP_PKG, TEST_APP_SERVICE));
+
+ sContext.bindService(testAppService, sConnection, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND);
+ }
+
+ @Before
+ public void beforeEachTestSetup() throws Throwable {
+ assumeIsNotLowRamDevice();
+ wakeUpAndDismissKeyguard();
+ bindService();
+ resetPermissionControllerBeforeEachTest();
+ bypassBatterySavingRestrictions();
+ assumeCanGetFineLocation();
+ }
+
+ /**
+ * Reset the permission controllers state before each test
+ */
+ public void resetPermissionControllerBeforeEachTest() throws Throwable {
+ // Has to be before resetPermissionController to make sure enablement time is the reset time
+ // of permission controller
+ runLocationCheck();
+
+ resetPermissionController();
+
+ eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ // Reset job scheduler stats (to allow more jobs to be run)
+ runShellCommand(
+ "cmd jobscheduler reset-execution-quota -u " + myUserHandle().getIdentifier() + " "
+ + PERMISSION_CONTROLLER_PKG);
+ runShellCommand("cmd jobscheduler reset-schedule-quota");
+ }
+
+ public void bypassBatterySavingRestrictions() {
+ runShellCommand("cmd tare set-vip " + myUserHandle().getIdentifier()
+ + " " + PERMISSION_CONTROLLER_PKG + " true");
+ }
+
+ /**
+ * Make sure fine location can be accessed at all.
+ */
+ public void assumeCanGetFineLocation() {
+ if (sCanAccessFineLocation == null) {
+ Criteria crit = new Criteria();
+ crit.setAccuracy(ACCURACY_FINE);
+
+ CountDownLatch locationCounter = new CountDownLatch(1);
+ sContext.getSystemService(LocationManager.class).requestSingleUpdate(crit,
+ new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ locationCounter.countDown();
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ }
+ }, Looper.getMainLooper());
+
+
+ try {
+ sCanAccessFineLocation = locationCounter.await(LOCATION_ACCESS_TIMEOUT_MILLIS,
+ MILLISECONDS);
+ } catch (InterruptedException ignored) {
+ }
+ }
+
+ assumeTrue(sCanAccessFineLocation);
+ }
+
+ /**
+ * Reset the permission controllers state.
+ */
+ private static void resetPermissionController() throws Throwable {
+ unbindService();
+ PermissionUtils.resetPermissionControllerJob(sUiAutomation, PERMISSION_CONTROLLER_PKG,
+ LOCATION_ACCESS_CHECK_JOB_ID, 45000,
+ ACTION_SET_UP_LOCATION_ACCESS_CHECK, LocationAccessCheckOnBootReceiver);
+ }
+
+ /**
+ * Unregister {@link CtsNotificationListenerService}.
+ */
+ public static void disallowNotificationAccess() {
+ runShellCommand("cmd notification disallow_listener " + (new ComponentName(sContext,
+ CtsNotificationListenerService.class)).flattenToString());
+ }
+
+ @After
+ public void cleanupAfterEachTest() throws Throwable {
+ resetPrivacyConfig();
+ locationUnbind();
+ resetBatterySavingRestrictions();
+ }
+
+ /**
+ * Reset location access check
+ */
+ public void resetPrivacyConfig() throws Throwable {
+ // Run a location access check to update enabled state inside permission controller
+ runLocationCheck();
+ }
+
+ public void locationUnbind() throws Throwable {
+ unbindService();
+ }
+
+ public void resetBatterySavingRestrictions() {
+ runShellCommand("cmd tare set-vip " + myUserHandle().getIdentifier()
+ + " " + PERMISSION_CONTROLLER_PKG + " default");
+ }
+
+ @Test
+ public void notificationIsShown() throws Throwable {
+ accessLocation();
+ runLocationCheck();
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 141028068)
+ public void notificationIsShownOnlyOnce() throws Throwable {
+ assumeNotPlayManaged();
+
+ accessLocation();
+ runLocationCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+
+ accessLocation();
+ runLocationCheck();
+
+ assertNull(getNotification(true));
+ }
+
+ @SystemUserOnly(reason = "b/172259935")
+ @Test
+ @AsbSecurityTest(cveBugId = 141028068)
+ public void notificationIsShownAgainAfterClear() throws Throwable {
+ assumeNotPlayManaged();
+ accessLocation();
+ runLocationCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+
+ clearPackageData(TEST_APP_PKG);
+
+ // Wait until package is cleared and permission controller has cleared the state
+ Thread.sleep(10000);
+ waitForBroadcasts();
+
+ // Clearing removed the permissions, hence grant them again
+ grantPermissionToTestApp(ACCESS_FINE_LOCATION);
+ grantPermissionToTestApp(ACCESS_BACKGROUND_LOCATION);
+
+ accessLocation();
+ runLocationCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @SystemUserOnly(reason = "b/172259935")
+ @Test
+ public void notificationIsShownAgainAfterUninstallAndReinstall() throws Throwable {
+ accessLocation();
+ runLocationCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+
+ uninstallTestApp();
+
+ // Wait until package permission controller has cleared the state
+ Thread.sleep(2000);
+
+ installBackgroundAccessApp();
+ waitForBroadcasts();
+ accessLocation();
+ runLocationCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 141028068)
+ public void removeNotificationOnUninstall() throws Throwable {
+ assumeNotPlayManaged();
+
+ accessLocation();
+ runLocationCheck();
+
+ eventually(() -> assertNotNull(getNotification(false)), EXPECTED_TIMEOUT_MILLIS);
+
+ uninstallTestApp();
+ // wait for permission controller (broadcast receiver) to clean up things
+ Thread.sleep(5000);
+ waitForBroadcasts();
+
+ try {
+ eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
+ } finally {
+ installBackgroundAccessApp();
+ }
+ }
+
+ @Test
+ public void notificationIsNotShownAfterAppDoesNotRequestLocationAnymore() throws Throwable {
+ accessLocation();
+ runLocationCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+
+ // Update to app to a version that does not request permission anymore
+ installForegroundAccessApp();
+
+ try {
+ resetPermissionController();
+
+ runLocationCheck();
+
+ // We don't expect a notification, but try to trigger one anyway
+ assertNull(getNotification(false));
+ } finally {
+ installBackgroundAccessApp();
+ }
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 141028068)
+ public void noNotificationIfBlamerNotSystemOrLocationProvider() throws Throwable {
+ assumeNotPlayManaged();
+
+ // Blame the app for access from an untrusted for notification purposes package.
+ runWithShellPermissionIdentity(() -> {
+ AppOpsManager appOpsManager = sContext.getSystemService(AppOpsManager.class);
+ appOpsManager.noteProxyOpNoThrow(OPSTR_FINE_LOCATION, TEST_APP_PKG,
+ sContext.getPackageManager().getPackageUid(TEST_APP_PKG, 0));
+ });
+ runLocationCheck();
+
+ assertNull(getNotification(false));
+ }
+
+ @Test
+ // Mark as flaky until b/286874765 is fixed
+ @FlakyTest
+ @MtsIgnore
+ @AsbSecurityTest(cveBugId = 141028068)
+ public void testOpeningLocationSettingsDoesNotTriggerAccess() throws Throwable {
+ assumeNotPlayManaged();
+
+ Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ sContext.startActivity(intent);
+
+ runLocationCheck();
+ assertNull(getNotification(false));
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 141028068)
+ public void noNotificationWhenLocationNeverAccessed() throws Throwable {
+ assumeNotPlayManaged();
+
+ // Reset to clear property location_access_check_enabled_time has been already happened
+ // when resetPermissionController() invoked from before test method
+
+ runLocationCheck();
+
+ // Not expecting notification as location is not accessed and previously set
+ // LOCATION_ACCESS_CHECK_ENABLED_TIME if any is cleaned up
+ assertNull(getNotification(false));
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 141028068)
+ public void notificationWhenLocationAccessed() throws Throwable {
+ assumeNotPlayManaged();
+
+ // Reset to clear property location_access_check_enabled_time has been already happened
+ // when resetPermissionController() invoked from before test method
+
+ accessLocation();
+ runLocationCheck();
+
+ // Expecting notification as accessing the location causes
+ // LOCATION_ACCESS_CHECK_ENABLED_TIME to be set
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 141028068)
+ public void noNotificationWhenLocationAccessedPriorToEnableTime() throws Throwable {
+ assumeNotPlayManaged();
+
+ accessLocation();
+
+ // Reset to clear the property location_access_check_enabled_time
+ resetPermissionController();
+
+ runLocationCheck();
+
+ // Not expecting the notification as the location
+ // access was prior to LOCATION_ACCESS_CHECK_ENABLED_TIME (No notification for prior events)
+ assertNull(getNotification(false));
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ public void notificationOnClickOpensSafetyCenter() throws Throwable {
+ assumeTrue(SafetyCenterUtils.deviceSupportsSafetyCenter(sContext));
+ accessLocation();
+ runLocationCheck();
+
+ StatusBarNotification currentNotification = eventually(() -> {
+ StatusBarNotification notification = getNotification(false);
+ assertNotNull(notification);
+ return notification;
+ }, EXPECTED_TIMEOUT_MILLIS);
+
+ // Verify content intent
+ PendingIntent contentIntent = currentNotification.getNotification().contentIntent;
+ if (SdkLevel.isAtLeastU()) {
+ contentIntent.send(null, 0, null, null, null, null,
+ ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle());
+ } else {
+ contentIntent.send();
+ }
+
+ SafetyCenterUtils.assertSafetyCenterStarted();
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/MainlineNetworkStackPermissionTest.java b/tests/cts/permission/src/android/permission/cts/MainlineNetworkStackPermissionTest.java
new file mode 100644
index 000000000..adac0befa
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/MainlineNetworkStackPermissionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class MainlineNetworkStackPermissionTest{
+ private final Context mContext = InstrumentationRegistry.getContext();
+
+ /**
+ * Test that a package defining android.permission.MAINLINE_NETWORK_STACK is installed,
+ * and is a system package
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot access PackageManager#getPermissionInfo")
+ public void testPackageWithMainlineNetworkStackPermission() throws Exception {
+ final PackageManager packageManager = mContext.getPackageManager();
+ assertNotNull("Unable to find PackageManager.", packageManager);
+
+ final PermissionInfo permissioninfo =
+ packageManager.getPermissionInfo(PERMISSION_MAINLINE_NETWORK_STACK, 0);
+ assertNotNull("Network stack permission is not defined.", permissioninfo);
+
+ PackageInfo packageInfo = packageManager.getPackageInfo(permissioninfo.packageName,
+ PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_PERMISSIONS);
+ assertNotNull("Package defining the network stack permission is not a system package.",
+ packageInfo.permissions);
+
+ for (PermissionInfo permission : packageInfo.permissions) {
+ if (PERMISSION_MAINLINE_NETWORK_STACK.equals(permission.name)) {
+ return;
+ }
+ }
+
+ fail("Expect a system package defining " + PERMISSION_MAINLINE_NETWORK_STACK
+ + " is installed.");
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/MinMaxSdkVersionTest.kt b/tests/cts/permission/src/android/permission/cts/MinMaxSdkVersionTest.kt
new file mode 100644
index 000000000..4679fbee8
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/MinMaxSdkVersionTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.app.Instrumentation
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import android.permission.cts.PermissionUtils.install
+import android.platform.test.annotations.AppModeFull
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import androidx.test.uiautomator.UiDevice
+import com.android.compatibility.common.util.CddTest
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@CddTest(requirement = "9.1/C-0-1")
+@AppModeFull(reason = "Instant apps cannot read state of other packages.")
+class MinMaxSdkVersionTest {
+ private val mInstrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private var mUiDevice: UiDevice? = null
+ private var mContext: Context? = null
+
+ @Before
+ fun setup() {
+ mUiDevice = UiDevice.getInstance(mInstrumentation)
+ mContext = mInstrumentation?.targetContext
+ }
+
+ @Test
+ fun givenMinSdkVersionInRangeThenPermissionIsRequested() {
+ install(TEST_APP_PATH)
+
+ Assert.assertTrue(appRequestsPermission(MINSDK_LT_DEVICESDK))
+ }
+
+ @Test
+ fun givenMinSdkVersionOutOfRangeThenPermissionIsNotRequested() {
+ install(TEST_APP_PATH)
+
+ Assert.assertFalse(appRequestsPermission(MINSDK_GT_DEVICESDK))
+ }
+
+ @Test
+ fun givenMaxSdkVersionInRangeThenPermissionIsRequested() {
+ install(TEST_APP_PATH)
+
+ Assert.assertTrue(appRequestsPermission(MAXSDK_GT_DEVICESDK))
+ }
+
+ @Test
+ fun givenMaxSdkVersionOutOfRangeThenPermissionIsNotRequested() {
+ install(TEST_APP_PATH)
+
+ Assert.assertFalse(appRequestsPermission(MAXSDK_LT_DEVICESDK))
+ }
+
+ private fun appRequestsPermission(permName: String): Boolean {
+ val packageInfo =
+ mContext!!
+ .packageManager
+ .getPackageInfo(TEST_APP_PKG_NAME, PackageManager.GET_PERMISSIONS)
+ return packageInfo.requestedPermissions!!.any { it == permName }
+ }
+
+ companion object {
+ private const val TEST_APP_NAME = "CtsAppThatRequestsMultiplePermissionsWithMinMaxSdk.apk"
+ private const val TMP_DIR = "/data/local/tmp/cts-permission/"
+ private const val TEST_APP_PATH = TMP_DIR + TEST_APP_NAME
+ private const val TEST_APP_PKG_NAME = "android.permission.cts.appthatrequestpermission"
+ private const val CUSTOM_PERMS = "$TEST_APP_PKG_NAME.permissions"
+ private const val MINSDK_LT_DEVICESDK = "$CUSTOM_PERMS.MINSDK_LT_DEVICESDK"
+ private const val MINSDK_GT_DEVICESDK = "$CUSTOM_PERMS.MINSDK_GT_DEVICESDK"
+ private const val MAXSDK_LT_DEVICESDK = "$CUSTOM_PERMS.MAXSDK_LT_DEVICESDK"
+ private const val MAXSDK_GT_DEVICESDK = "$CUSTOM_PERMS.MAXSDK_GT_DEVICESDK"
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NearbyDevicesPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NearbyDevicesPermissionTest.java
new file mode 100644
index 000000000..d4ad2ad04
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NearbyDevicesPermissionTest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_SCAN;
+import static android.permission.cts.PermissionUtils.grantPermission;
+import static android.permission.cts.PermissionUtils.install;
+import static android.permission.cts.PermissionUtils.revokePermission;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import android.bluetooth.cts.EnableBluetoothRule;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.EnableLocationRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests the behavior of the
+ * {@link android.Manifest.permission_group#NEARBY_DEVICES} permission group
+ * under various permutations of grant states.
+ *
+ * Note that some tests will be recognized as known failures with the new permission subsystem
+ * until b/273999500 is fixed.
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+public class NearbyDevicesPermissionTest {
+ private static final String TEST_APP_PKG = "android.permission.cts.appthatrequestpermission";
+ private static final String TEST_APP_AUTHORITY = "appthatrequestpermission";
+ private static final String DISAVOWAL_APP_PKG = "android.permission.cts.appneverforlocation";
+
+ private static final String TMP_DIR = "/data/local/tmp/cts-permission/";
+ private static final String APK_BLUETOOTH_30 = TMP_DIR
+ + "CtsAppThatRequestsBluetoothPermission30.apk";
+ private static final String APK_BLUETOOTH_31 = TMP_DIR
+ + "CtsAppThatRequestsBluetoothPermission31.apk";
+ private static final String APK_BLUETOOTH_NEVER_FOR_LOCATION_31 = TMP_DIR
+ + "CtsAppThatRequestsBluetoothPermissionNeverForLocation31.apk";
+ private static final String APK_BLUETOOTH_NEVER_FOR_LOCATION_NO_PROVIDER = TMP_DIR
+ + "CtsAppThatRequestsBluetoothPermissionNeverForLocationNoProvider.apk";
+
+ private enum Result {
+ UNKNOWN, EXCEPTION, EMPTY, FILTERED, FULL
+ }
+
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+
+ @ClassRule
+ public static final EnableBluetoothRule sEnableBluetoothRule = new EnableBluetoothRule(true);
+
+ @Rule
+ public final EnableLocationRule enableLocationRule = new EnableLocationRule();
+
+ public void uninstallTestApp() {
+ uninstallApp(TEST_APP_PKG);
+ uninstallApp(DISAVOWAL_APP_PKG);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ uninstallTestApp();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ uninstallTestApp();
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermission30_Default() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_30);
+ assertScanBluetoothResult(Result.EMPTY);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermission30_GrantLocation() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_30);
+ grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION);
+ grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION);
+ assertScanBluetoothResult(Result.FULL);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermission31_Default() throws Throwable {
+ install(APK_BLUETOOTH_31);
+ assertScanBluetoothResult(Result.EXCEPTION);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermission31_GrantNearby() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_31);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_CONNECT);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_SCAN);
+ assertScanBluetoothResult(Result.EMPTY);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermission31_GrantLocation() throws Throwable {
+ install(APK_BLUETOOTH_31);
+ grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION);
+ grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION);
+ assertScanBluetoothResult(Result.EXCEPTION);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermission31_GrantNearby_GrantLocation() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_31);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_CONNECT);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_SCAN);
+ grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION);
+ grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION);
+ assertScanBluetoothResult(Result.FULL);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermissionNeverForLocation31_Default() throws Throwable {
+ install(APK_BLUETOOTH_NEVER_FOR_LOCATION_31);
+ assertScanBluetoothResult(Result.EXCEPTION);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermissionNeverForLocation31_GrantNearby() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_NEVER_FOR_LOCATION_31);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_CONNECT);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_SCAN);
+ assertScanBluetoothResult(Result.FILTERED);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermissionNeverForLocation31_GrantLocation() throws Throwable {
+ install(APK_BLUETOOTH_NEVER_FOR_LOCATION_31);
+ grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION);
+ grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION);
+ assertScanBluetoothResult(Result.EXCEPTION);
+ }
+
+ @Test
+ @CddTest(requirement = "7.4.3/C-6-1")
+ public void testRequestBluetoothPermissionNeverForLocation31_GrantNearby_GrantLocation()
+ throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_NEVER_FOR_LOCATION_31);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_CONNECT);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_SCAN);
+ grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION);
+ grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION);
+ assertScanBluetoothResult(Result.FILTERED);
+ }
+
+ @Test
+ public void testRequestBluetoothPermission31_OnBehalfOfDisavowingApp() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_31);
+ install(APK_BLUETOOTH_NEVER_FOR_LOCATION_NO_PROVIDER);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_CONNECT);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_SCAN);
+ grantPermission(DISAVOWAL_APP_PKG, BLUETOOTH_CONNECT);
+ grantPermission(DISAVOWAL_APP_PKG, BLUETOOTH_SCAN);
+ assertScanBluetoothResult("PROXY", Result.FILTERED);
+ }
+
+ /**
+ * Verify that a legacy app that was unable to interact with Bluetooth
+ * devices is still unable to interact with them after updating to a modern
+ * SDK; they'd always need to involve the user to gain permissions.
+ */
+ @Test
+ public void testRequestBluetoothPermission_Default_Upgrade() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_30);
+ assertScanBluetoothResult(Result.EMPTY);
+
+ // Upgrading to target a new SDK level means they need to explicitly
+ // request the new runtime permission; by default it's denied
+ install(APK_BLUETOOTH_NEVER_FOR_LOCATION_31);
+ assertScanBluetoothResult(Result.EXCEPTION);
+
+ // If the user does grant it, they can scan again
+ grantPermission(TEST_APP_PKG, BLUETOOTH_CONNECT);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_SCAN);
+ assertScanBluetoothResult(Result.FILTERED);
+ }
+
+ /**
+ * Verify that a legacy app that was able to interact with Bluetooth devices
+ * is still able to interact with them after updating to a modern SDK.
+ */
+ @Test
+ public void testRequestBluetoothPermission_GrantLocation_Upgrade() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_30);
+ grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION);
+ grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION);
+ assertScanBluetoothResult(Result.FULL);
+
+ // Upgrading to target a new SDK level means they still have the access
+ // they enjoyed as a legacy app
+ install(APK_BLUETOOTH_31);
+ assertScanBluetoothResult(Result.FULL);
+ }
+
+ /**
+ * Verify that downgrading an app doesn't gain them any access to Bluetooth
+ * scan results; they'd always need to involve the user to gain permissions.
+ */
+ @Test
+ public void testRequestBluetoothPermission_Downgrade() throws Throwable {
+ assumeTrue(supportsBluetoothLe());
+
+ install(APK_BLUETOOTH_31);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_CONNECT);
+ grantPermission(TEST_APP_PKG, BLUETOOTH_SCAN);
+ grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION);
+ grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION);
+ assertScanBluetoothResult(Result.FULL);
+
+ // Revoking nearby permission means modern app can't scan
+ revokePermission(TEST_APP_PKG, BLUETOOTH_CONNECT);
+ revokePermission(TEST_APP_PKG, BLUETOOTH_SCAN);
+ assertScanBluetoothResult(Result.EXCEPTION);
+
+ // And if they attempt to downgrade, confirm that they can't obtain the
+ // split-permission grant from the older non-runtime permissions
+ install(APK_BLUETOOTH_30);
+ assertScanBluetoothResult(Result.EXCEPTION);
+ }
+
+ private void assertScanBluetoothResult(Result expected) {
+ assertScanBluetoothResult(null, expected);
+ }
+
+ private void assertScanBluetoothResult(String arg, Result expected) {
+ SystemClock.sleep(1000); // Wait for location permissions to propagate
+ final ContentResolver resolver = InstrumentationRegistry.getTargetContext()
+ .getContentResolver();
+ final Bundle res = resolver.call(TEST_APP_AUTHORITY, "", arg, null);
+ Result actual = Result.values()[res.getInt(Intent.EXTRA_INDEX)];
+ assertEquals(expected, actual);
+ }
+
+ private boolean supportsBluetoothLe() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
+ }
+
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NearbyDevicesRenouncePermissionTest.java b/tests/cts/permission/src/android/permission/cts/NearbyDevicesRenouncePermissionTest.java
new file mode 100644
index 000000000..aeb4d1d28
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NearbyDevicesRenouncePermissionTest.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.AppOpsManager;
+import android.app.AsyncNotedAppOp;
+import android.app.SyncNotedAppOp;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.cts.EnableBluetoothRule;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanResult;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.content.ContextParams;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.DeviceConfig;
+import android.util.ArraySet;
+import android.util.Base64;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
+import com.android.compatibility.common.util.EnableLocationRule;
+import com.android.compatibility.common.util.SystemUtil;
+
+import com.google.common.util.concurrent.Uninterruptibles;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Tests behaviour when performing bluetooth scans with renounced location permission.
+ */
+public class NearbyDevicesRenouncePermissionTest {
+
+ private static final String TAG = "NearbyDevicesRenouncePermissionTest";
+ private static final String OPSTR_BLUETOOTH_SCAN = "android:bluetooth_scan";
+
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+
+ @ClassRule
+ public static final EnableBluetoothRule sEnableBluetoothRule = new EnableBluetoothRule(true);
+
+ @Rule
+ public DeviceConfigStateChangerRule safetyLabelChangeNotificationsEnabledConfig =
+ new DeviceConfigStateChangerRule(
+ mContext,
+ DeviceConfig.NAMESPACE_BLUETOOTH,
+ "scan_quota_count",
+ Integer.toString(1000)
+ );
+
+ @Rule
+ public final EnableLocationRule enableLocationRule = new EnableLocationRule();
+
+ private AppOpsManager mAppOpsManager;
+
+ private volatile long mTestStartTimestamp;
+ private final AtomicInteger mLocationNoteCount = new AtomicInteger(0);
+ private final AtomicInteger mScanNoteCount = new AtomicInteger(0);
+
+ private enum Result {
+ UNKNOWN, EXCEPTION, EMPTY, FILTERED, FULL
+ }
+
+ private enum Scenario {
+ DEFAULT, RENOUNCE, RENOUNCE_MIDDLE, RENOUNCE_END
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ // Sleep to guarantee that past noteOp timestamps are less than mTestStartTimestamp
+ Uninterruptibles.sleepUninterruptibly(2, TimeUnit.MILLISECONDS);
+ mTestStartTimestamp = System.currentTimeMillis();
+
+ mLocationNoteCount.set(0);
+ mScanNoteCount.set(0);
+
+ mAppOpsManager = getApplicationContext().getSystemService(AppOpsManager.class);
+ mAppOpsManager.setOnOpNotedCallback(getApplicationContext().getMainExecutor(),
+ new AppOpsManager.OnOpNotedCallback() {
+ @Override
+ public void onNoted(SyncNotedAppOp op) {
+ switch (op.getOp()) {
+ case OPSTR_FINE_LOCATION:
+ logNoteOp(op);
+ mLocationNoteCount.incrementAndGet();
+ break;
+ case OPSTR_BLUETOOTH_SCAN:
+ logNoteOp(op);
+ mScanNoteCount.incrementAndGet();
+ break;
+ default:
+ }
+ }
+
+ @Override
+ public void onSelfNoted(SyncNotedAppOp op) {
+ }
+
+ @Override
+ public void onAsyncNoted(AsyncNotedAppOp asyncOp) {
+ switch (asyncOp.getOp()) {
+ case OPSTR_FINE_LOCATION:
+ logNoteOp(asyncOp);
+ if (asyncOp.getTime() < mTestStartTimestamp) {
+ Log.i(TAG, "ignoring asyncOp that originated before test "
+ + "start");
+ return;
+ }
+ mLocationNoteCount.incrementAndGet();
+ break;
+ case OPSTR_BLUETOOTH_SCAN:
+ logNoteOp(asyncOp);
+ if (asyncOp.getTime() < mTestStartTimestamp) {
+ Log.i(TAG, "ignoring asyncOp that originated before test "
+ + "start");
+ return;
+ }
+ mScanNoteCount.incrementAndGet();
+ break;
+ default:
+ }
+ }
+ });
+ }
+
+ private void logNoteOp(SyncNotedAppOp op) {
+ Log.i(TAG, "OnOpNotedCallback::onNoted(op=" + op.getOp() + ")");
+ }
+
+ private void logNoteOp(AsyncNotedAppOp asyncOp) {
+ Log.i(TAG, "OnOpNotedCallback::"
+ + "onAsyncNoted(op=" + asyncOp.getOp()
+ + ", testStartTimestamp=" + mTestStartTimestamp
+ + ", noteOpTimestamp=" + asyncOp.getTime() + ")");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mAppOpsManager.setOnOpNotedCallback(null, null);
+ }
+
+ @AppModeFull
+ @Test
+ public void scanWithoutRenouncingNotesBluetoothAndLocation() throws Exception {
+ assumeTrue(supportsBluetoothLe());
+
+ assertThat(performScan(Scenario.DEFAULT)).isEqualTo(Result.FULL);
+ SystemUtil.eventually(() -> {
+ assertThat(mLocationNoteCount.get()).isGreaterThan(0);
+ assertThat(mScanNoteCount.get()).isGreaterThan(0);
+ });
+ }
+
+ @AppModeFull
+ @Test
+ public void scanRenouncingLocationNotesBluetoothButNotLocation() throws Exception {
+ assumeTrue(supportsBluetoothLe());
+
+ assertThat(performScan(Scenario.RENOUNCE)).isEqualTo(Result.FILTERED);
+ SystemUtil.eventually(() -> {
+ assertThat(mLocationNoteCount.get()).isEqualTo(0);
+ assertThat(mScanNoteCount.get()).isGreaterThan(0);
+ });
+ }
+
+ @AppModeFull
+ @Test
+ public void scanRenouncingInMiddleOfChainNotesBluetoothButNotLocation() throws Exception {
+ assumeTrue(supportsBluetoothLe());
+
+ assertThat(performScan(Scenario.RENOUNCE_MIDDLE)).isEqualTo(Result.FILTERED);
+ SystemUtil.eventually(() -> {
+ assertThat(mLocationNoteCount.get()).isEqualTo(0);
+ assertThat(mScanNoteCount.get()).isGreaterThan(0);
+ });
+ }
+
+ @AppModeFull
+ @Test
+ public void scanRenouncingAtEndOfChainNotesBluetoothButNotLocation() throws Exception {
+ assertThat(performScan(Scenario.RENOUNCE_END)).isEqualTo(Result.FILTERED);
+ SystemUtil.eventually(() -> {
+ assertThat(mLocationNoteCount.get()).isEqualTo(0);
+ assertThat(mScanNoteCount.get()).isGreaterThan(0);
+ });
+ }
+
+ private Result performScan(Scenario scenario) {
+ try {
+ Context context = createContext(scenario, getApplicationContext());
+
+ final BluetoothManager bm = context.getSystemService(BluetoothManager.class);
+ final BluetoothLeScanner scanner = bm.getAdapter().getBluetoothLeScanner();
+
+ final HashSet<String> observed = new HashSet<>();
+
+ ScanCallback callback = new ScanCallback() {
+ public void onScanResult(int callbackType, ScanResult result) {
+ Log.v(TAG, String.valueOf(result));
+ observed.add(Base64.encodeToString(result.getScanRecord().getBytes(), 0));
+ }
+
+ public void onBatchScanResults(List<ScanResult> results) {
+ for (ScanResult result : results) {
+ onScanResult(0, result);
+ }
+ }
+ };
+ scanner.startScan(callback);
+
+ // Wait a few seconds to figure out what we actually observed
+ SystemClock.sleep(3000);
+ scanner.stopScan(callback);
+ switch (observed.size()) {
+ case 0:
+ return Result.EMPTY;
+ case 1:
+ return Result.FILTERED;
+ case 5:
+ return Result.FULL;
+ default:
+ return Result.UNKNOWN;
+ }
+ } catch (Throwable t) {
+ Log.v(TAG, "Failed to scan", t);
+ return Result.EXCEPTION;
+ }
+ }
+
+ private Context createContext(Scenario scenario, Context context) throws Exception {
+ if (scenario == Scenario.DEFAULT) {
+ return context;
+ }
+
+ Set<String> renouncedPermissions = new ArraySet<>();
+ renouncedPermissions.add(ACCESS_FINE_LOCATION);
+
+ switch (scenario) {
+ case RENOUNCE:
+ return SystemUtil.callWithShellPermissionIdentity(() ->
+ context.createContext(
+ new ContextParams.Builder()
+ .setRenouncedPermissions(renouncedPermissions)
+ .setAttributionTag(context.getAttributionTag())
+ .build())
+ );
+ case RENOUNCE_MIDDLE:
+ AttributionSource nextAttrib = new AttributionSource(
+ Process.SHELL_UID, "com.android.shell", null, (Set<String>) null, null);
+ return SystemUtil.callWithShellPermissionIdentity(() ->
+ context.createContext(
+ new ContextParams.Builder()
+ .setRenouncedPermissions(renouncedPermissions)
+ .setAttributionTag(context.getAttributionTag())
+ .setNextAttributionSource(nextAttrib)
+ .build())
+ );
+ case RENOUNCE_END:
+ nextAttrib = new AttributionSource(
+ Process.SHELL_UID, "com.android.shell", null, renouncedPermissions, null);
+ return SystemUtil.callWithShellPermissionIdentity(() ->
+ context.createContext(
+ new ContextParams.Builder()
+ .setAttributionTag(context.getAttributionTag())
+ .setNextAttributionSource(nextAttrib)
+ .build())
+ );
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ private boolean supportsBluetoothLe() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NfcPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NfcPermissionTest.java
new file mode 100644
index 000000000..1b3f65ee6
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NfcPermissionTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.ActivityManager;
+import android.content.pm.PackageManager;
+import android.nfc.NfcAdapter;
+import android.nfc.NfcAdapter.ControllerAlwaysOnListener;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.concurrent.Executor;
+
+@RunWith(JUnit4.class)
+public final class NfcPermissionTest {
+
+ private NfcAdapter mNfcAdapter;
+ private static final String PKG_NAME = "com.android.packagename";
+
+ private boolean supportsHardware() {
+ final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_NFC);
+ }
+
+ @Before
+ public void setUp() {
+ assumeTrue(supportsHardware());
+ mNfcAdapter = NfcAdapter.getDefaultAdapter(InstrumentationRegistry.getTargetContext());
+ }
+
+ /**
+ * Verifies that isControllerAlwaysOnSupported() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testIsControllerAlwaysOnSupported() {
+ try {
+ mNfcAdapter.isControllerAlwaysOnSupported();
+ fail("mNfcAdapter.isControllerAlwaysOnSupported() did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that isControllerAlwaysOn() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testIsControllerAlwaysOn() {
+ try {
+ mNfcAdapter.isControllerAlwaysOn();
+ fail("mNfcAdapter.isControllerAlwaysOn() did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that setControllerAlwaysOn(true) requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testSetControllerAlwaysOnTrue() {
+ try {
+ mNfcAdapter.setControllerAlwaysOn(true);
+ fail("mNfcAdapter.setControllerAlwaysOn(true) did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that setControllerAlwaysOn(false) requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testSetControllerAlwaysOnFalse() {
+ try {
+ mNfcAdapter.setControllerAlwaysOn(false);
+ fail("mNfcAdapter.setControllerAlwaysOn(true) did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that registerControllerAlwaysOnListener() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testRegisterControllerAlwaysOnListener() {
+ try {
+ mNfcAdapter.registerControllerAlwaysOnListener(
+ new SynchronousExecutor(), new AlwaysOnStateListener());
+ fail("mNfcAdapter.registerControllerAlwaysOnListener did not throw"
+ + "SecurityException as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that unregisterControllerAlwaysOnListener() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testUnregisterControllerAlwaysOnListener() {
+ try {
+ mNfcAdapter.unregisterControllerAlwaysOnListener(new AlwaysOnStateListener());
+ fail("mNfcAdapter.unregisterControllerAlwaysOnListener did not throw"
+ + "SecurityException as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that isTagIntentAppPreferenceSupported() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission.WRITE_SECURE_SETTINGS}.
+ */
+ @Test
+ @AppModeFull
+ public void testIsTagIntentAppPreferenceSupported() {
+ try {
+ mNfcAdapter.isTagIntentAppPreferenceSupported();
+ fail("mNfcAdapter.isTagIntentAppPreferenceSupported() did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that getTagIntentAppPreferenceForUser() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission.WRITE_SECURE_SETTINGS}.
+ */
+ @Test
+ @AppModeFull
+ public void testGetTagIntentAppPreferenceForUser() {
+ try {
+ mNfcAdapter.getTagIntentAppPreferenceForUser(ActivityManager.getCurrentUser());
+ fail("mNfcAdapter.getTagIntentAppPreferenceForUser() did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that setTagIntentAppPreferenceForUser() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission.WRITE_SECURE_SETTINGS}.
+ */
+ @Test
+ @AppModeFull
+ public void testSetTagIntentAppPreferenceForUser() {
+ try {
+ mNfcAdapter.setTagIntentAppPreferenceForUser(ActivityManager.getCurrentUser(),
+ PKG_NAME, true);
+ fail("mNfcAdapter.setTagIntentAppPreferenceForUser() did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ private class SynchronousExecutor implements Executor {
+ public void execute(Runnable r) {
+ r.run();
+ }
+ }
+
+ private class AlwaysOnStateListener implements ControllerAlwaysOnListener {
+ @Override
+ public void onControllerAlwaysOnChanged(boolean isEnabled) {
+ // Do nothing
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
new file mode 100644
index 000000000..3d9ba8214
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase2;
+
+import androidx.test.filters.MediumTest;
+
+import java.util.List;
+
+/**
+ * Verify the Activity related operations require specific permissions.
+ */
+public class NoActivityRelatedPermissionTest
+ extends ActivityInstrumentationTestCase2<PermissionStubActivity> {
+
+ private PermissionStubActivity mActivity;
+
+ public NoActivityRelatedPermissionTest() {
+ super("android.permission.cts", PermissionStubActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ }
+
+ /**
+ * Verify that get task requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#GET_TASKS}
+ */
+ @MediumTest
+ public void testGetTask() {
+ ActivityManager manager = (ActivityManager) getActivity()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ List<ActivityManager.RunningTaskInfo> runningTasks = manager.getRunningTasks(10);
+ // Current implementation should only return tasks for home and the caller. Since there can
+ // be multiple home tasks, we remove them from the list and then check that there is one or
+ // less task left in the list.
+ removeHomeRunningTasks(runningTasks);
+ assertTrue("Found tasks: " + runningTasks,
+ runningTasks == null || runningTasks.size() <= 1);
+
+ List<ActivityManager.RecentTaskInfo> recentTasks = manager.getRecentTasks(10,
+ ActivityManager.RECENT_WITH_EXCLUDED);
+ // Current implementation should only return tasks for home and the caller. Since there can
+ // be multiple home tasks, we remove them from the list and then check that there is one or
+ // less task left in the list.
+ removeHomeRecentsTasks(recentTasks);
+ assertTrue("Found tasks: " + recentTasks, recentTasks == null || recentTasks.size() <= 1);
+ }
+
+ private void removeHomeRecentsTasks(List<ActivityManager.RecentTaskInfo> tasks) {
+ for (int i = tasks.size() -1; i >= 0; i--) {
+ ActivityManager.RecentTaskInfo task = tasks.get(i);
+ if (task.baseIntent != null && isHomeIntent(task.baseIntent)) {
+ tasks.remove(i);
+ }
+ }
+ }
+
+ private void removeHomeRunningTasks(List<ActivityManager.RunningTaskInfo> tasks) {
+ for (int i = tasks.size() -1; i >= 0; i--) {
+ ActivityManager.RunningTaskInfo task = tasks.get(i);
+ if (task.baseIntent != null && isHomeIntent(task.baseIntent)) {
+ tasks.remove(i);
+ }
+ }
+ }
+
+ private boolean isHomeIntent(Intent intent) {
+ return Intent.ACTION_MAIN.equals(intent.getAction())
+ && (intent.hasCategory(Intent.CATEGORY_HOME)
+ || intent.hasCategory(Intent.CATEGORY_SECONDARY_HOME))
+ && intent.getCategories().size() == 1
+ && intent.getData() == null
+ && intent.getType() == null;
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoAudioPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoAudioPermissionTest.java
new file mode 100644
index 000000000..50498b1d5
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoAudioPermissionTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify the audio related operations require specific permissions.
+ */
+public class NoAudioPermissionTest extends AndroidTestCase {
+ private static final String TAG = NoAudioPermissionTest.class.getSimpleName();
+ private AudioManager mAudioManager;
+ private static final int MODE_COUNT = 3;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ assertNotNull(mAudioManager);
+ }
+
+ private boolean hasMicrophone() {
+ return getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_MICROPHONE);
+ }
+
+ /**
+ * Verify that AudioManager.setMicrophoneMute, AudioManager.setMode requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+ */
+ @SmallTest
+ public void testSetMicrophoneMute() {
+ boolean muteState = mAudioManager.isMicrophoneMute();
+ int originalMode = mAudioManager.getMode();
+ // If there is no permission of MODIFY_AUDIO_SETTINGS, setMicrophoneMute does nothing.
+ if (muteState) {
+ Log.w(TAG, "Mic seems muted by hardware! Please unmute and rerrun the test.");
+ } else {
+ mAudioManager.setMicrophoneMute(!muteState);
+ assertEquals(muteState, mAudioManager.isMicrophoneMute());
+ }
+
+ // If there is no permission of MODIFY_AUDIO_SETTINGS, setMode does nothing.
+ assertTrue(AudioManager.MODE_NORMAL != AudioManager.MODE_RINGTONE);
+
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ assertEquals(originalMode, mAudioManager.getMode());
+
+ mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+ assertEquals(originalMode, mAudioManager.getMode());
+ }
+
+ /**
+ * Verify that AudioManager routing methods require permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+ */
+ @SuppressWarnings("deprecation")
+ @SmallTest
+ public void testRouting() {
+
+ // If there is no permission of MODIFY_AUDIO_SETTINGS, setSpeakerphoneOn does nothing.
+ boolean prevState = mAudioManager.isSpeakerphoneOn();
+ mAudioManager.setSpeakerphoneOn(!prevState);
+ assertEquals(prevState, mAudioManager.isSpeakerphoneOn());
+
+ // If there is no permission of MODIFY_AUDIO_SETTINGS, setBluetoothScoOn does nothing.
+ prevState = mAudioManager.isBluetoothScoOn();
+ mAudioManager.setBluetoothScoOn(!prevState);
+ assertEquals(prevState, mAudioManager.isBluetoothScoOn());
+ }
+
+ /**
+ * Verify that {@link android.media.AudioRecord.Builder#build} and
+ * {@link android.media.AudioRecord#AudioRecord} require permission
+ * {@link android.Manifest.permission#RECORD_AUDIO}.
+ */
+ @SmallTest
+ public void testRecordPermission() {
+ if (!hasMicrophone()) return;
+
+ // test builder
+ assertThrows(java.lang.UnsupportedOperationException.class, () -> {
+ final AudioRecord record = new AudioRecord.Builder().build();
+ record.release();
+ });
+
+ // test constructor
+ final int sampleRate = 8000;
+ final int halfSecondInBytes = sampleRate;
+ AudioRecord record = new AudioRecord(
+ MediaRecorder.AudioSource.DEFAULT, sampleRate, AudioFormat.CHANNEL_IN_MONO,
+ AudioFormat.ENCODING_PCM_16BIT, halfSecondInBytes);
+ final int state = record.getState();
+ record.release();
+ assertEquals(AudioRecord.STATE_UNINITIALIZED, state);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoBroadcastPackageRemovedPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoBroadcastPackageRemovedPermissionTest.java
new file mode 100644
index 000000000..1a46842b2
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoBroadcastPackageRemovedPermissionTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify Context related methods without specific BROADCAST series permissions.
+ */
+public class NoBroadcastPackageRemovedPermissionTest extends AndroidTestCase {
+ private static final String TEST_RECEIVER_PERMISSION = "receiverPermission";
+
+ /**
+ * Verify that Context#sendStickyBroadcast(Intent),
+ * Context#removeStickyBroadcast(Intent)
+ * requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#BROADCAST_STICKY }.
+ */
+ @SmallTest
+ public void testSendOrRemoveStickyBroadcast() {
+ try {
+ mContext.sendStickyBroadcast(createIntent(Intent.ACTION_WALLPAPER_CHANGED));
+ fail("Context.sendStickyBroadcast did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ mContext.removeStickyBroadcast(createIntent(Intent.ACTION_WALLPAPER_CHANGED));
+ fail("Context.removeStickyBroadcast did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that Context#sendBroadcast(Intent),
+ * Context#sendBroadcast(Intent, String)
+ * Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver,
+ * Handler, int, String, Bundle)
+ * Context#sendOrderedBroadcast(Intent, String) with ACTION_UID_REMOVED
+ * with ACTION_PACKAGE_REMOVED requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#BROADCAST_PACKAGE_REMOVED}.
+ */
+ @SmallTest
+ public void testSendBroadcast() {
+ try {
+ mContext.sendBroadcast(createIntent(Intent.ACTION_PACKAGE_REMOVED));
+ fail("Context.sendBroadcast did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ mContext.sendBroadcast(createIntent(Intent.ACTION_PACKAGE_REMOVED),
+ TEST_RECEIVER_PERMISSION);
+ fail("Context.sendBroadcast did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ mContext.sendOrderedBroadcast(createIntent(Intent.ACTION_PACKAGE_REMOVED),
+ TEST_RECEIVER_PERMISSION, null, null, 0, "initialData", Bundle.EMPTY);
+ fail("Context.sendOrderedBroadcast did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ mContext.sendOrderedBroadcast(createIntent(Intent.ACTION_PACKAGE_REMOVED),
+ TEST_RECEIVER_PERMISSION);
+ fail("Context.sendOrderedBroadcast did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ private Intent createIntent(String action) {
+ Intent intent = new Intent();
+ intent.setAction(action);
+ return intent;
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoCaptureVideoPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoCaptureVideoPermissionTest.java
new file mode 100644
index 000000000..e0573044c
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoCaptureVideoPermissionTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.ImageReader;
+import android.test.AndroidTestCase;
+import android.util.DisplayMetrics;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify the capture system video output permission requirements.
+ */
+public class NoCaptureVideoPermissionTest extends AndroidTestCase {
+ private static final String NAME = "VirtualDisplayTest";
+ private static final int WIDTH = 720;
+ private static final int HEIGHT = 480;
+ private static final int DENSITY = DisplayMetrics.DENSITY_MEDIUM;
+
+ /**
+ * Verify that DisplayManager.createVirtualDisplay() requires permissions to
+ * create public displays.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT} or
+ * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT}.
+ */
+ @SmallTest
+ public void testCreatePublicVirtualDisplay() {
+ DisplayManager displayManager =
+ (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
+ ImageReader reader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBX_8888, 1);
+ try {
+ displayManager.createVirtualDisplay(NAME, WIDTH, HEIGHT, DENSITY,
+ reader.getSurface(), DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC);
+ fail("DisplayManager.createVirtualDisplay() didn't throw SecurityException "
+ + "as expected when creating public virtual display.");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ reader.close();
+ }
+ }
+
+ /**
+ * Verify that DisplayManager.createVirtualDisplay() requires permissions to
+ * create secure displays.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT}.
+ */
+ @SmallTest
+ public void testCreateSecureVirtualDisplay() {
+ DisplayManager displayManager =
+ (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
+ ImageReader reader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBX_8888, 1);
+ try {
+ displayManager.createVirtualDisplay(NAME, WIDTH, HEIGHT, DENSITY,
+ reader.getSurface(), DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE);
+ fail("DisplayManager.createVirtualDisplay() didn't throw SecurityException "
+ + "as expected when creating secure virtual display.");
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ reader.close();
+ }
+ }
+
+ /**
+ * Verify that DisplayManager.createVirtualDisplay() does not requires permissions to
+ * create private displays.
+ */
+ @SmallTest
+ public void testCreatePrivateVirtualDisplay() {
+ DisplayManager displayManager =
+ (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
+ ImageReader reader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBX_8888, 1);
+ try {
+ VirtualDisplay display = displayManager.createVirtualDisplay(
+ NAME, WIDTH, HEIGHT, DENSITY,
+ reader.getSurface(), 0);
+ display.release();
+ } catch (SecurityException e) {
+ fail("DisplayManager.createVirtualDisplay() should not throw SecurityException "
+ + "when creating private virtual display.");
+ } finally {
+ reader.close();
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoKeyPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoKeyPermissionTest.java
new file mode 100644
index 000000000..ac77947d9
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoKeyPermissionTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify the key input related operations require specific permissions.
+ */
+public class NoKeyPermissionTest extends AndroidTestCase {
+ KeyguardManager mKeyManager;
+ KeyguardManager.KeyguardLock mKeyLock;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKeyManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ if (mKeyManager != null) {
+ mKeyLock = mKeyManager.newKeyguardLock("testTag");
+ }
+ }
+
+ /**
+ * Verify that KeyguardManager.KeyguardLock.disableKeyguard requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#DISABLE_KEYGUARD}.
+ */
+ @SmallTest
+ public void testDisableKeyguard() {
+ // KeyguardManager was not accessible, pass.
+ if (mKeyManager == null) {
+ return;
+ }
+ try {
+ mKeyLock.disableKeyguard();
+ fail("KeyguardManager.KeyguardLock.disableKeyguard did not throw SecurityException as"
+ + " expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that KeyguardManager.KeyguardLock.reenableKeyguard requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#DISABLE_KEYGUARD}.
+ */
+ @SmallTest
+ public void testReenableKeyguard() {
+ // KeyguardManager was not accessible, pass.
+ if (mKeyManager == null) {
+ return;
+ }
+ try {
+ mKeyLock.reenableKeyguard();
+ fail("KeyguardManager.KeyguardLock.reenableKeyguard did not throw SecurityException as"
+ + " expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that KeyguardManager.exitKeyguardSecurely requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#DISABLE_KEYGUARD}.
+ */
+ @SmallTest
+ public void testExitKeyguardSecurely() {
+ // KeyguardManager was not accessible, pass.
+ if (mKeyManager == null) {
+ return;
+ }
+ try {
+ mKeyManager.exitKeyguardSecurely(null);
+ fail("KeyguardManager.exitKeyguardSecurely did not throw SecurityException as"
+ + " expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoNetworkStatePermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoNetworkStatePermissionTest.java
new file mode 100644
index 000000000..5dc73d520
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoNetworkStatePermissionTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+import java.net.InetAddress;
+
+/**
+ * Verify ConnectivityManager related methods without specific network state permissions.
+ */
+public class NoNetworkStatePermissionTest extends AndroidTestCase {
+ private ConnectivityManager mConnectivityManager;
+ private static final int TEST_NETWORK_TYPE = ConnectivityManager.TYPE_MOBILE;
+ private static final String TEST_FEATURE = "enableHIPRI";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ assertNotNull(mConnectivityManager);
+ }
+
+ /**
+ * Verify that ConnectivityManager#getActiveNetworkInfo() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ */
+ @SmallTest
+ public void testGetActiveNetworkInfo() {
+ try {
+ mConnectivityManager.getActiveNetworkInfo();
+ fail("ConnectivityManager.getActiveNetworkInfo didn't throw SecurityException as"
+ + " expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that ConnectivityManager#getNetworkInfo() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ */
+ @SmallTest
+ public void testGetNetworkInfo() {
+ try {
+ mConnectivityManager.getNetworkInfo(TEST_NETWORK_TYPE);
+ fail("ConnectivityManager.getNetworkInfo didn't throw SecurityException as"
+ + " expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that ConnectivityManager#getAllNetworkInfo() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ */
+ @SmallTest
+ public void testGetAllNetworkInfo() {
+ try {
+ mConnectivityManager.getAllNetworkInfo();
+ fail("ConnectivityManager.getAllNetworkInfo didn't throw SecurityException as"
+ + " expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @SmallTest
+ public void testSecurityExceptionFromDns() throws Exception {
+ try {
+ InetAddress.getByName("www.google.com");
+ fail();
+ } catch (SecurityException expected) {
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoReadLogsPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoReadLogsPermissionTest.java
new file mode 100644
index 000000000..f0d70b2ce
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoReadLogsPermissionTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStat;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.MediumTest;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * Verify the read system log require specific permissions.
+ */
+public class NoReadLogsPermissionTest extends AndroidTestCase {
+ /**
+ * Verify that we'll only get our logs without the READ_LOGS permission.
+ *
+ * We test this by examining the logs looking for ActivityManager lines.
+ * Since ActivityManager runs as a different UID, we shouldn't see
+ * any of those log entries.
+ *
+ * @throws IOException
+ */
+ @MediumTest
+ public void testLogcat() throws IOException {
+ Process logcatProc = null;
+ BufferedReader reader = null;
+ try {
+ logcatProc = Runtime.getRuntime().exec(new String[]
+ {"logcat", "-v", "brief", "-d", "ActivityManager:* *:S" });
+
+ reader = new BufferedReader(new InputStreamReader(logcatProc.getInputStream()));
+
+ int lineCt = 0;
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (!line.startsWith("--------- beginning of ")) {
+ lineCt++;
+ }
+ }
+
+ // no permission get an empty log buffer.
+ // Logcat returns only one line:
+ // "--------- beginning of <log device>"
+
+ assertEquals("Unexpected logcat entries. Are you running the "
+ + "the latest logger.c from the Android kernel?",
+ 0, lineCt);
+
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ }
+
+ public void testEventsLogSane() throws ErrnoException {
+ testLogIsSane("/dev/log/events");
+ }
+
+ public void testMainLogSane() throws ErrnoException {
+ testLogIsSane("/dev/log/main");
+ }
+
+ public void testRadioLogSane() throws ErrnoException {
+ testLogIsSane("/dev/log/radio");
+ }
+
+ public void testSystemLogSane() throws ErrnoException {
+ testLogIsSane("/dev/log/system");
+ }
+
+ private static void testLogIsSane(String log) throws ErrnoException {
+ try {
+ StructStat stat = Os.stat(log);
+ assertEquals("not owned by uid=0", 0, stat.st_uid);
+ assertEquals("not owned by gid=logs", "log", FileUtils.getGroupName(stat.st_gid));
+ } catch (ErrnoException e) {
+ if (e.errno != OsConstants.ENOENT && e.errno != OsConstants.EACCES) {
+ throw e;
+ }
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoRollbackPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoRollbackPermissionTest.java
new file mode 100644
index 000000000..50b84fa70
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoRollbackPermissionTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.pm.PackageInstaller;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+
+@AppModeFull(reason = "PackageInstaller cannot be accessed by instant apps")
+public class NoRollbackPermissionTest {
+ @Test
+ public void testCreateInstallSessionWithReasonRollbackFails() throws Exception {
+ // The INSTALL_REASON_ROLLBACK allows an APK to be rolled back to a previous signing key
+ // without setting the ROLLBACK capability in the lineage. Since only signature|privileged
+ // apps can hold the necessary permission to initiate a rollback ensure apps without this
+ // permission cannot set rollback as the install reason.
+ PackageInstaller packageInstaller =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager()
+ .getPackageInstaller();
+ PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ parentParams.setRequestDowngrade(true);
+ parentParams.setMultiPackage();
+ // The constant PackageManager.INSTALL_REASON_ROLLBACK is hidden from apps, but an app can
+ // still use its constant value.
+ parentParams.setInstallReason(5);
+ assertThrows(SecurityException.class, () -> packageInstaller.createSession(parentParams));
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java
new file mode 100644
index 000000000..437aa19c4
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.permission.cts;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.os.Vibrator;
+import android.os.VibratorManager;
+import android.platform.test.annotations.AppModeFull;
+import android.telephony.gsm.SmsManager;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.TimeZone;
+
+/**
+ * Verify the system function require specific permissions.
+ */
+@SuppressWarnings("deprecation")
+public class NoSystemFunctionPermissionTest extends AndroidTestCase {
+
+ /**
+ * Verify that ActivityManager.restartPackage() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#RESTART_PACKAGES}.
+ */
+ @SmallTest
+ public void testRestartPackage() {
+ ActivityManager activityManager = (ActivityManager) mContext.getSystemService(
+ Context.ACTIVITY_SERVICE);
+
+ try {
+ activityManager.restartPackage("packageName");
+ fail("ActivityManager.restartPackage() didn't throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that AlarmManager.setTimeZone() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SET_TIME_ZONE}.
+ */
+ @SmallTest
+ public void testSetTimeZone() {
+ AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
+ Context.ALARM_SERVICE);
+ String[] timeZones = TimeZone.getAvailableIDs();
+ String timeZone = timeZones[0];
+
+ try {
+ alarmManager.setTimeZone(timeZone);
+ fail("AlarmManager.setTimeZone() did not throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that setting wallpaper relate methods require permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SET_WALLPAPER}.
+ * @throws IOException
+ */
+ @AppModeFull(reason = "Instant apps cannot access the WallpaperManager")
+ @SmallTest
+ public void testSetWallpaper() throws IOException {
+ if (!WallpaperManager.getInstance(mContext).isWallpaperSupported()) {
+ return;
+ }
+
+ Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
+
+ try {
+ mContext.setWallpaper(bitmap);
+ fail("Context.setWallpaper(BitMap) did not throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ mContext.setWallpaper((InputStream) null);
+ fail("Context.setWallpaper(InputStream) did not throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ mContext.clearWallpaper();
+ fail("Context.clearWallpaper() did not throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that Vibrator's vibrating related methods requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#VIBRATE}.
+ */
+ @SmallTest
+ public void testVibrator() {
+ Vibrator vibrator = mContext.getSystemService(VibratorManager.class).getDefaultVibrator();
+
+ if (!vibrator.hasVibrator()) {
+ // Run the test only if a vibrator is present.
+ return;
+ }
+
+ if (!vibrator.hasVibrator()) {
+ // If the test device does not have a vibrator, then abort test.
+ return;
+ }
+
+ try {
+ vibrator.cancel();
+ fail("Vibrator.cancel() did not throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ vibrator.vibrate(1);
+ fail("Vibrator.vibrate(long) did not throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ long[] testPattern = {1, 1, 1, 1, 1};
+
+ try {
+ vibrator.vibrate(testPattern, 1);
+ fail("Vibrator.vibrate(long[], int) not throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that sending sms requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SMS}.
+ */
+ @SmallTest
+ public void testSendSms() {
+ if (!getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+
+ SmsManager smsManager = SmsManager.getDefault();
+ byte[] testData = new byte[10];
+ try {
+ smsManager.sendDataMessage("1233", "1233", (short) 0, testData, null, null);
+ fail("SmsManager.sendDataMessage() did not throw SecurityException as expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoWakeLockPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoWakeLockPermissionTest.java
new file mode 100644
index 000000000..95c4da727
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoWakeLockPermissionTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.permission.cts;
+
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.WifiLock;
+import android.os.PowerManager;
+import android.platform.test.annotations.AppModeFull;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify the Wake Lock related operations require specific permissions.
+ */
+public class NoWakeLockPermissionTest extends AndroidTestCase {
+ private PowerManager mPowerManager;
+
+ private PowerManager.WakeLock mWakeLock;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "tag");
+ }
+
+ /**
+ * Verify that WifiManager.WifiLock.acquire() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#WAKE_LOCK}.
+ */
+ @AppModeFull(reason = "Instant apps cannot access the WifiManager")
+ @SmallTest
+ public void testWifiLockAcquire() {
+ if (!mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI)) {
+ return;
+ }
+
+ final WifiManager wifiManager = (WifiManager) mContext.getSystemService(
+ Context.WIFI_SERVICE);
+ final WifiLock wifiLock = wifiManager.createWifiLock("WakeLockPermissionTest");
+ try {
+ wifiLock.acquire();
+ fail("WifiManager.WifiLock.acquire() didn't throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that MediaPlayer.start() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#WAKE_LOCK}.
+ */
+ @SmallTest
+ public void testMediaPlayerWakeLock() {
+ final MediaPlayer mediaPlayer = new MediaPlayer();
+ mediaPlayer.setWakeMode(mContext, PowerManager.FULL_WAKE_LOCK);
+ try {
+ mediaPlayer.start();
+ fail("MediaPlayer.setWakeMode() did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ mediaPlayer.stop();
+ }
+
+ /**
+ * Verify that PowerManager.WakeLock.acquire() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#WAKE_LOCK}.
+ */
+ @SmallTest
+ public void testPowerManagerWakeLockAcquire() {
+ try {
+ mWakeLock.acquire();
+ fail("WakeLock.acquire() did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that PowerManager.WakeLock.acquire(long) requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#WAKE_LOCK}.
+ */
+ @SmallTest
+ public void testPowerManagerWakeLockAcquire2() {
+ // Tset acquire(long)
+ try {
+ mWakeLock.acquire(1);
+ fail("WakeLock.acquire(long) did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java b/tests/cts/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java
new file mode 100644
index 000000000..fc1d6b59f
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.permission.cts;
+
+import static android.app.WallpaperManager.FLAG_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
+import static org.junit.Assert.assertThrows;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.platform.test.annotations.AppModeFull;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.function.ThrowingRunnable;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+/**
+ * Verify that Wallpaper-related operations enforce the correct permissions.
+ */
+@AppModeFull(reason = "instant apps cannot access the WallpaperManager")
+public class NoWallpaperPermissionsTest extends AndroidTestCase {
+ private WallpaperManager mWM;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mWM = (WallpaperManager) mContext.getSystemService(Context.WALLPAPER_SERVICE);
+ }
+
+ /**
+ * Verify that the setResource(...) methods enforce the SET_WALLPAPER permission
+ */
+ @SmallTest
+ public void testSetResource() throws IOException {
+ if (wallpaperNotSupported()) {
+ return;
+ }
+
+ try {
+ mWM.setResource(R.drawable.robot);
+ fail("WallpaperManager.setResource(id) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+
+ try {
+ mWM.setResource(R.drawable.robot, FLAG_LOCK);
+ fail("WallpaperManager.setResource(id, which) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+ }
+
+ /**
+ * Verify that the setBitmap(...) methods enforce the SET_WALLPAPER permission
+ */
+ @SmallTest
+ public void testSetBitmap() throws IOException {
+ if (wallpaperNotSupported()) {
+ return;
+ }
+
+ Bitmap b = Bitmap.createBitmap(160, 120, Bitmap.Config.RGB_565);
+
+ try {
+ mWM.setBitmap(b);
+ fail("setBitmap(b) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+
+ try {
+ mWM.setBitmap(b, null, false);
+ fail("setBitmap(b, crop, allowBackup) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+
+ try {
+ mWM.setBitmap(b, null, false, FLAG_SYSTEM);
+ fail("setBitmap(b, crop, allowBackup, which) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+ }
+
+ /**
+ * Verify that the setStream(...) methods enforce the SET_WALLPAPER permission
+ */
+ @SmallTest
+ public void testSetStream() throws IOException {
+ if (wallpaperNotSupported()) {
+ return;
+ }
+
+ ByteArrayInputStream stream = new ByteArrayInputStream(new byte[32]);
+
+ try {
+ mWM.setStream(stream);
+ fail("setStream(stream) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+
+ try {
+ mWM.setStream(stream, null, false);
+ fail("setStream(stream, crop, allowBackup) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+
+ try {
+ mWM.setStream(stream, null, false, FLAG_LOCK);
+ fail("setStream(stream, crop, allowBackup, which) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+ }
+
+ /**
+ * Verify that the clearWallpaper(...) methods enforce the SET_WALLPAPER permission
+ */
+ @SmallTest
+ public void testClearWallpaper() throws IOException {
+ if (wallpaperNotSupported()) {
+ return;
+ }
+
+ try {
+ mWM.clear();
+ fail("clear() did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+
+ try {
+ mWM.clear(FLAG_SYSTEM);
+ fail("clear(which) did not enforce SET_WALLPAPER");
+ } catch (SecurityException expected) { /* expected */ }
+ }
+
+ /**
+ * Verify that reading the current wallpaper enforce the READ_WALLPAPER_INTERNAL permission.
+ * The methods concerned are:
+ * getDrawable, peekDrawable, getFastDrawable, peekFastDrawable, getWallpaperFile.
+ *
+ * These methods should throw a SecurityException, even if MANAGE_EXTERNAL_STORAGE is granted.
+ */
+ public void testReadWallpaper() {
+ if (wallpaperNotSupported()) {
+ return;
+ }
+ String message = "with no permissions, getDrawable should throw a SecurityException";
+ assertSecurityException(mWM::getDrawable, message);
+ assertSecurityException(() -> mWM.getDrawable(FLAG_SYSTEM), message);
+ assertSecurityException(() -> mWM.getDrawable(FLAG_LOCK), message);
+
+ message = "with no permissions, peekDrawable should throw a SecurityException";
+ assertSecurityException(mWM::peekDrawable, message);
+ assertSecurityException(() -> mWM.peekDrawable(FLAG_SYSTEM), message);
+ assertSecurityException(() -> mWM.peekDrawable(FLAG_LOCK), message);
+
+ message = "with no permissions, getFastDrawable should throw a SecurityException";
+ assertSecurityException(mWM::getFastDrawable, message);
+ assertSecurityException(() -> mWM.getFastDrawable(FLAG_SYSTEM), message);
+ assertSecurityException(() -> mWM.getFastDrawable(FLAG_LOCK), message);
+
+ message = "with no permissions, peekFastDrawable should throw a SecurityException";
+ assertSecurityException(mWM::peekFastDrawable, message);
+ assertSecurityException(() -> mWM.peekFastDrawable(FLAG_SYSTEM), message);
+ assertSecurityException(() -> mWM.peekFastDrawable(FLAG_LOCK), message);
+
+ message = "with no permissions, getWallpaperFile should throw a SecurityException";
+ assertSecurityException(() -> mWM.getWallpaperFile(FLAG_SYSTEM), message);
+ assertSecurityException(() -> mWM.getWallpaperFile(FLAG_LOCK), message);
+ }
+
+ // ---------- Utility methods ----------
+
+ private boolean wallpaperNotSupported() {
+ return !(mWM.isWallpaperSupported() && mWM.isSetWallpaperAllowed());
+ }
+
+ private void assertSecurityException(ThrowingRunnable runnable, String errorMessage) {
+ assertThrows(errorMessage, SecurityException.class, runnable);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java
new file mode 100644
index 000000000..9fff22747
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Verify WifiManager related methods without specific Wifi state permissions.
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Instant apps cannot access the WifiManager")
+@SmallTest
+public class NoWifiStatePermissionTest {
+ private static final Context sContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ private static final int TEST_NET_ID = 1;
+ private static final WifiConfiguration TEST_WIFI_CONFIGURATION = new WifiConfiguration();
+ private WifiManager mWifiManager;
+
+ @Before
+ public void setUp() {
+ boolean hasWifi = sContext.getPackageManager().hasSystemFeature(FEATURE_WIFI);
+ assumeTrue(hasWifi);
+
+ mWifiManager = (WifiManager) sContext.getSystemService(Context.WIFI_SERVICE);
+ assertNotNull(mWifiManager);
+ }
+
+ /**
+ * Verify that WifiManager#getWifiState() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testGetWifiState() {
+ mWifiManager.getWifiState();
+ }
+
+ /**
+ * Verify that WifiManager#getConfiguredNetworks() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testGetConfiguredNetworks() {
+ mWifiManager.getConfiguredNetworks();
+ }
+
+ /**
+ * Verify that WifiManager#getConnectionInfo() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testGetConnectionInfo() {
+ mWifiManager.getConnectionInfo();
+ }
+
+ /**
+ * Verify that WifiManager#getScanResults() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testGetScanResults() {
+ mWifiManager.getScanResults();
+ }
+
+ /**
+ * Verify that WifiManager#getDhcpInfo() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testGetDhcpInfo() {
+ mWifiManager.getDhcpInfo();
+ }
+
+ /**
+ * Verify that WifiManager#disconnect() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testDisconnect() {
+ mWifiManager.disconnect();
+ }
+
+ /**
+ * Verify that WifiManager#reconnect() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testReconnect() {
+ mWifiManager.reconnect();
+ }
+
+ /**
+ * Verify that WifiManager#reassociate() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testReassociate() {
+ mWifiManager.reassociate();
+ }
+
+ /**
+ * Verify that WifiManager#addNetwork() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testAddNetwork() {
+ mWifiManager.addNetwork(TEST_WIFI_CONFIGURATION);
+ }
+
+ /**
+ * Verify that WifiManager#updateNetwork() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testUpdateNetwork() {
+ TEST_WIFI_CONFIGURATION.networkId = 2;
+ mWifiManager.updateNetwork(TEST_WIFI_CONFIGURATION);
+ }
+ /**
+ * Verify that WifiManager#removeNetwork() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testRemoveNetwork() {
+ mWifiManager.removeNetwork(TEST_NET_ID);
+ }
+
+ /**
+ * Verify that WifiManager#enableNetwork() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testEnableNetwork() {
+ mWifiManager.enableNetwork(TEST_NET_ID, false);
+ }
+
+ /**
+ * Verify that WifiManager#disableNetwork() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testDisableNetwork() {
+ mWifiManager.disableNetwork(TEST_NET_ID);
+ }
+
+ /**
+ * Verify that WifiManager#pingSupplicant() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testPingSupplicant() {
+ mWifiManager.pingSupplicant();
+ }
+
+ /**
+ * Verify that WifiManager#startScan() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testStartScan() {
+ mWifiManager.startScan();
+ }
+
+ /**
+ * Verify that WifiManager#setWifiEnabled() requires permissions.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
+ */
+ @Test(expected = SecurityException.class)
+ public void testSetWifiEnabled() {
+ mWifiManager.setWifiEnabled(true);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NotificationListenerCheckTest.java b/tests/cts/permission/src/android/permission/cts/NotificationListenerCheckTest.java
new file mode 100644
index 000000000..19fc20de6
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NotificationListenerCheckTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.permission.cts.PermissionUtils.clearAppState;
+import static android.permission.cts.PermissionUtils.install;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+import static android.permission.cts.TestUtils.ensure;
+import static android.permission.cts.TestUtils.eventually;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.rule.ScreenRecordRule;
+import android.service.notification.StatusBarNotification;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.modules.utils.build.SdkLevel;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests the {@code NotificationListenerCheck} in permission controller.
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Cannot set system settings as instant app. Also we never show a notification"
+ + " listener check notification for instant apps.")
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+@ScreenRecordRule.ScreenRecord
+@FlakyTest
+public class NotificationListenerCheckTest extends BaseNotificationListenerCheckTest {
+
+ public final ScreenRecordRule mScreenRecordRule = new ScreenRecordRule(false, false);
+
+ @Before
+ public void setup() throws Throwable {
+ // Skip tests if safety center not allowed
+ assumeDeviceSupportsSafetyCenter();
+
+ wakeUpAndDismissKeyguard();
+ resetPermissionControllerBeforeEachTest();
+
+ // Cts NLS is required to verify sent Notifications, however, we don't want it to show up in
+ // testing
+ triggerAndDismissCtsNotificationListenerNotification();
+
+ clearNotifications();
+
+ // Install and allow the app with NLS for testing
+ install(TEST_APP_NOTIFICATION_LISTENER_APK);
+ allowTestAppNotificationListenerService();
+ }
+
+ @After
+ public void tearDown() throws Throwable {
+ // Disallow and uninstall the app with NLS for testing
+ disallowTestAppNotificationListenerService();
+ uninstallApp(TEST_APP_PKG);
+
+ clearNotifications();
+ }
+
+ @Test
+ public void noNotificationIfFeatureDisabled() throws Throwable {
+ setNotificationListenerCheckEnabled(false);
+
+ runNotificationListenerCheck();
+
+ ensure(() -> assertNull("Expected no notifications", getNotification(false)),
+ ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void noNotificationIfSafetyCenterDisabled() throws Throwable {
+ SafetyCenterUtils.setSafetyCenterEnabled(false);
+
+ runNotificationListenerCheck();
+
+ ensure(() -> assertNull("Expected no notifications", getNotification(false)),
+ ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsShown() throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull("Expected notification, none found", getNotification(false)),
+ UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsShownOnlyOnce() throws Throwable {
+ runNotificationListenerCheck();
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ runNotificationListenerCheck();
+ ensure(() -> assertNull("Expected no notifications", getNotification(false)),
+ ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsShownAgainAfterClear() throws Throwable {
+ runNotificationListenerCheck();
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ clearAppState(TEST_APP_PKG);
+ // Wait until package is cleared and permission controller has cleared the state
+ Thread.sleep(2000);
+
+ allowTestAppNotificationListenerService();
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsShownAgainAfterUninstallAndReinstall() throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ uninstallApp(TEST_APP_PKG);
+
+ // Wait until package permission controller has cleared the state
+ Thread.sleep(2000);
+
+ install(TEST_APP_NOTIFICATION_LISTENER_APK);
+
+ allowTestAppNotificationListenerService();
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsShownAgainAfterDisableAndReenableAppNotificationListener()
+ throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ // Disallow NLS, and run NLS check job. This should clear NLS off notified list
+ disallowTestAppNotificationListenerService();
+ runNotificationListenerCheck();
+
+ // Re-allow NLS, and run NLS check job. This work now that it's cleared NLS off notified
+ // list
+ allowTestAppNotificationListenerService();
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void removeNotificationOnUninstall() throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ uninstallApp(TEST_APP_PKG);
+
+ // Wait until package permission controller has cleared the state
+ Thread.sleep(2000);
+
+ eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsNotShownAfterDisableAppNotificationListener() throws Throwable {
+ disallowTestAppNotificationListenerService();
+
+ runNotificationListenerCheck();
+
+ // We don't expect a notification, but try to trigger one anyway
+ ensure(() -> assertNull("Expected no notifications", getNotification(false)),
+ ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationOnClick_opensSafetyCenter() throws Throwable {
+ runNotificationListenerCheck();
+
+ StatusBarNotification currentNotification = eventually(
+ () -> {
+ StatusBarNotification notification = getNotification(false);
+ assertNotNull(notification);
+ return notification;
+ }, UNEXPECTED_TIMEOUT_MILLIS);
+
+ // Verify content intent
+ PendingIntent contentIntent = currentNotification.getNotification().contentIntent;
+ if (SdkLevel.isAtLeastU()) {
+ contentIntent.send(null, 0, null, null, null, null,
+ ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle());
+ } else {
+ contentIntent.send();
+ }
+
+ SafetyCenterUtils.assertSafetyCenterStarted();
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/NotificationListenerCheckWithSafetyCenterUnsupportedTest.java b/tests/cts/permission/src/android/permission/cts/NotificationListenerCheckWithSafetyCenterUnsupportedTest.java
new file mode 100644
index 000000000..a346de6fd
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/NotificationListenerCheckWithSafetyCenterUnsupportedTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.permission.cts.PermissionUtils.install;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+import static android.permission.cts.TestUtils.ensure;
+
+import static org.junit.Assert.assertNull;
+
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests the {@code NotificationListenerCheck} in permission controller.
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Cannot set system settings as instant app. Also we never show a notification"
+ + " listener check notification for instant apps.")
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+public class NotificationListenerCheckWithSafetyCenterUnsupportedTest
+ extends BaseNotificationListenerCheckTest {
+
+ @Before
+ public void setup() throws Throwable {
+ // Skip tests if safety center is supported
+ assumeDeviceDoesNotSupportSafetyCenter();
+
+ wakeUpAndDismissKeyguard();
+ resetPermissionControllerBeforeEachTest();
+
+ clearNotifications();
+
+ // Install and allow the app with NLS for testing
+ install(TEST_APP_NOTIFICATION_LISTENER_APK);
+ allowTestAppNotificationListenerService();
+ }
+
+ @After
+ public void tearDown() throws Throwable {
+ // Disallow and uninstall the app with NLS for testing
+ disallowTestAppNotificationListenerService();
+ uninstallApp(TEST_APP_PKG);
+
+ clearNotifications();
+ }
+
+ @Test
+ public void noNotifications_featureEnabled_safetyCenterEnabled() throws Throwable {
+ runNotificationListenerCheck();
+
+ ensure(() -> assertNull("Expected no notifications", getNotification(false)),
+ ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void noNotifications_featureDisabled_safetyCenterEnabled() throws Throwable {
+ setNotificationListenerCheckEnabled(false);
+
+ runNotificationListenerCheck();
+
+ ensure(() -> assertNull("Expected no notifications", getNotification(false)),
+ ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void noNotifications_featureEnabled_safetyCenterDisabled() throws Throwable {
+ SafetyCenterUtils.setSafetyCenterEnabled(false);
+
+ runNotificationListenerCheck();
+
+ ensure(() -> assertNull("Expected no notifications", getNotification(false)),
+ ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void noNotifications_featureDisabled_safetyCenterDisabled() throws Throwable {
+ setNotificationListenerCheckEnabled(false);
+ SafetyCenterUtils.setSafetyCenterEnabled(false);
+
+ runNotificationListenerCheck();
+
+ ensure(() -> assertNull("Expected no notifications", getNotification(false)),
+ ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/OneTimePermissionTest.java b/tests/cts/permission/src/android/permission/cts/OneTimePermissionTest.java
new file mode 100644
index 000000000..f5f222f80
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/OneTimePermissionTest.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.CAMERA;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static org.junit.Assume.assumeFalse;
+
+import android.app.ActivityManager;
+import android.app.DreamManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.platform.test.rule.ScreenRecordRule;
+import android.provider.DeviceConfig;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+
+import com.android.compatibility.common.util.FeatureUtil;
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.compatibility.common.util.UiAutomatorUtils2;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@ScreenRecordRule.ScreenRecord
+public class OneTimePermissionTest {
+
+ private static final String APP_PKG_NAME = "android.permission.cts.appthatrequestpermission";
+ private static final String CUSTOM_CAMERA_PERM_APP_PKG_NAME =
+ "android.permission.cts.appthatrequestcustomcamerapermission";
+ private static final String APK =
+ "/data/local/tmp/cts-permission/CtsAppThatRequestsOneTimePermission.apk";
+ private static final String CUSTOM_CAMERA_PERM_APK =
+ "/data/local/tmp/cts-permission/CtsAppThatRequestCustomCameraPermission.apk";
+ private static final String EXTRA_FOREGROUND_SERVICE_LIFESPAN =
+ "android.permission.cts.OneTimePermissionTest.EXTRA_FOREGROUND_SERVICE_LIFESPAN";
+ private static final String EXTRA_FOREGROUND_SERVICE_STICKY =
+ "android.permission.cts.OneTimePermissionTest.EXTRA_FOREGROUND_SERVICE_STICKY";
+
+ public static final String CUSTOM_PERMISSION = "appthatrequestcustomcamerapermission.CUSTOM";
+
+ private static final long ONE_TIME_TIMEOUT_MILLIS = 5000;
+ private static final long ONE_TIME_KILLED_DELAY_MILLIS = 5000;
+ private static final long ONE_TIME_TIMER_LOWER_GRACE_PERIOD = 1000;
+ private static final long ONE_TIME_TIMER_UPPER_GRACE_PERIOD = 10000;
+
+ private final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private final PackageManager mPackageManager = mContext.getPackageManager();
+ private final UiDevice mUiDevice =
+ UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ private final ActivityManager mActivityManager =
+ mContext.getSystemService(ActivityManager.class);
+ private String mOldOneTimePermissionTimeoutValue;
+ private String mOldOneTimePermissionKilledDelayValue;
+
+ @Rule
+ public final ScreenRecordRule sScreenRecordRule = new ScreenRecordRule(false, false);
+
+ @Rule
+ public IgnoreAllTestsRule mIgnoreAutomotive = new IgnoreAllTestsRule(
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
+
+ @Before
+ public void wakeUpScreen() {
+ SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP");
+
+ SystemUtil.runShellCommand("input keyevent 82");
+ }
+
+ @Before
+ public void installApp() {
+ runShellCommandOrThrow("pm install -r " + APK);
+ runShellCommandOrThrow("pm install -r " + CUSTOM_CAMERA_PERM_APK);
+ }
+
+ @Before
+ public void prepareDeviceForOneTime() {
+ runWithShellPermissionIdentity(() -> {
+ mOldOneTimePermissionTimeoutValue = DeviceConfig.getProperty("permissions",
+ "one_time_permissions_timeout_millis");
+ mOldOneTimePermissionKilledDelayValue = DeviceConfig.getProperty("permissions",
+ "one_time_permissions_killed_delay_millis");
+ DeviceConfig.setProperty("permissions", "one_time_permissions_timeout_millis",
+ Long.toString(ONE_TIME_TIMEOUT_MILLIS), false);
+ DeviceConfig.setProperty("permissions",
+ "one_time_permissions_killed_delay_millis",
+ Long.toString(ONE_TIME_KILLED_DELAY_MILLIS), false);
+ });
+ }
+
+ @After
+ public void uninstallApp() {
+ runShellCommand("pm uninstall " + APP_PKG_NAME);
+ runShellCommand("pm uninstall " + CUSTOM_CAMERA_PERM_APP_PKG_NAME);
+ }
+
+ @After
+ public void restoreDeviceForOneTime() {
+ runWithShellPermissionIdentity(
+ () -> {
+ DeviceConfig.setProperty("permissions", "one_time_permissions_timeout_millis",
+ mOldOneTimePermissionTimeoutValue, false);
+ DeviceConfig.setProperty("permissions",
+ "one_time_permissions_killed_delay_millis",
+ mOldOneTimePermissionKilledDelayValue, false);
+ });
+ }
+
+ @Test
+ public void testOneTimePermission() throws Throwable {
+ startApp();
+
+ CompletableFuture<Long> exitTime = registerAppExitListener();
+
+ clickOneTimeButton();
+
+ exitApp();
+
+ assertGranted(5000);
+
+ assertDenied(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD);
+
+ assertExpectedLifespan(exitTime, ONE_TIME_TIMEOUT_MILLIS);
+ }
+
+ @Ignore
+ @Test
+ public void testForegroundServiceMaintainsPermission() throws Throwable {
+ startApp();
+
+ CompletableFuture<Long> exitTime = registerAppExitListener();
+
+ clickOneTimeButton();
+
+ long expectedLifespanMillis = 2 * ONE_TIME_TIMEOUT_MILLIS;
+ startAppForegroundService(expectedLifespanMillis, false);
+
+ exitApp();
+
+ assertGranted(5000);
+
+ assertDenied(expectedLifespanMillis + ONE_TIME_TIMER_UPPER_GRACE_PERIOD);
+
+ assertExpectedLifespan(exitTime, expectedLifespanMillis);
+
+ }
+
+ @Test
+ public void testPermissionRevokedOnKill() throws Throwable {
+ startApp();
+
+ clickOneTimeButton();
+
+ exitApp();
+
+ assertGranted(5000);
+
+ mUiDevice.waitForIdle();
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ mActivityManager.killBackgroundProcesses(APP_PKG_NAME));
+
+ runWithShellPermissionIdentity(
+ () -> Thread.sleep(DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
+ "one_time_permissions_killed_delay_millis", 5000L)));
+ assertDenied(500);
+ }
+
+ @Test
+ @FlakyTest
+ public void testStickyServiceMaintainsPermissionOnRestart() throws Throwable {
+ startApp();
+
+ clickOneTimeButton();
+
+ startAppForegroundService(2 * ONE_TIME_TIMEOUT_MILLIS, true);
+
+ exitApp();
+
+ assertGranted(5000);
+ mUiDevice.waitForIdle();
+ Thread.sleep(ONE_TIME_TIMEOUT_MILLIS);
+
+ runShellCommand("am crash " + APP_PKG_NAME);
+
+ eventually(() -> runWithShellPermissionIdentity(() -> {
+ if (mActivityManager.getPackageImportance(APP_PKG_NAME) <= IMPORTANCE_CACHED) {
+ throw new AssertionError("App was never killed");
+ }
+ }));
+
+ eventually(() -> runWithShellPermissionIdentity(() -> {
+ if (mActivityManager.getPackageImportance(APP_PKG_NAME)
+ > IMPORTANCE_FOREGROUND_SERVICE) {
+ throw new AssertionError("Foreground service never resumed");
+ }
+ Assert.assertEquals("Service resumed without permission",
+ PackageManager.PERMISSION_GRANTED, mContext.getPackageManager()
+ .checkPermission(ACCESS_FINE_LOCATION, APP_PKG_NAME));
+ }));
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 237405974L)
+ public void testCustomPermissionIsGrantedOneTime() throws Throwable {
+ startApp(new ComponentName(CUSTOM_CAMERA_PERM_APP_PKG_NAME,
+ CUSTOM_CAMERA_PERM_APP_PKG_NAME + ".RequestCameraPermission"));
+
+ // We're only manually granting CAMERA, but the app will later request CUSTOM and get it
+ // granted silently. This is intentional since it's in the same group but both should
+ // eventually be revoked
+ clickOneTimeButton();
+
+ // Just waiting for the revocation
+ eventually(() -> Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+ mContext.getPackageManager()
+ .checkPermission(CAMERA, CUSTOM_CAMERA_PERM_APP_PKG_NAME)), 30000);
+
+ // This checks the vulnerability
+ eventually(() -> Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+ mContext.getPackageManager()
+ .checkPermission(CUSTOM_PERMISSION, CUSTOM_CAMERA_PERM_APP_PKG_NAME)),
+ 30000);
+
+ }
+
+ private void assertGrantedState(String s, int permissionGranted, long timeoutMillis) {
+ eventually(() -> Assert.assertEquals(s,
+ permissionGranted, mPackageManager
+ .checkPermission(ACCESS_FINE_LOCATION, APP_PKG_NAME)), timeoutMillis);
+ }
+
+ private void assertGranted(long timeoutMillis) {
+ assertGrantedState("Permission was never granted", PackageManager.PERMISSION_GRANTED,
+ timeoutMillis);
+ }
+
+ private void assertDenied(long timeoutMillis) {
+ assertGrantedState("Permission was never revoked", PackageManager.PERMISSION_DENIED,
+ timeoutMillis);
+ }
+
+ private void assertExpectedLifespan(CompletableFuture<Long> exitTime, long expectedLifespan)
+ throws InterruptedException, java.util.concurrent.ExecutionException,
+ java.util.concurrent.TimeoutException {
+ long grantedLength = System.currentTimeMillis() - exitTime.get(0, TimeUnit.MILLISECONDS);
+ if (grantedLength + ONE_TIME_TIMER_LOWER_GRACE_PERIOD < expectedLifespan) {
+ throw new AssertionError(
+ "The one time permission lived shorter than expected. expected: "
+ + expectedLifespan + "ms but was: " + grantedLength + "ms");
+ }
+ }
+
+ private void exitApp() {
+ boolean[] hasExited = {false};
+ try {
+ new Thread(() -> {
+ while (!hasExited[0]) {
+ DreamManager mDreamManager = mContext.getSystemService(DreamManager.class);
+ mUiDevice.pressHome();
+ mUiDevice.pressBack();
+ runWithShellPermissionIdentity(() -> {
+ if (mDreamManager.isDreaming()) {
+ mDreamManager.stopDream();
+ }
+ });
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }).start();
+ eventually(() -> {
+ runWithShellPermissionIdentity(() -> {
+ if (mActivityManager.getPackageImportance(APP_PKG_NAME)
+ <= IMPORTANCE_FOREGROUND) {
+ throw new AssertionError("Unable to exit application");
+ }
+ });
+ });
+ } finally {
+ hasExited[0] = true;
+ }
+ }
+
+ private void clickOneTimeButton() throws Throwable {
+ final UiObject2 uiObject = UiAutomatorUtils2.waitFindObject(By.res(
+ "com.android.permissioncontroller:id/permission_allow_one_time_button"), 10000);
+ Thread.sleep(500);
+ uiObject.click();
+ }
+
+ /**
+ * Start the app. The app will request the permissions.
+ */
+ private void startApp(ComponentName componentName) {
+ // One time permission is not applicable for Wear OS.
+ // The only permissions available are Allow or Deny
+ assumeFalse(
+ "Skipping test: One time permission is not supported in Wear OS",
+ FeatureUtil.isWatch());
+ Intent startApp = new Intent();
+ startApp.setComponent(componentName);
+ startApp.setFlags(FLAG_ACTIVITY_NEW_TASK);
+
+ mContext.startActivity(startApp);
+ }
+
+ /**
+ * Start the default app for these tests. The app will request the permissions.
+ */
+ private void startApp() {
+ startApp(new ComponentName(APP_PKG_NAME, APP_PKG_NAME + ".RequestPermission"));
+ }
+
+ private void startAppForegroundService(long lifespanMillis, boolean sticky) {
+ Intent intent = new Intent()
+ .setComponent(new ComponentName(
+ APP_PKG_NAME, APP_PKG_NAME + ".KeepAliveForegroundService"))
+ .putExtra(EXTRA_FOREGROUND_SERVICE_LIFESPAN, lifespanMillis)
+ .putExtra(EXTRA_FOREGROUND_SERVICE_STICKY, sticky);
+ mContext.startService(intent);
+ }
+
+ private CompletableFuture<Long> registerAppExitListener() {
+ CompletableFuture<Long> exitTimeCallback = new CompletableFuture<>();
+ try {
+ int uid = mContext.getPackageManager().getPackageUid(APP_PKG_NAME, 0);
+ runWithShellPermissionIdentity(() ->
+ mActivityManager.addOnUidImportanceListener(new SingleAppExitListener(
+ uid, IMPORTANCE_FOREGROUND, exitTimeCallback), IMPORTANCE_FOREGROUND));
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new AssertionError("Package not found.", e);
+ }
+ return exitTimeCallback;
+ }
+
+ private class SingleAppExitListener implements ActivityManager.OnUidImportanceListener {
+
+ private final int mUid;
+ private final int mImportance;
+ private final CompletableFuture<Long> mCallback;
+
+ SingleAppExitListener(int uid, int importance, CompletableFuture<Long> callback) {
+ mUid = uid;
+ mImportance = importance;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onUidImportance(int uid, int importance) {
+ if (uid == mUid && importance > mImportance) {
+ mCallback.complete(System.currentTimeMillis());
+ mActivityManager.removeOnUidImportanceListener(this);
+ }
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PackageManagerRequiringPermissionsTest.java b/tests/cts/permission/src/android/permission/cts/PackageManagerRequiringPermissionsTest.java
new file mode 100644
index 000000000..7ebb09f98
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PackageManagerRequiringPermissionsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.AppModeFull;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify the PackageManager related operations require specific permissions.
+ */
+@SmallTest
+public class PackageManagerRequiringPermissionsTest extends AndroidTestCase {
+ // Must be a known-present application package other than the one hosting this class
+ private static final String PACKAGE_NAME = "android";
+
+ private PackageManager mPackageManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mPackageManager = getContext().getPackageManager();
+ assertNotNull(mPackageManager);
+ }
+
+ /**
+ * Verify that PackageManager.setApplicationEnabledSetting requires permission.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#CHANGE_COMPONENT_ENABLED_STATE}.
+ */
+ public void testSetApplicationEnabledSetting() {
+ try {
+ mPackageManager.setApplicationEnabledSetting(PACKAGE_NAME,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ fail("PackageManager.setApplicationEnabledSetting did not throw SecurityException as"
+ + "expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that PackageManager.addPreferredActivity requires permission.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SET_PREFERRED_APPLICATIONS}.
+ */
+ public void testAddPreferredActivity() {
+ try {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
+ filter.addCategory(Intent.CATEGORY_HOME);
+ mPackageManager.addPreferredActivity(filter, 0, null, null);
+ fail("PackageManager.addPreferredActivity did not throw" +
+ " SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that PackageManager.clearPackagePreferredActivities requires permission.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SET_PREFERRED_APPLICATIONS}.
+ */
+ @AppModeFull(reason = "clearPackagePreferredActivities always returns null for instant apps "
+ + "(it does not even check for permissions)")
+ public void testClearPackagePreferredActivities() {
+ try {
+ mPackageManager.clearPackagePreferredActivities(null);
+ fail("PackageManager.clearPackagePreferredActivities did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that PackageManager.verifyPendingInstall requires permission.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#PACKAGE_VERIFICATION_AGENT}
+ */
+ public void testVerifyPendingInstall() {
+ try {
+ mPackageManager.verifyPendingInstall(1, 1);
+ fail("PackageManager.verifyPendingInstall did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that PackageManager.extendVerificationTimeout requires permission.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#PACKAGE_VERIFICATION_AGENT}.
+ */
+ public void testExtendVerificationTimeout() {
+ try {
+ mPackageManager.extendVerificationTimeout(1, 1, 10000);
+ fail("PackageManager.extendVerificationTimeout did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PermissionControllerTest.java b/tests/cts/permission/src/android/permission/cts/PermissionControllerTest.java
new file mode 100644
index 000000000..4367d2bf6
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PermissionControllerTest.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.BODY_SENSORS;
+import static android.Manifest.permission.READ_CALENDAR;
+import static android.Manifest.permission.READ_CONTACTS;
+import static android.Manifest.permission.WRITE_CALENDAR;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.permissionToOp;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.permission.PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED;
+import static android.permission.PermissionControllerManager.REASON_INSTALLER_POLICY_VIOLATION;
+import static android.permission.PermissionControllerManager.REASON_MALWARE;
+import static android.permission.cts.PermissionUtils.grantPermission;
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permission.cts.PermissionUtils.isPermissionGranted;
+
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.util.Collections.singletonList;
+
+import android.app.AppOpsManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.pm.PermissionGroupInfo;
+import android.permission.PermissionControllerManager;
+import android.permission.RuntimePermissionPresentationInfo;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Test {@link PermissionControllerManager}
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Instant apps cannot talk to permission controller")
+public class PermissionControllerTest {
+ private static final String APK =
+ "/data/local/tmp/cts-permission/CtsAppThatAccessesLocationOnCommand.apk";
+ private static final String APP = "android.permission.cts.appthataccesseslocation";
+ private static final String APK2 =
+ "/data/local/tmp/cts-permission/"
+ + "CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk";
+ private static final String APP2 = "android.permission.cts.appthatrequestcustompermission";
+ private static final String CUSTOM_PERMISSION =
+ "android.permission.cts.appthatrequestcustompermission.TEST_PERMISSION";
+
+ private static final UiAutomation sUiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ private static final Context sContext = InstrumentationRegistry.getTargetContext();
+ private static final PermissionControllerManager sController =
+ sContext.getSystemService(PermissionControllerManager.class);
+
+ @Before
+ @After
+ public void resetAppState() {
+ runWithShellPermissionIdentity(() -> {
+ sUiAutomation.grantRuntimePermission(APP, ACCESS_FINE_LOCATION);
+ sUiAutomation.grantRuntimePermission(APP, ACCESS_BACKGROUND_LOCATION);
+ setAppOp(APP, ACCESS_FINE_LOCATION, MODE_ALLOWED);
+ });
+ }
+
+ @BeforeClass
+ public static void installApp() {
+ runShellCommandOrThrow("pm install -r -g " + APK);
+ runShellCommandOrThrow("pm install -r " + APK2);
+ }
+
+ @AfterClass
+ public static void uninstallApp() {
+ runShellCommand("pm uninstall " + APP);
+ runShellCommand("pm uninstall " + APP2);
+ }
+
+ private @NonNull Map<String, List<String>> revokePermissions(
+ @NonNull Map<String, List<String>> request, boolean doDryRun, int reason,
+ @NonNull Executor executor) throws Exception {
+ AtomicReference<Map<String, List<String>>> result = new AtomicReference<>();
+
+ sController.revokeRuntimePermissions(request, doDryRun, reason, executor,
+ new PermissionControllerManager.OnRevokeRuntimePermissionsCallback() {
+ @Override
+ public void onRevokeRuntimePermissions(@NonNull Map<String, List<String>> r) {
+ synchronized (result) {
+ result.set(r);
+ result.notifyAll();
+ }
+ }
+ });
+
+ synchronized (result) {
+ while (result.get() == null) {
+ result.wait();
+ }
+ }
+
+ return result.get();
+ }
+
+ private @NonNull Map<String, List<String>> revokePermissions(
+ @NonNull Map<String, List<String>> request, boolean doDryRun, boolean adoptShell)
+ throws Exception {
+ if (adoptShell) {
+ Map<String, List<String>> revokeRet =
+ callWithShellPermissionIdentity(() -> revokePermissions(
+ request, doDryRun, REASON_MALWARE, sContext.getMainExecutor()));
+ return revokeRet;
+ }
+ return revokePermissions(request, doDryRun, REASON_MALWARE, sContext.getMainExecutor());
+ }
+
+ private @NonNull Map<String, List<String>> revokePermissions(
+ @NonNull Map<String, List<String>> request, boolean doDryRun) throws Exception {
+ return revokePermissions(request, doDryRun, true);
+ }
+
+ private void setAppOp(@NonNull String pkg, @NonNull String perm, int mode) throws Exception {
+ sContext.getSystemService(AppOpsManager.class).setUidMode(permissionToOp(perm),
+ sContext.getPackageManager().getPackageUid(pkg, 0), mode);
+ }
+
+ private Map<String, List<String>> buildRevokeRequest(@NonNull String app,
+ @NonNull String permission) {
+ return Collections.singletonMap(app, singletonList(permission));
+ }
+
+ private void assertRuntimePermissionLabelsAreValid(List<String> runtimePermissions,
+ List<RuntimePermissionPresentationInfo> permissionInfos, int expectedRuntimeGranted,
+ String app) throws Exception {
+ int numRuntimeGranted = 0;
+ for (String permission : runtimePermissions) {
+ if (isPermissionGranted(app, permission)) {
+ numRuntimeGranted++;
+ }
+ }
+ assertThat(numRuntimeGranted).isEqualTo(expectedRuntimeGranted);
+
+ ArrayList<CharSequence> maybeStandardPermissionLabels = new ArrayList<>();
+ ArrayList<CharSequence> nonStandardPermissionLabels = new ArrayList<>();
+ for (PermissionGroupInfo permGroup : sContext.getPackageManager().getAllPermissionGroups(
+ 0)) {
+ CharSequence permissionGroupLabel = permGroup.loadLabel(sContext.getPackageManager());
+ if (permGroup.packageName.equals("android")) {
+ maybeStandardPermissionLabels.add(permissionGroupLabel);
+ } else {
+ nonStandardPermissionLabels.add(permissionGroupLabel);
+ }
+ }
+
+ int numInfosGranted = 0;
+
+ for (RuntimePermissionPresentationInfo permissionInfo : permissionInfos) {
+ CharSequence permissionGroupLabel = permissionInfo.getLabel();
+
+ // PermissionInfo should be included in exactly one of existing (possibly) standard
+ // or nonstandard permission groups
+ if (permissionInfo.isStandard()) {
+ assertThat(maybeStandardPermissionLabels).contains(permissionGroupLabel);
+ } else {
+ assertThat(nonStandardPermissionLabels).contains(permissionGroupLabel);
+ }
+ if (permissionInfo.isGranted()) {
+ numInfosGranted++;
+ }
+ }
+
+ // Each permissionInfo represents one or more runtime permissions, but we don't have a
+ // mapping, so we check that we have at least as many runtimePermissions as permissionInfos
+ assertThat(numRuntimeGranted).isAtLeast(numInfosGranted);
+ }
+
+ @Test
+ public void revokePermissionsDryRunSinglePermission() throws Exception {
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_BACKGROUND_LOCATION);
+
+ Map<String, List<String>> result = revokePermissions(request, true);
+
+ assertThat(result.size()).isEqualTo(1);
+ assertThat(result.get(APP)).isNotNull();
+ assertThat(result.get(APP)).containsExactly(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ @Test
+ public void revokePermissionsSinglePermission() throws Exception {
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_BACKGROUND_LOCATION);
+
+ revokePermissions(request, false);
+
+ assertThat(sContext.getPackageManager().checkPermission(ACCESS_BACKGROUND_LOCATION,
+ APP)).isEqualTo(PERMISSION_DENIED);
+ }
+
+ @Test
+ public void revokePermissionsDoNotAlreadyRevokedPermission() throws Exception {
+ // Properly revoke the permission
+ runWithShellPermissionIdentity(() -> {
+ sUiAutomation.revokeRuntimePermission(APP, ACCESS_BACKGROUND_LOCATION);
+ setAppOp(APP, ACCESS_FINE_LOCATION, MODE_FOREGROUND);
+ });
+
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_BACKGROUND_LOCATION);
+ Map<String, List<String>> result = revokePermissions(request, false);
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void revokePermissionsDryRunForegroundPermission() throws Exception {
+ assertThat(sContext.getPackageManager().checkPermission(ACCESS_FINE_LOCATION,
+ APP)).isEqualTo(PERMISSION_GRANTED);
+
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_FINE_LOCATION);
+ Map<String, List<String>> result = revokePermissions(request, true);
+
+ assertThat(result.size()).isEqualTo(1);
+ assertThat(result.get(APP)).isNotNull();
+ assertThat(result.get(APP)).containsExactly(ACCESS_FINE_LOCATION,
+ ACCESS_BACKGROUND_LOCATION, ACCESS_COARSE_LOCATION);
+ }
+
+ @Test
+ public void revokePermissionsUnrequestedPermission() throws Exception {
+ Map<String, List<String>> request = buildRevokeRequest(APP, READ_CONTACTS);
+
+ Map<String, List<String>> result = revokePermissions(request, false);
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void revokeFromUnknownPackage() throws Exception {
+ Map<String, List<String>> request = buildRevokeRequest("invalid.app", READ_CONTACTS);
+
+ Map<String, List<String>> result = revokePermissions(request, false);
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void revokePermissionsFromUnknownPermission() throws Exception {
+ Map<String, List<String>> request = buildRevokeRequest(APP, "unknown.permission");
+
+ Map<String, List<String>> result = revokePermissions(request, false);
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void revokePermissionsPolicyViolationFromWrongPackage() throws Exception {
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_FINE_LOCATION);
+ Map<String, List<String>> result = callWithShellPermissionIdentity(
+ () -> revokePermissions(request,
+ false, REASON_INSTALLER_POLICY_VIOLATION, sContext.getMainExecutor()));
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void revokePermissionsWithExecutorForCallback() throws Exception {
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_BACKGROUND_LOCATION);
+
+ AtomicBoolean wasRunOnExecutor = new AtomicBoolean();
+ runWithShellPermissionIdentity(() ->
+ revokePermissions(request, true, REASON_MALWARE, command -> {
+ wasRunOnExecutor.set(true);
+ command.run();
+ }));
+
+ assertThat(wasRunOnExecutor.get()).isTrue();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void revokePermissionsWithNullPkg() throws Exception {
+ Map<String, List<String>> request = Collections.singletonMap(null,
+ singletonList(ACCESS_FINE_LOCATION));
+
+ revokePermissions(request, true);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void revokePermissionsWithNullPermissions() throws Exception {
+ Map<String, List<String>> request = Collections.singletonMap(APP, null);
+
+ revokePermissions(request, true);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void revokePermissionsWithNullPermission() throws Exception {
+ Map<String, List<String>> request = Collections.singletonMap(APP,
+ singletonList(null));
+
+ revokePermissions(request, true);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void revokePermissionsWithNullRequests() {
+ sController.revokeRuntimePermissions(null, false, REASON_MALWARE,
+ sContext.getMainExecutor(),
+ new PermissionControllerManager.OnRevokeRuntimePermissionsCallback() {
+ @Override
+ public void onRevokeRuntimePermissions(
+ @NonNull Map<String, List<String>> revoked) {
+ }
+ });
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void revokePermissionsWithNullCallback() {
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_BACKGROUND_LOCATION);
+
+ sController.revokeRuntimePermissions(request, false, REASON_MALWARE,
+ sContext.getMainExecutor(), null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void revokePermissionsWithNullExecutor() {
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_BACKGROUND_LOCATION);
+
+ sController.revokeRuntimePermissions(request, false, REASON_MALWARE, null,
+ new PermissionControllerManager.OnRevokeRuntimePermissionsCallback() {
+ @Override
+ public void onRevokeRuntimePermissions(
+ @NonNull Map<String, List<String>> revoked) {
+
+ }
+ });
+ }
+
+ @Test(expected = SecurityException.class)
+ public void revokePermissionsWithoutPermission() throws Exception {
+ Map<String, List<String>> request = buildRevokeRequest(APP, ACCESS_BACKGROUND_LOCATION);
+
+ // This will fail as the test-app does not have the required permission
+ revokePermissions(request, true, false);
+ }
+
+ @Test
+ public void getAppPermissionsForApp() throws Exception {
+ CompletableFuture<List<RuntimePermissionPresentationInfo>> futurePermissionInfos =
+ new CompletableFuture<>();
+
+ List<String> runtimePermissions;
+ List<RuntimePermissionPresentationInfo> permissionInfos;
+
+ sUiAutomation.adoptShellPermissionIdentity();
+ try {
+ sController.getAppPermissions(APP, futurePermissionInfos::complete, null);
+ runtimePermissions = PermissionUtils.getRuntimePermissions(APP);
+ assertThat(runtimePermissions).isNotEmpty();
+ permissionInfos = futurePermissionInfos.get();
+ } finally {
+ sUiAutomation.dropShellPermissionIdentity();
+ }
+
+ assertRuntimePermissionLabelsAreValid(runtimePermissions, permissionInfos, 3, APP);
+ }
+
+ @Test
+ public void getAppPermissionsForCustomApp() throws Exception {
+ CompletableFuture<List<RuntimePermissionPresentationInfo>> futurePermissionInfos =
+ new CompletableFuture<>();
+
+ // Grant all requested permissions except READ_CALENDAR
+ sUiAutomation.grantRuntimePermission(APP2, CUSTOM_PERMISSION);
+ PermissionUtils.grantPermission(APP2, BODY_SENSORS);
+ PermissionUtils.grantPermission(APP2, READ_CONTACTS);
+ PermissionUtils.grantPermission(APP2, WRITE_CALENDAR);
+
+ List<String> runtimePermissions;
+ List<RuntimePermissionPresentationInfo> permissionInfos;
+ sUiAutomation.adoptShellPermissionIdentity();
+ try {
+ sController.getAppPermissions(APP2, futurePermissionInfos::complete, null);
+ runtimePermissions = PermissionUtils.getRuntimePermissions(APP2);
+
+ permissionInfos = futurePermissionInfos.get();
+ } finally {
+ sUiAutomation.dropShellPermissionIdentity();
+ }
+
+ assertThat(permissionInfos).isNotEmpty();
+ assertThat(runtimePermissions.size()).isEqualTo(6);
+ assertRuntimePermissionLabelsAreValid(runtimePermissions, permissionInfos, 4, APP2);
+ }
+
+ @Test
+ public void revokePermissionAutomaticallyExtendsToWholeGroup() throws Exception {
+ grantPermission(APP2, READ_CALENDAR);
+ grantPermission(APP2, WRITE_CALENDAR);
+
+ runWithShellPermissionIdentity(
+ () -> {
+ sController.revokeRuntimePermission(APP2, READ_CALENDAR);
+
+ eventually(() -> {
+ assertThat(isGranted(APP2, READ_CALENDAR)).isEqualTo(false);
+ // revokePermission automatically extends the revocation to whole group
+ assertThat(isGranted(APP2, WRITE_CALENDAR)).isEqualTo(false);
+ });
+ });
+ }
+
+ @Test
+ public void revokePermissionCustom() throws Exception {
+ sUiAutomation.grantRuntimePermission(APP2, CUSTOM_PERMISSION);
+
+ runWithShellPermissionIdentity(
+ () -> {
+ sController.revokeRuntimePermission(APP2, CUSTOM_PERMISSION);
+
+ eventually(() -> {
+ assertThat(isPermissionGranted(APP2, CUSTOM_PERMISSION)).isEqualTo(false);
+ });
+ });
+ }
+
+ @Test
+ public void revokePermissionWithInvalidPkg() throws Exception {
+ // No return value, call is ignored
+ runWithShellPermissionIdentity(
+ () -> sController.revokeRuntimePermission("invalid.package", READ_CALENDAR));
+ }
+
+ @Test
+ public void revokePermissionWithInvalidPermission() throws Exception {
+ // No return value, call is ignored
+ runWithShellPermissionIdentity(
+ () -> sController.revokeRuntimePermission(APP2, "invalid.permission"));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void revokePermissionWithNullPkg() throws Exception {
+ sController.revokeRuntimePermission(null, READ_CALENDAR);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void revokePermissionWithNullPermission() throws Exception {
+ sController.revokeRuntimePermission(APP2, null);
+ }
+
+ // TODO: Add more tests for countPermissionAppsGranted when the method can be safely called
+ // multiple times in a row
+
+ @Test
+ public void countPermissionAppsGranted() {
+ runWithShellPermissionIdentity(
+ () -> {
+ CompletableFuture<Integer> numApps = new CompletableFuture<>();
+
+ sController.countPermissionApps(singletonList(ACCESS_FINE_LOCATION),
+ COUNT_ONLY_WHEN_GRANTED, numApps::complete, null);
+
+ // TODO: Better would be to count before, grant a permission, count again and
+ // then compare before and after
+ assertThat(numApps.get()).isAtLeast(1);
+ });
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void countPermissionAppsNullPermission() {
+ sController.countPermissionApps(null, 0, (n) -> { }, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void countPermissionAppsInvalidFlags() {
+ sController.countPermissionApps(singletonList(ACCESS_FINE_LOCATION), -1, (n) -> { }, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void countPermissionAppsNullCallback() {
+ sController.countPermissionApps(singletonList(ACCESS_FINE_LOCATION), 0, null, null);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PermissionFlagsTest.java b/tests/cts/permission/src/android/permission/cts/PermissionFlagsTest.java
new file mode 100644
index 000000000..d03e215ed
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PermissionFlagsTest.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.READ_CALL_LOG;
+import static android.Manifest.permission.READ_CONTACTS;
+import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.permission.cts.PermissionUtils.clearAppState;
+import static android.permission.cts.PermissionUtils.getAllPermissionFlags;
+import static android.permission.cts.PermissionUtils.getPermissionFlags;
+import static android.permission.cts.PermissionUtils.install;
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permission.cts.PermissionUtils.setPermissionFlags;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.platform.test.annotations.PlatinumTest;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests how permission flags behave.
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Cannot read permission flags of other app.")
+@PlatinumTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+public class PermissionFlagsTest {
+ /** The package name of most apps used in the test */
+ private static final String APP_PKG = "android.permission.cts.appthatrequestpermission";
+ private static final String APP_SYSTEM_ALERT_WINDOW_PKG =
+ "android.permission.cts.usesystemalertwindowpermission";
+
+ private static final String TMP_DIR = "/data/local/tmp/cts-permission/";
+ private static final String APK_CONTACTS_15 =
+ TMP_DIR + "CtsAppThatRequestsContactsPermission15.apk";
+ private static final String APK_LOCATION_22 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission22.apk";
+ private static final String APK_LOCATION_28 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission28.apk";
+ private static final String APK_SYSTEM_ALERT_WINDOW_23 =
+ TMP_DIR + "CtsAppThatRequestsSystemAlertWindow23.apk";
+
+ @After
+ @Before
+ public void uninstallTestApp() {
+ uninstallApp(APP_PKG);
+ uninstallApp(APP_SYSTEM_ALERT_WINDOW_PKG);
+ }
+
+ @Test
+ public void implicitPermission() {
+ install(APK_LOCATION_28);
+
+ assertEquals(FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
+ getPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION));
+ }
+
+ @Test
+ public void regularPermission() {
+ install(APK_LOCATION_28);
+
+ assertEquals(0, getPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION));
+ }
+
+ @Test
+ public void regularPermissionPreM() {
+ install(APK_CONTACTS_15);
+
+ assertEquals(FLAG_PERMISSION_REVIEW_REQUIRED,
+ getPermissionFlags(APP_PKG, READ_CONTACTS) & FLAG_PERMISSION_REVIEW_REQUIRED);
+ }
+
+ @Test
+ public void clearRegularPermissionPreM() {
+ install(APK_CONTACTS_15);
+
+ int defaultState = getPermissionFlags(APP_PKG, READ_CONTACTS);
+ setPermissionFlags(APP_PKG, READ_CONTACTS, FLAG_PERMISSION_REVIEW_REQUIRED, 0);
+ setPermissionFlags(APP_PKG, READ_CONTACTS,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED);
+
+ clearAppState(APP_PKG);
+
+ eventually(() -> assertEquals(defaultState, getPermissionFlags(APP_PKG, READ_CONTACTS)));
+ }
+
+ @Test
+ public void clearImplicitPermissionPreM() {
+ install(APK_CONTACTS_15);
+
+ int defaultState = getPermissionFlags(APP_PKG, READ_CALL_LOG);
+ setPermissionFlags(APP_PKG, READ_CALL_LOG, FLAG_PERMISSION_REVIEW_REQUIRED, 0);
+ setPermissionFlags(APP_PKG, READ_CALL_LOG,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED);
+
+ clearAppState(APP_PKG);
+
+ eventually(() -> assertEquals(defaultState, getPermissionFlags(APP_PKG, READ_CALL_LOG)));
+ }
+
+ @Test
+ public void clearRegularPermission() {
+ install(APK_LOCATION_28);
+
+ int defaultState = getPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION);
+ setPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED);
+
+ clearAppState(APP_PKG);
+
+ eventually(() -> assertEquals(defaultState,
+ getPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION)));
+ }
+
+ @Test
+ public void clearImplicitPermission() {
+ install(APK_LOCATION_28);
+
+ int defaultState = getPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+ setPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED);
+
+ clearAppState(APP_PKG);
+
+ eventually(() -> assertEquals(defaultState,
+ getPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION)));
+ }
+
+ @Test
+ public void reinstallPreM() {
+ install(APK_CONTACTS_15);
+ install(APK_CONTACTS_15);
+
+ assertEquals(FLAG_PERMISSION_REVIEW_REQUIRED,
+ getPermissionFlags(APP_PKG, READ_CONTACTS) & FLAG_PERMISSION_REVIEW_REQUIRED);
+ }
+
+ @Test
+ public void reinstallDoesNotOverrideChangesPreM() {
+ install(APK_CONTACTS_15);
+
+ setPermissionFlags(APP_PKG, READ_CONTACTS, FLAG_PERMISSION_REVIEW_REQUIRED, 0);
+ setPermissionFlags(APP_PKG, READ_CONTACTS,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED);
+
+ install(APK_CONTACTS_15);
+
+ assertEquals(FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ getPermissionFlags(APP_PKG, READ_CONTACTS) & (FLAG_PERMISSION_USER_SET
+ | FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_REVIEW_REQUIRED));
+ }
+
+ @Test
+ public void reinstall() {
+ install(APK_LOCATION_28);
+ install(APK_LOCATION_28);
+
+ assertEquals(0, getPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION));
+ assertEquals(FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
+ getPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION));
+ }
+
+ @Test
+ public void reinstallDoesNotOverrideChanges() {
+ install(APK_LOCATION_28);
+
+ setPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED);
+ setPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED);
+
+ install(APK_LOCATION_28);
+
+ assertEquals(FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED,
+ getPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION));
+
+ assertEquals(FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED
+ | FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
+ getPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION));
+ }
+
+ @Test
+ public void revokeOnUpgrade() throws Exception {
+ install(APK_LOCATION_22);
+
+ install(APK_LOCATION_28);
+
+ assertFalse(isGranted(APP_PKG, ACCESS_COARSE_LOCATION));
+ assertFalse(isGranted(APP_PKG, ACCESS_BACKGROUND_LOCATION));
+ assertEquals(0,getPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION)
+ & FLAG_PERMISSION_REVOKED_COMPAT);
+ assertEquals(0,getPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION)
+ & FLAG_PERMISSION_REVOKED_COMPAT);
+ }
+
+ @AsbSecurityTest(cveBugId = 283006437)
+ @Test
+ public void nonRuntimePermissionFlagsPreservedAfterReinstall() throws Exception {
+ install(APK_SYSTEM_ALERT_WINDOW_23);
+
+ int flags = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_ROLE;
+ setPermissionFlags(APP_SYSTEM_ALERT_WINDOW_PKG, SYSTEM_ALERT_WINDOW, flags, flags);
+ assertEquals(flags, getAllPermissionFlags(APP_SYSTEM_ALERT_WINDOW_PKG, SYSTEM_ALERT_WINDOW)
+ & flags);
+
+ install(APK_SYSTEM_ALERT_WINDOW_23);
+
+ assertEquals(flags, getAllPermissionFlags(APP_SYSTEM_ALERT_WINDOW_PKG, SYSTEM_ALERT_WINDOW)
+ & flags);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PermissionGroupChange.java b/tests/cts/permission/src/android/permission/cts/PermissionGroupChange.java
new file mode 100644
index 000000000..46fe167c0
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PermissionGroupChange.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.widget.ScrollView;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiScrollable;
+import androidx.test.uiautomator.UiSelector;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+public class PermissionGroupChange {
+ private static final String APP_PKG_NAME = "android.permission.cts.appthatrequestpermission";
+ private static final long EXPECTED_BEHAVIOR_TIMEOUT_SEC = 15;
+ private static final long UNEXPECTED_BEHAVIOR_TIMEOUT_SEC = 2;
+
+ private Context mContext;
+ private UiDevice mUiDevice;
+ private String mAllowButtonText = null;
+
+ @Before
+ public void setContextAndUiDevice() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+
+ @Before
+ public void uninstallAndWakeUpScreen() {
+ runShellCommand("pm uninstall " + APP_PKG_NAME);
+ SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP");
+ }
+
+ /**
+ * Retry for a time until the runnable stops throwing.
+ *
+ * @param runnable The condition to execute
+ * @param timeoutSec The time to try
+ */
+ private void eventually(ThrowingRunnable runnable, long timeoutSec) throws Throwable {
+ long startTime = System.nanoTime();
+ while (true) {
+ try {
+ runnable.run();
+ return;
+ } catch (Throwable t) {
+ if (System.nanoTime() - startTime < TimeUnit.SECONDS.toNanos(timeoutSec)) {
+ Thread.sleep(100);
+ continue;
+ }
+
+ throw t;
+ }
+ }
+ }
+
+
+ private void scrollToBottomIfWatch() throws Exception {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ UiScrollable scrollable = new UiScrollable(
+ new UiSelector().className(ScrollView.class));
+ if (scrollable.exists()) {
+ scrollable.flingToEnd(10);
+ }
+ }
+ }
+
+ protected void clickAllowButton() throws Exception {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ if (mAllowButtonText == null) {
+ mAllowButtonText = getPermissionControllerString("grant_dialog_button_allow");
+ }
+ mUiDevice.findObject(By.text(Pattern.compile(Pattern.quote(mAllowButtonText),
+ Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE))).click();
+ } else {
+ mUiDevice.findObject(By.res(
+ "com.android.permissioncontroller:id/permission_allow_button")).click();
+ }
+ }
+
+ private void grantPermissionViaUi() throws Throwable {
+ eventually(() -> {
+ scrollToBottomIfWatch();
+ clickAllowButton();
+ }, EXPECTED_BEHAVIOR_TIMEOUT_SEC);
+ }
+
+ private void waitUntilPermissionGranted(String permName, long timeoutSec) throws Throwable {
+ eventually(() -> {
+ PackageInfo appInfo = mContext.getPackageManager().getPackageInfo(APP_PKG_NAME,
+ GET_PERMISSIONS);
+
+ for (int i = 0; i < appInfo.requestedPermissions.length; i++) {
+ if (appInfo.requestedPermissions[i].equals(permName)
+ && ((appInfo.requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED)
+ != 0)) {
+ return;
+ }
+ }
+
+ fail(permName + " not granted");
+ }, timeoutSec);
+ }
+
+ private void installApp(String apk) {
+ String installResult = SystemUtil.runShellCommandOrThrow(
+ "pm install -r /data/local/tmp/cts-permission/" + apk + ".apk");
+ assertEquals("Success", installResult.trim());
+ }
+
+ /**
+ * Start the app. The app will request the permissions.
+ */
+ private void startApp() {
+ Intent startApp = new Intent();
+ startApp.setComponent(new ComponentName(APP_PKG_NAME, APP_PKG_NAME + ".RequestPermission"));
+ startApp.setFlags(FLAG_ACTIVITY_NEW_TASK);
+
+ mContext.startActivity(startApp);
+ }
+
+ @After
+ public void uninstallTestApp() {
+ runShellCommand("pm uninstall android.permission.cts.appthatrequestpermission");
+ }
+
+ @Test
+ @AppModeFull
+ @AsbSecurityTest(cveBugId = 72710897)
+ public void permissionGroupShouldNotBeAutoGrantedIfNewMember() throws Throwable {
+ installApp("CtsAppThatRequestsPermissionAandB");
+
+ startApp();
+ grantPermissionViaUi();
+ waitUntilPermissionGranted("android.permission.cts.appthatrequestpermission.A",
+ EXPECTED_BEHAVIOR_TIMEOUT_SEC);
+
+ // Update app which changes the permission group of "android.permission.cts
+ // .appthatrequestpermission.A" to the same as "android.permission.cts.C"
+ installApp("CtsAppThatRequestsPermissionAandC");
+
+ startApp();
+ try {
+ // The permission should not be auto-granted
+ waitUntilPermissionGranted("android.permission.cts.C", UNEXPECTED_BEHAVIOR_TIMEOUT_SEC);
+ fail("android.permission.cts.C was auto-granted");
+ } catch (Throwable expected) {
+ assertEquals("android.permission.cts.C not granted", expected.getMessage());
+ }
+ }
+
+ private String getPermissionControllerString(String res)
+ throws PackageManager.NameNotFoundException {
+ Resources permissionControllerResources = mContext.createPackageContext(
+ mContext.getPackageManager().getPermissionControllerPackageName(), 0)
+ .getResources();
+ return permissionControllerResources.getString(permissionControllerResources
+ .getIdentifier(res, "string", "com.android.permissioncontroller"));
+ }
+
+ private interface ThrowingRunnable {
+ void run() throws Throwable;
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PermissionManagerNativeJniTest.java b/tests/cts/permission/src/android/permission/cts/PermissionManagerNativeJniTest.java
new file mode 100644
index 000000000..868b3d1fc
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PermissionManagerNativeJniTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import org.junit.runner.RunWith;
+import com.android.gtestrunner.GtestRunner;
+import com.android.gtestrunner.TargetLibrary;
+
+@RunWith(GtestRunner.class)
+@TargetLibrary("permissionmanager_native_test")
+public class PermissionManagerNativeJniTest {}
+
diff --git a/tests/cts/permission/src/android/permission/cts/PermissionManagerTest.java b/tests/cts/permission/src/android/permission/cts/PermissionManagerTest.java
new file mode 100644
index 000000000..6fa940aa0
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PermissionManagerTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.permission.PermissionManager;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link PermissionManager}
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Instant apps cannot talk to permission manager")
+public class PermissionManagerTest {
+ private final Context mContext = InstrumentationRegistry.getTargetContext();
+
+ @Test
+ public void testRuntimePermissionsVersion() throws Exception {
+ final PermissionManager permissionManager =
+ mContext.getSystemService(PermissionManager.class);
+ final int version = callWithShellPermissionIdentity(() ->
+ permissionManager.getRuntimePermissionsVersion());
+ assertThat(version).isAtLeast(0);
+ runWithShellPermissionIdentity(() ->
+ permissionManager.setRuntimePermissionsVersion(version));
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PermissionStubActivity.java b/tests/cts/permission/src/android/permission/cts/PermissionStubActivity.java
new file mode 100644
index 000000000..dd611777c
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PermissionStubActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ListView;
+
+/**
+ * A minimal application for Window test.
+ */
+public class PermissionStubActivity extends Activity {
+ private ListView mListView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mListView = new ListView(this);
+ mListView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT));
+
+ setContentView(mListView);
+ }
+
+ public Dialog getDialog() {
+ return new AlertDialog.Builder(PermissionStubActivity.this).create();
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java b/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java
new file mode 100644
index 000000000..543a3cbbd
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.companion.virtual.VirtualDeviceManager;
+import android.companion.virtual.VirtualDeviceParams;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.OnPermissionsChangedListener;
+import android.permission.flags.Flags;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.virtualdevice.cts.common.FakeAssociationRule;
+
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@AppModeFull(reason = "Instant apps cannot access properties of other apps")
+@RunWith(AndroidJUnit4ClassRunner.class)
+public class PermissionUpdateListenerTest {
+ private static final String LOG_TAG = PermissionUpdateListenerTest.class.getSimpleName();
+ private static final String APK =
+ "/data/local/tmp/cts-permission/"
+ + "CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk";
+ private static final String PACKAGE_NAME =
+ "android.permission.cts.appthatrequestcustompermission";
+ private static final String PERMISSION_NAME = "android.permission.RECORD_AUDIO";
+ private static final int TIMEOUT = 10000;
+
+ private final Context mDefaultContext =
+ InstrumentationRegistry.getInstrumentation().getContext();
+ private final PackageManager mPackageManager = mDefaultContext.getPackageManager();
+
+ private int mTestAppUid;
+
+ private VirtualDeviceManager mVirtualDeviceManager;
+
+ @Rule
+ public FakeAssociationRule mFakeAssociationRule = new FakeAssociationRule();
+
+ @Rule
+ public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ android.Manifest.permission.CREATE_VIRTUAL_DEVICE);
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ @Before
+ public void setup() throws PackageManager.NameNotFoundException, InterruptedException {
+ runShellCommandOrThrow("pm install " + APK);
+ // permission change events are generated for a package install, the wait helps prevent
+ // those permission change events interfere with the test.
+ SystemUtil.waitForBroadcasts();
+ Thread.sleep(1000);
+ mTestAppUid = mPackageManager.getPackageUid(PACKAGE_NAME, 0);
+ mVirtualDeviceManager = mDefaultContext.getSystemService(VirtualDeviceManager.class);
+ }
+
+ @After
+ public void cleanup() {
+ runShellCommand("pm uninstall " + PACKAGE_NAME);
+ }
+
+ @Test
+ public void testGrantPermissionInvokesOldCallback() throws InterruptedException {
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ OnPermissionsChangedListener permissionsChangedListener =
+ uid -> {
+ if (mTestAppUid == uid) {
+ countDownLatch.countDown();
+ }
+ };
+
+ runWithShellPermissionIdentity(() -> {
+ mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener);
+ mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
+ mDefaultContext.getUser());
+ });
+ countDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
+ runWithShellPermissionIdentity(() -> {
+ mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
+ });
+
+ assertThat(countDownLatch.getCount()).isEqualTo(0);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public void testVirtualDeviceGrantPermissionNotifyListener() throws InterruptedException {
+ VirtualDeviceManager.VirtualDevice virtualDevice =
+ mVirtualDeviceManager.createVirtualDevice(
+ mFakeAssociationRule.getAssociationInfo().getId(),
+ new VirtualDeviceParams.Builder().build());
+ Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId());
+ testGrantPermissionNotifyListener(deviceContext, virtualDevice.getPersistentDeviceId());
+ }
+
+ @Test
+ public void testDefaultDeviceGrantPermissionNotifyListener() throws InterruptedException {
+ testGrantPermissionNotifyListener(
+ mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+ }
+
+ private void testGrantPermissionNotifyListener(
+ Context context, String expectedDeviceId) throws InterruptedException {
+ final PackageManager packageManager = context.getPackageManager();
+ TestOnPermissionsChangedListener permissionsChangedListener =
+ new TestOnPermissionsChangedListener(1);
+ runWithShellPermissionIdentity(() -> {
+ packageManager.addOnPermissionsChangeListener(permissionsChangedListener);
+ packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
+ mDefaultContext.getUser());
+ });
+
+ permissionsChangedListener.waitForPermissionChangedCallbacks();
+ runWithShellPermissionIdentity(() -> {
+ packageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
+ });
+
+ String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid);
+ assertThat(deviceId).isEqualTo(expectedDeviceId);
+ }
+
+ @Test
+ public void testDefaultDeviceRevokePermissionNotifyListener() throws InterruptedException {
+ testRevokePermissionNotifyListener(
+ mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public void testVirtualDeviceRevokePermissionNotifyListener() throws InterruptedException {
+ VirtualDeviceManager.VirtualDevice virtualDevice =
+ mVirtualDeviceManager.createVirtualDevice(
+ mFakeAssociationRule.getAssociationInfo().getId(),
+ new VirtualDeviceParams.Builder().build());
+ Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId());
+ testRevokePermissionNotifyListener(
+ deviceContext, virtualDevice.getPersistentDeviceId());
+ }
+
+ private void testRevokePermissionNotifyListener(
+ Context context, String expectedDeviceId) throws InterruptedException {
+ final PackageManager packageManager = context.getPackageManager();
+ TestOnPermissionsChangedListener permissionsChangedListener =
+ new TestOnPermissionsChangedListener(1);
+ runWithShellPermissionIdentity(() -> {
+ packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
+ mDefaultContext.getUser());
+ packageManager.addOnPermissionsChangeListener(permissionsChangedListener);
+ packageManager.revokeRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
+ mDefaultContext.getUser());
+ });
+ permissionsChangedListener.waitForPermissionChangedCallbacks();
+ runWithShellPermissionIdentity(() -> {
+ packageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
+ });
+
+ String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid);
+ assertThat(deviceId).isEqualTo(expectedDeviceId);
+ }
+
+ @Test
+ public void testDefaultDeviceUpdatePermissionFlagsNotifyListener() throws InterruptedException {
+ testUpdatePermissionFlagsNotifyListener(
+ mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public void testVirtualDeviceUpdatePermissionFlagsNotifyListener() throws InterruptedException {
+ VirtualDeviceManager.VirtualDevice virtualDevice =
+ mVirtualDeviceManager.createVirtualDevice(
+ mFakeAssociationRule.getAssociationInfo().getId(),
+ new VirtualDeviceParams.Builder().build());
+ Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId());
+ testUpdatePermissionFlagsNotifyListener(
+ deviceContext, virtualDevice.getPersistentDeviceId());
+ }
+
+ private void testUpdatePermissionFlagsNotifyListener(
+ Context context, String expectedDeviceId) throws InterruptedException {
+ TestOnPermissionsChangedListener permissionsChangedListener =
+ new TestOnPermissionsChangedListener(1);
+ final PackageManager packageManager = context.getPackageManager();
+ runWithShellPermissionIdentity(() -> {
+ packageManager.addOnPermissionsChangeListener(permissionsChangedListener);
+ int flag = PackageManager.FLAG_PERMISSION_USER_SET;
+ packageManager.updatePermissionFlags(PERMISSION_NAME, PACKAGE_NAME, flag, flag,
+ mDefaultContext.getUser());
+ });
+ permissionsChangedListener.waitForPermissionChangedCallbacks();
+ runWithShellPermissionIdentity(() -> {
+ packageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
+ });
+
+ String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid);
+ assertThat(deviceId).isEqualTo(expectedDeviceId);
+ }
+
+ private class TestOnPermissionsChangedListener
+ implements OnPermissionsChangedListener {
+ // map of uid and persistentDeviceID
+ private final Map<Integer, String> mUidDeviceIdsMap = new ConcurrentHashMap<>();
+ private final CountDownLatch mCountDownLatch;
+
+ TestOnPermissionsChangedListener(int expectedCallbackCount) {
+ mCountDownLatch = new CountDownLatch(expectedCallbackCount);
+ }
+
+ @Override
+ public void onPermissionsChanged(int uid) {
+ // ignored when we implement the new callback.
+ }
+
+ @Override
+ public void onPermissionsChanged(int uid, String deviceId) {
+ if (uid == mTestAppUid) {
+ mCountDownLatch.countDown();
+ mUidDeviceIdsMap.put(uid, deviceId);
+ }
+ }
+
+ String getNotifiedDeviceId(int uid) {
+ return mUidDeviceIdsMap.get(uid);
+ }
+
+ void waitForPermissionChangedCallbacks() throws InterruptedException {
+ mCountDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
+ assertThat(mCountDownLatch.getCount()).isEqualTo(0);
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PlatformPermissionGroupMappingTest.kt b/tests/cts/permission/src/android/permission/cts/PlatformPermissionGroupMappingTest.kt
new file mode 100644
index 000000000..2816bbb5a
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PlatformPermissionGroupMappingTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.os.Build
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+class PlatformPermissionGroupMappingTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context = instrumentation.context
+ private val packageManager = context.packageManager
+
+ @Test
+ fun platformPermissionHasPermissionGroup() {
+ val future = CompletableFuture<String>()
+ packageManager.getGroupOfPlatformPermission(
+ android.Manifest.permission.READ_CALENDAR,
+ context.mainExecutor
+ ) {
+ future.complete(it)
+ }
+ val permissionGroupName = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ assertThat(permissionGroupName).isEqualTo(android.Manifest.permission_group.CALENDAR)
+ }
+
+ @Test
+ fun platformPermissionGroupHasPermission() {
+ val future = CompletableFuture<List<String>>()
+ packageManager.getPlatformPermissionsForGroup(
+ android.Manifest.permission_group.CALENDAR,
+ context.mainExecutor
+ ) {
+ future.complete(it)
+ }
+ val permissionNames = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ assertThat(permissionNames).contains(android.Manifest.permission.READ_CALENDAR)
+ }
+
+ companion object {
+ private const val TIMEOUT_MILLIS = 15 * 1000L
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/PowerManagerServicePermissionTest.java b/tests/cts/permission/src/android/permission/cts/PowerManagerServicePermissionTest.java
new file mode 100644
index 000000000..b842cc0cf
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/PowerManagerServicePermissionTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permission.cts;
+
+import android.os.PowerManager;
+import android.test.AndroidTestCase;
+
+import java.time.Duration;
+
+public class PowerManagerServicePermissionTest extends AndroidTestCase {
+
+ public void testSetBatterySaver_requiresPermissions() {
+ PowerManager manager = getContext().getSystemService(PowerManager.class);
+ boolean batterySaverOn = manager.isPowerSaveMode();
+
+ try {
+ manager.setPowerSaveModeEnabled(!batterySaverOn);
+ fail("Toggling battery saver requires POWER_SAVER or DEVICE_POWER permission");
+ } catch (SecurityException e) {
+ // Expected Exception
+ }
+ }
+
+ public void testSetDynamicPowerSavings_requiresPermissions() {
+ try {
+ PowerManager manager = getContext().getSystemService(PowerManager.class);
+ manager.setDynamicPowerSaveHint(true, 0);
+ fail("Updating the dynamic power savings state requires the POWER_SAVER permission");
+ } catch (SecurityException e) {
+ // Expected Exception
+ }
+ }
+
+ public void testSetBatteryDischargePrediction_requiresPermissions() {
+ try {
+ PowerManager manager = getContext().getSystemService(PowerManager.class);
+ manager.setBatteryDischargePrediction(Duration.ofMillis(1000), false);
+ fail("Updating the discharge prediction requires the DEVICE_POWER"
+ + " or BATTERY_PREDICTION permission");
+ } catch (SecurityException e) {
+ // Expected Exception
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/ProviderPermissionTest.java b/tests/cts/permission/src/android/permission/cts/ProviderPermissionTest.java
new file mode 100644
index 000000000..83c2ffaee
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/ProviderPermissionTest.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
+
+import android.app.UiAutomation;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AppModeInstant;
+import android.provider.CallLog;
+import android.provider.Contacts;
+import android.provider.ContactsContract;
+import android.provider.Settings;
+import android.provider.Telephony;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Tests Permissions related to reading from and writing to providers
+ */
+@MediumTest
+public class ProviderPermissionTest extends AndroidTestCase {
+
+ private static final String TAG = ProviderPermissionTest.class.getSimpleName();
+
+ private static final List<Uri> CONTACT_URIS = List.of(
+ Contacts.People.CONTENT_URI, // Deprecated.
+ ContactsContract.Contacts.CONTENT_FILTER_URI,
+ ContactsContract.Contacts.CONTENT_GROUP_URI,
+ ContactsContract.Contacts.CONTENT_LOOKUP_URI,
+ ContactsContract.CommonDataKinds.Email.CONTENT_URI,
+ ContactsContract.CommonDataKinds.Email.CONTENT_FILTER_URI,
+ ContactsContract.Directory.CONTENT_URI,
+ ContactsContract.Directory.ENTERPRISE_CONTENT_URI,
+ ContactsContract.Profile.CONTENT_URI);
+
+ /**
+ * Verify that reading contacts requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#READ_CONTACTS}
+ */
+ public void testReadContacts() {
+ for (Uri uri : CONTACT_URIS) {
+ Log.d(TAG, "Checking contacts URI " + uri);
+ assertReadingContentUriRequiresPermission(uri,
+ android.Manifest.permission.READ_CONTACTS);
+ }
+ }
+
+ /**
+ * Verify that writing contacts requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#WRITE_CONTACTS}
+ */
+ public void testWriteContacts() {
+ assertWritingContentUriRequiresPermission(Contacts.People.CONTENT_URI,
+ android.Manifest.permission.WRITE_CONTACTS);
+ }
+
+ /**
+ * Verify that reading call logs requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#READ_CALL_LOG}
+ */
+ @AppModeFull
+ public void testReadCallLog() {
+ assertReadingContentUriRequiresPermission(CallLog.CONTENT_URI,
+ android.Manifest.permission.READ_CALL_LOG);
+ }
+
+ /**
+ * Verify that writing call logs requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#WRITE_CALL_LOG}
+ */
+ @AppModeFull
+ public void testWriteCallLog() {
+ assertWritingContentUriRequiresPermission(CallLog.CONTENT_URI,
+ android.Manifest.permission.WRITE_CALL_LOG);
+ }
+
+ /**
+ * Verify that reading from call-log (a content provider that is not accessible to instant apps)
+ * returns null
+ */
+ @AppModeInstant
+ public void testReadCallLogInstant() {
+ assertNull(getContext().getContentResolver().query(CallLog.CONTENT_URI, null, null, null,
+ null));
+ }
+
+ /**
+ * Verify that writing to call-log (a content provider that is not accessible to instant apps)
+ * yields an IAE.
+ */
+ @AppModeInstant
+ public void testWriteCallLogInstant() {
+ try {
+ getContext().getContentResolver().insert(CallLog.CONTENT_URI, new ContentValues());
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ /**
+ * Verify that reading already received SMS messages requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#READ_SMS}
+ *
+ * <p>Note: The WRITE_SMS permission has been removed.
+ */
+ @AppModeFull
+ public void testReadSms() {
+ if (!mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+
+ assertReadingContentUriRequiresPermission(Telephony.Sms.CONTENT_URI,
+ android.Manifest.permission.READ_SMS);
+ }
+
+ /**
+ * Verify that reading from 'sms' (a content provider that is not accessible to instant apps)
+ * returns null
+ */
+ @AppModeInstant
+ public void testReadSmsInstant() {
+ if (!mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+
+ assertNull(getContext().getContentResolver().query(Telephony.Sms.CONTENT_URI, null, null,
+ null, null));
+ }
+
+ /**
+ * Verify that write to settings requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#WRITE_SETTINGS}
+ */
+ public void testWriteSettings() {
+ final String permission = android.Manifest.permission.WRITE_SETTINGS;
+ ContentValues value = new ContentValues();
+ value.put(Settings.System.NAME, "name");
+ value.put(Settings.System.VALUE, "value_insert");
+
+ try {
+ getContext().getContentResolver().insert(Settings.System.CONTENT_URI, value);
+ fail("expected SecurityException requiring " + permission);
+ } catch (SecurityException expected) {
+ assertNotNull("security exception's error message.", expected.getMessage());
+ assertTrue("error message should contain \"" + permission + "\". Got: \""
+ + expected.getMessage() + "\".",
+ expected.getMessage().contains(permission));
+ }
+ }
+
+ /**
+ * Verify that the {@link android.Manifest.permission#MANAGE_DOCUMENTS}
+ * permission is only held by up to one package: whoever handles the
+ * {@link android.content.Intent#ACTION_OPEN_DOCUMENT} intent, if any.
+ * <p>
+ * No other apps should <em>ever</em> attempt to acquire this permission,
+ * since it would give those apps extremely broad access to all storage
+ * providers on the device without user involvement in the arbitration
+ * process. Apps should instead always rely on Uri permission grants for
+ * access, using
+ * {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} and related
+ * APIs.
+ */
+ public void testManageDocuments() {
+ final PackageManager pm = getContext().getPackageManager();
+
+ final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ final ResolveInfo ri = pm.resolveActivity(intent, 0);
+
+ if (ri != null) {
+ final String validPkg = ri.activityInfo.packageName;
+
+ final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
+ android.Manifest.permission.MANAGE_DOCUMENTS
+ }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ for (PackageInfo pi : holding) {
+ if (!Objects.equals(pi.packageName, validPkg)) {
+ fail("Exactly one package (must be " + validPkg
+ + ") can request the MANAGE_DOCUMENTS permission; found package "
+ + pi.packageName + " which must be revoked for security reasons");
+ }
+ }
+ }
+ }
+
+ /**
+ * The {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission is
+ * a very powerful permission that grants raw storage access to all devices,
+ * and as such it's only appropriate to be granted to the media stack.
+ * <p>
+ * CDD now requires that all apps requesting this permission also hold the
+ * "Storage" runtime permission, to give users visibility into the
+ * capabilities of each app, and control over those capabilities.
+ * <p>
+ * If the end user revokes the "Storage" permission from an app, but that
+ * app still has raw access to storage via {@code WRITE_MEDIA_STORAGE}, that
+ * would be a CDD violation and a privacy incident.
+ */
+ public void testWriteMediaStorage() throws Exception {
+ final UiAutomation ui = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ final PackageManager pm = getContext().getPackageManager();
+ final UserHandle userHandle = getContext().getUser();
+ final List<PackageInfo> pkgs = pm.getInstalledPackages(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS);
+ for (PackageInfo pkg : pkgs) {
+ final int appUid = userHandle.getAppId(pkg.applicationInfo.uid);
+ final boolean isSystem = appUid == android.os.Process.SYSTEM_UID;
+ final boolean hasFrontDoor = pm.getLaunchIntentForPackage(pkg.packageName) != null;
+ final boolean grantedMedia = pm.checkPermission(WRITE_MEDIA_STORAGE,
+ pkg.packageName) == PackageManager.PERMISSION_GRANTED;
+
+ if (!isSystem && hasFrontDoor && grantedMedia) {
+ final boolean requestsStorage = contains(pkg.requestedPermissions,
+ MANAGE_EXTERNAL_STORAGE);
+ if (!requestsStorage) {
+ fail("Found " + pkg.packageName + " holding WRITE_MEDIA_STORAGE permission "
+ + "without also requesting MANAGE_EXTERNAL_STORAGE; these permissions "
+ + "must be requested together");
+ }
+
+ final boolean grantedStorage = pm.checkPermission(MANAGE_EXTERNAL_STORAGE,
+ pkg.packageName) == PackageManager.PERMISSION_GRANTED;
+ if (grantedStorage) {
+ final int flags;
+ ui.adoptShellPermissionIdentity("android.permission.GET_RUNTIME_PERMISSIONS");
+ try {
+ flags = pm.getPermissionFlags(MANAGE_EXTERNAL_STORAGE, pkg.packageName,
+ android.os.Process.myUserHandle());
+ } finally {
+ ui.dropShellPermissionIdentity();
+ }
+
+ final boolean isFixed = (flags & (PackageManager.FLAG_PERMISSION_USER_FIXED
+ | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+ | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0;
+ if (isFixed) {
+ fail("Found " + pkg.packageName + " holding MANAGE_EXTERNAL_STORAGE in a "
+ + "fixed state; this permission must be revokable by the user");
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean contains(String[] haystack, String needle) {
+ if (haystack != null) {
+ for (String test : haystack) {
+ if (Objects.equals(test, needle)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/RebootPermissionTest.java b/tests/cts/permission/src/android/permission/cts/RebootPermissionTest.java
new file mode 100644
index 000000000..13f17dce8
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/RebootPermissionTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.Intent;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify that rebooting requires Permission.
+ */
+public class RebootPermissionTest extends AndroidTestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /**
+ * Verify that rebooting by sending a broadcast Intent requires Permission.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#REBOOT}.
+ */
+ @SmallTest
+ public void testBroadcastReboot() {
+ try {
+ mContext.sendBroadcast(new Intent(Intent.ACTION_REBOOT));
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+}
diff --git a/tests/cts/permission/src/android/permission/cts/RemovePermissionTest.java b/tests/cts/permission/src/android/permission/cts/RemovePermissionTest.java
new file mode 100644
index 000000000..915918f71
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/RemovePermissionTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+@AppModeFull(reason = "Instant apps cannot read state of other packages.")
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+public class RemovePermissionTest extends StsExtraBusinessLogicTestCase {
+ private static final String APP_PKG_NAME_BASE =
+ "android.permission.cts.revokepermissionwhenremoved";
+ private static final String ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".AdversarialPermissionDefinerApp";
+ private static final String VICTIM_PERMISSION_DEFINER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".VictimPermissionDefinerApp";
+ private static final String ADVERSARIAL_PERMISSION_USER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".userapp";
+ private static final String RUNTIME_PERMISSION_USER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".runtimepermissionuserapp";
+ private static final String RUNTIME_PERMISSION_DEFINER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".runtimepermissiondefinerapp";
+ private static final String INSTALL_PERMISSION_USER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".installpermissionuserapp";
+ private static final String INSTALL_PERMISSION_DEFINER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".installpermissiondefinerapp";
+ private static final String INSTALL_PERMISSION_ESCALATOR_PKG_NAME =
+ APP_PKG_NAME_BASE + ".installpermissionescalatorapp";
+
+ private static final String TEST_PERMISSION =
+ "android.permission.cts.revokepermissionwhenremoved.TestPermission";
+ private static final String TEST_RUNTIME_PERMISSION =
+ APP_PKG_NAME_BASE + ".TestRuntimePermission";
+ private static final String TEST_INSTALL_PERMISSION =
+ APP_PKG_NAME_BASE + ".TestInstallPermission";
+
+ private static final String ADVERSARIAL_PERMISSION_DEFINER_APK_NAME =
+ "CtsAdversarialPermissionDefinerApp";
+ private static final String ADVERSARIAL_PERMISSION_USER_APK_NAME =
+ "CtsAdversarialPermissionUserApp";
+ private static final String VICTIM_PERMISSION_DEFINER_APK_NAME =
+ "CtsVictimPermissionDefinerApp";
+ private static final String RUNTIME_PERMISSION_DEFINER_APK_NAME =
+ "CtsRuntimePermissionDefinerApp";
+ private static final String RUNTIME_PERMISSION_USER_APK_NAME =
+ "CtsRuntimePermissionUserApp";
+ private static final String INSTALL_PERMISSION_DEFINER_APK_NAME =
+ "CtsInstallPermissionDefinerApp";
+ private static final String INSTALL_PERMISSION_USER_APK_NAME =
+ "CtsInstallPermissionUserApp";
+ private static final String INSTALL_PERMISSION_ESCALATOR_APK_NAME =
+ "CtsInstallPermissionEscalatorApp";
+
+ private Context mContext;
+ private Instrumentation mInstrumentation;
+
+ @Before
+ public void setContextAndInstrumentation() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ }
+
+ @Before
+ public void wakeUpScreen() {
+ SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP");
+ }
+
+ @After
+ public void cleanUpTestApps() throws Exception {
+ uninstallApp(ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME, true);
+ uninstallApp(ADVERSARIAL_PERMISSION_USER_PKG_NAME, true);
+ uninstallApp(VICTIM_PERMISSION_DEFINER_PKG_NAME, true);
+ uninstallApp(RUNTIME_PERMISSION_DEFINER_PKG_NAME, true);
+ uninstallApp(RUNTIME_PERMISSION_USER_PKG_NAME, true);
+ uninstallApp(INSTALL_PERMISSION_USER_PKG_NAME, true);
+ uninstallApp(INSTALL_PERMISSION_DEFINER_PKG_NAME, true);
+ uninstallApp(INSTALL_PERMISSION_ESCALATOR_PKG_NAME, true);
+ Thread.sleep(5000);
+ }
+
+ private boolean permissionGranted(String pkgName, String permName)
+ throws PackageManager.NameNotFoundException {
+ PackageInfo appInfo = mContext.getPackageManager().getPackageInfo(pkgName,
+ GET_PERMISSIONS);
+
+ for (int i = 0; i < appInfo.requestedPermissions.length; i++) {
+ if (appInfo.requestedPermissions[i].equals(permName)
+ && ((appInfo.requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED)
+ != 0)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void installApp(String apk) throws InterruptedException {
+ String installResult = SystemUtil.runShellCommandOrThrow(
+ "pm install -r -d /data/local/tmp/cts-permission/" + apk + ".apk");
+ assertEquals("Success", installResult.trim());
+ Thread.sleep(5000);
+ }
+
+ private void uninstallApp(String pkg) throws InterruptedException {
+ uninstallApp(pkg, false);
+ }
+
+ private void uninstallApp(String pkg, boolean cleanUp) throws InterruptedException {
+ String uninstallResult = SystemUtil.runShellCommand("pm uninstall " + pkg);
+ if (!cleanUp) {
+ assertEquals("Success", uninstallResult.trim());
+ Thread.sleep(5000);
+ }
+ }
+
+ private void grantPermission(String pkg, String permission) {
+ mInstrumentation.getUiAutomation().grantRuntimePermission(
+ pkg, permission);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 67319274)
+ public void runtimePermissionShouldBeRevokedIfRemoved() throws Throwable {
+ installApp(ADVERSARIAL_PERMISSION_DEFINER_APK_NAME);
+ installApp(ADVERSARIAL_PERMISSION_USER_APK_NAME);
+
+ grantPermission(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION);
+ assertTrue(permissionGranted(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION));
+
+ // Uninstall app which defines a permission with the same name as in victim app.
+ // Install the victim app.
+ uninstallApp(ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME);
+ installApp(VICTIM_PERMISSION_DEFINER_APK_NAME);
+ assertFalse(permissionGranted(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION));
+ }
+
+ @Test
+ public void runtimePermissionShouldRemainGrantedAfterAppUpdate() throws Throwable {
+ installApp(RUNTIME_PERMISSION_DEFINER_APK_NAME);
+ installApp(RUNTIME_PERMISSION_USER_APK_NAME);
+
+ grantPermission(RUNTIME_PERMISSION_USER_PKG_NAME, TEST_RUNTIME_PERMISSION);
+ assertTrue(permissionGranted(RUNTIME_PERMISSION_USER_PKG_NAME, TEST_RUNTIME_PERMISSION));
+
+ // Install app which defines a permission. This is similar to update the app
+ // operation
+ installApp(RUNTIME_PERMISSION_DEFINER_APK_NAME);
+ assertTrue(permissionGranted(RUNTIME_PERMISSION_USER_PKG_NAME, TEST_RUNTIME_PERMISSION));
+ }
+
+ @Test
+ public void runtimePermissionDependencyTest() throws Throwable {
+ installApp(ADVERSARIAL_PERMISSION_USER_APK_NAME);
+ // Should fail to grant permission because its definer is not installed yet
+ try {
+ grantPermission(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION);
+ fail("Should have thrown security exception above");
+ } catch (SecurityException expected) {
+ }
+ assertFalse(permissionGranted(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION));
+ // Now install the permission definer; should be able to grant permission to user package
+ installApp(ADVERSARIAL_PERMISSION_DEFINER_APK_NAME);
+ grantPermission(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION);
+ assertTrue(permissionGranted(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION));
+ // Now uninstall the permission definer; the user packages' permission should be revoked
+ uninstallApp(ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME);
+ assertFalse(permissionGranted(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION));
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 155648771)
+ public void installPermissionShouldBeRevokedIfRemoved() throws Throwable {
+ installApp(INSTALL_PERMISSION_DEFINER_APK_NAME);
+ installApp(INSTALL_PERMISSION_USER_APK_NAME);
+ assertTrue(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+
+ // Uninstall the app which defines the install permission, and install another app
+ // redefining it as a runtime permission.
+ uninstallApp(INSTALL_PERMISSION_DEFINER_PKG_NAME);
+ installApp(INSTALL_PERMISSION_ESCALATOR_APK_NAME);
+ assertFalse(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+ }
+
+ @Test
+ public void installPermissionShouldRemainGrantedAfterAppUpdate() throws Throwable {
+ installApp(INSTALL_PERMISSION_DEFINER_APK_NAME);
+ installApp(INSTALL_PERMISSION_USER_APK_NAME);
+ assertTrue(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+
+ // Install the app which defines the install permission again, similar to updating the app.
+ installApp(INSTALL_PERMISSION_DEFINER_APK_NAME);
+ assertTrue(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+ }
+
+ @Test
+ public void installPermissionDependencyTest() throws Throwable {
+ installApp(INSTALL_PERMISSION_USER_APK_NAME);
+ // Should not have the permission auto-granted
+ assertFalse(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+
+ // Now install the permission definer; user package should have the permission auto granted
+ installApp(INSTALL_PERMISSION_DEFINER_APK_NAME);
+ installApp(INSTALL_PERMISSION_USER_APK_NAME);
+ assertTrue(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+
+ // Now uninstall the permission definer; the user package's permission should be revoked
+ uninstallApp(INSTALL_PERMISSION_DEFINER_PKG_NAME);
+ assertFalse(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/RevokePermissionTest.kt b/tests/cts/permission/src/android/permission/cts/RevokePermissionTest.kt
new file mode 100644
index 000000000..05235e141
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/RevokePermissionTest.kt
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.Manifest.permission.CAMERA
+import android.Manifest.permission.READ_CALENDAR
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
+import android.os.Process
+import android.platform.test.annotations.AppModeFull
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+
+class RevokePermissionTest {
+
+ private val APP_PKG_NAME = "android.permission.cts.appthatrequestcustompermission"
+ private val APK =
+ "/data/local/tmp/cts-permission/" +
+ "CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk"
+
+ @Before
+ fun installApp() {
+ runShellCommand("pm install -r -g $APK")
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps can't revoke permissions.")
+ fun testRevokePermission() {
+ testRevoke(packageName = APP_PKG_NAME, permission = READ_CALENDAR, isGranted = true)
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps can't revoke permissions.")
+ fun testRevokePermissionNotRequested() {
+ testRevoke(
+ packageName = APP_PKG_NAME,
+ permission = CAMERA,
+ throwableType = SecurityException::class.java,
+ throwableMessages =
+ listOf(
+ "has not requested permission",
+ "Permission $CAMERA isn't requested by package $APP_PKG_NAME"
+ )
+ )
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps can't revoke permissions.")
+ fun testRevokeFakePermission() {
+ val fakePermissionName = "FAKE_PERMISSION"
+ testRevoke(
+ packageName = APP_PKG_NAME,
+ permission = fakePermissionName,
+ throwableType = java.lang.IllegalArgumentException::class.java,
+ throwableMessages =
+ listOf(
+ "Unknown permission: $fakePermissionName",
+ "Unknown permission $fakePermissionName"
+ )
+ )
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps can't revoke permissions.")
+ fun testRevokeFakePackage() {
+ val fakePackageName = "fake.package.name.which.should.not.exist"
+ assertPackageNotInstalled(fakePackageName)
+ testRevoke(packageName = fakePackageName, permission = READ_CALENDAR)
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps can't revoke permissions.")
+ fun testRevokePermissionWithReason() {
+ testRevoke(
+ packageName = APP_PKG_NAME,
+ permission = READ_CALENDAR,
+ reason = "test reason",
+ isGranted = true
+ )
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps can't revoke permissions.")
+ fun testRevokePermissionNotRequestedWithReason() {
+ testRevoke(
+ packageName = APP_PKG_NAME,
+ permission = CAMERA,
+ reason = "test reason",
+ throwableType = SecurityException::class.java,
+ throwableMessages =
+ listOf(
+ "has not requested permission",
+ "Permission $CAMERA isn't requested by package $APP_PKG_NAME"
+ )
+ )
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps can't revoke permissions.")
+ fun testRevokeFakePermissionWithReason() {
+ val fakePermissionName = "FAKE_PERMISSION"
+ testRevoke(
+ packageName = APP_PKG_NAME,
+ permission = fakePermissionName,
+ reason = "test reason",
+ throwableType = java.lang.IllegalArgumentException::class.java,
+ throwableMessages =
+ listOf(
+ "Unknown permission: $fakePermissionName",
+ "Unknown permission $fakePermissionName"
+ )
+ )
+ }
+
+ @Test
+ @AppModeFull(reason = "Instant apps can't revoke permissions.")
+ fun testRevokeFakePackageWithReason() {
+ val fakePackageName = "fake.package.name.which.should.not.exist"
+ assertPackageNotInstalled(fakePackageName)
+ testRevoke(
+ packageName = fakePackageName,
+ permission = READ_CALENDAR,
+ reason = "test reason"
+ )
+ }
+
+ @After
+ fun uninstallApp() {
+ runShellCommand("pm uninstall $APP_PKG_NAME")
+ }
+
+ private fun testRevoke(
+ packageName: String,
+ permission: String,
+ reason: String? = null,
+ isGranted: Boolean = false,
+ throwableType: Class<*>? = null,
+ throwableMessages: List<String> = listOf("")
+ ) {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+ val pm = context.packageManager
+
+ if (isGranted) {
+ assertEquals(PERMISSION_GRANTED, pm.checkPermission(READ_CALENDAR, APP_PKG_NAME))
+ }
+
+ runWithShellPermissionIdentity {
+ if (throwableType == null) {
+ if (reason == null) {
+ pm.revokeRuntimePermission(packageName, permission, Process.myUserHandle())
+ } else {
+ pm.revokeRuntimePermission(
+ packageName,
+ permission,
+ Process.myUserHandle(),
+ reason
+ )
+ }
+ } else {
+ try {
+ if (reason == null) {
+ pm.revokeRuntimePermission(packageName, permission, Process.myUserHandle())
+ } else {
+ pm.revokeRuntimePermission(
+ packageName,
+ permission,
+ Process.myUserHandle(),
+ reason
+ )
+ }
+ } catch (t: Throwable) {
+ if (
+ t::class.java.name == throwableType.name &&
+ throwableMessages.any { t.message!!.contains(it) }
+ ) {
+ return@runWithShellPermissionIdentity
+ }
+ throw RuntimeException("Unexpected throwable", t)
+ }
+ throw RuntimeException("revokeRuntimePermission expected to throw.")
+ }
+ }
+ }
+
+ private fun assertPackageNotInstalled(packageName: String) {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+ val pm = context.packageManager
+ try {
+ pm.getPackageInfo(packageName, 0)
+ throw RuntimeException("$packageName exists on this device")
+ } catch (e: PackageManager.NameNotFoundException) {
+ // Expected
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/RevokeSawPermissionTest.kt b/tests/cts/permission/src/android/permission/cts/RevokeSawPermissionTest.kt
new file mode 100644
index 000000000..17327c6d4
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/RevokeSawPermissionTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.content.pm.PackageManager
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.After
+import org.junit.Assert
+import org.junit.Test
+
+private val APP_PKG_NAME = "android.permission.cts.usesystemalertwindowpermission"
+private val APK_22 = "/data/local/tmp/cts-permission/" + "CtsAppThatRequestsSystemAlertWindow22.apk"
+private val APK_23 = "/data/local/tmp/cts-permission/" + "CtsAppThatRequestsSystemAlertWindow23.apk"
+
+class RevokeSawPermissionTest {
+
+ fun installApp(apk: String) {
+ PermissionUtils.install(apk)
+ }
+
+ @After
+ fun uninstallApp() {
+ PermissionUtils.uninstallApp(APP_PKG_NAME)
+ }
+
+ @AsbSecurityTest(cveBugId = [221040577L])
+ @Test
+ fun testPre23AppsWithSystemAlertWindowGetDeniedOnUpgrade() {
+ installApp(APK_22)
+ assertAppHasPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, true)
+ installApp(APK_23)
+ assertAppHasPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, false)
+ }
+
+ private fun assertAppHasPermission(permissionName: String, expectPermission: Boolean) {
+ Assert.assertEquals(
+ if (expectPermission) {
+ PackageManager.PERMISSION_GRANTED
+ } else {
+ PackageManager.PERMISSION_DENIED
+ },
+ InstrumentationRegistry.getInstrumentation()
+ .getTargetContext()
+ .packageManager
+ .checkPermission(permissionName, APP_PKG_NAME)
+ )
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/RevokeSelfPermissionTest.java b/tests/cts/permission/src/android/permission/cts/RevokeSelfPermissionTest.java
new file mode 100644
index 000000000..674fa2d12
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/RevokeSelfPermissionTest.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.CAMERA;
+import static android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.permission.cts.PermissionUtils.getPermissionFlags;
+import static android.permission.cts.PermissionUtils.grantPermission;
+import static android.permission.cts.PermissionUtils.setPermissionFlags;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.os.Build;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.DeviceConfig;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@AppModeFull(reason = "Null permission info in instant mode")
+public class RevokeSelfPermissionTest {
+ private static final String APP_PKG_NAME =
+ "android.permission.cts.apptotestrevokeselfpermission";
+ private static final String APK =
+ "/data/local/tmp/cts-permission/CtsAppToTestRevokeSelfPermission.apk";
+ private static final long ONE_TIME_TIMEOUT_MILLIS = 500;
+ private static final long ONE_TIME_TIMER_UPPER_GRACE_PERIOD = 5000;
+
+ private final Instrumentation mInstrumentation =
+ InstrumentationRegistry.getInstrumentation();
+ private final Context mContext = mInstrumentation.getTargetContext();
+ private final ActivityManager mActivityManager =
+ mContext.getSystemService(ActivityManager.class);
+ private final UiDevice mUiDevice = UiDevice.getInstance(mInstrumentation);
+ private String mOldOneTimePermissionTimeoutValue;
+ private String mOldScreenOffTimeoutValue;
+ private String mOldSleepTimeoutValue;
+
+ @Before
+ public void wakeUpScreen() {
+ SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP");
+ SystemUtil.runShellCommand("input keyevent 82");
+ mOldScreenOffTimeoutValue = SystemUtil.runShellCommand(
+ "settings get system screen_off_timeout");
+ mOldSleepTimeoutValue = SystemUtil.runShellCommand("settings get secure sleep_timeout");
+ SystemUtil.runShellCommand("settings put system screen_off_timeout -1");
+ SystemUtil.runShellCommand("settings put secure sleep_timeout -1");
+ }
+
+ @Before
+ public void prepareDeviceForOneTime() {
+ runWithShellPermissionIdentity(() -> {
+ mOldOneTimePermissionTimeoutValue = DeviceConfig.getProperty("permissions",
+ "one_time_permissions_timeout_millis");
+ DeviceConfig.setProperty("permissions", "one_time_permissions_timeout_millis",
+ Long.toString(ONE_TIME_TIMEOUT_MILLIS), false);
+ });
+ }
+
+ @After
+ public void uninstallApp() {
+ runShellCommand("pm uninstall " + APP_PKG_NAME);
+ }
+
+ @After
+ public void restoreDeviceForOneTime() {
+ runWithShellPermissionIdentity(() -> {
+ DeviceConfig.setProperty("permissions", "one_time_permissions_timeout_millis",
+ mOldOneTimePermissionTimeoutValue, false);
+ });
+ SystemUtil.runShellCommand("settings put system screen_off_timeout "
+ + mOldScreenOffTimeoutValue);
+ SystemUtil.runShellCommand("settings put secure sleep_timeout " + mOldSleepTimeoutValue);
+ }
+
+ @Test
+ public void testMultiplePermissions() throws Throwable {
+ // Trying to revoke multiple permissions including some from the same permission group
+ // should work.
+ installApp();
+ String[] permissions = new String[] {ACCESS_COARSE_LOCATION, ACCESS_BACKGROUND_LOCATION,
+ CAMERA};
+ for (String permission : permissions) {
+ grantPermission(APP_PKG_NAME, permission);
+ assertGranted(ONE_TIME_TIMER_UPPER_GRACE_PERIOD, permission);
+ }
+ revokePermissions(permissions);
+ placeAppInBackground();
+ for (String permission : permissions) {
+ assertDenied(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ permission);
+ }
+ uninstallApp();
+ }
+
+ @Test
+ public void testNormalPermission() throws Throwable {
+ // Trying to revoke a normal (non-runtime) permission should not actually revoke it.
+ installApp();
+ revokePermission(HIGH_SAMPLING_RATE_SENSORS);
+ placeAppInBackground();
+ try {
+ waitUntilPermissionRevoked(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ HIGH_SAMPLING_RATE_SENSORS);
+ fail("android.permission.HIGH_SAMPLING_RATE_SENSORS was revoked");
+ } catch (Throwable expected) {
+ assertEquals(HIGH_SAMPLING_RATE_SENSORS + " not revoked",
+ expected.getMessage());
+ }
+ uninstallApp();
+ }
+
+ @Test
+ public void testKillTriggersRevocation() throws Throwable {
+ // Killing the process should start the revocation right away
+ installApp();
+ grantPermission(APP_PKG_NAME, ACCESS_FINE_LOCATION);
+ assertGranted(ONE_TIME_TIMER_UPPER_GRACE_PERIOD, ACCESS_FINE_LOCATION);
+ revokePermission(ACCESS_FINE_LOCATION);
+ killApp();
+ assertDenied(ONE_TIME_TIMER_UPPER_GRACE_PERIOD, ACCESS_FINE_LOCATION);
+ uninstallApp();
+ }
+
+ @Test
+ public void testNoRevocationWhileForeground() throws Throwable {
+ // Even after calling revokeSelfPermissionOnKill, the permission should stay granted while
+ // the package is in the foreground.
+ installApp();
+ grantPermission(APP_PKG_NAME, ACCESS_FINE_LOCATION);
+ assertGranted(ONE_TIME_TIMER_UPPER_GRACE_PERIOD, ACCESS_FINE_LOCATION);
+ revokePermission(ACCESS_FINE_LOCATION);
+ keepAppInForeground(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD);
+ try {
+ waitUntilPermissionRevoked(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_FINE_LOCATION);
+ fail("android.permission.ACCESS_FINE_LOCATION was revoked");
+ } catch (Throwable expected) {
+ assertEquals(ACCESS_FINE_LOCATION + " not revoked",
+ expected.getMessage());
+ }
+ uninstallApp();
+ }
+
+ @Test
+ public void testRevokeLocationPermission() throws Throwable {
+ // Test behavior specific to location group: revoking fine location should not revoke coarse
+ // location, and background location should not be revoked as long as a foreground
+ // permission is still granted
+ installApp();
+ grantPermission(APP_PKG_NAME, ACCESS_COARSE_LOCATION);
+ assertGranted(ONE_TIME_TIMER_UPPER_GRACE_PERIOD, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG_NAME, ACCESS_FINE_LOCATION);
+ assertGranted(ONE_TIME_TIMER_UPPER_GRACE_PERIOD, ACCESS_FINE_LOCATION);
+ grantPermission(APP_PKG_NAME, ACCESS_BACKGROUND_LOCATION);
+ assertGranted(ONE_TIME_TIMER_UPPER_GRACE_PERIOD, ACCESS_BACKGROUND_LOCATION);
+ revokePermission(ACCESS_BACKGROUND_LOCATION);
+ killApp();
+ assertDenied(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_BACKGROUND_LOCATION);
+ assertGranted(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_COARSE_LOCATION);
+ assertGranted(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_FINE_LOCATION);
+ grantPermission(APP_PKG_NAME, ACCESS_BACKGROUND_LOCATION);
+ setPermissionFlags(APP_PKG_NAME, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_ONE_TIME, 0);
+ assertGranted(ONE_TIME_TIMER_UPPER_GRACE_PERIOD, ACCESS_BACKGROUND_LOCATION);
+ revokePermission(ACCESS_FINE_LOCATION);
+ killApp();
+ assertDenied(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_FINE_LOCATION);
+ assertGranted(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_COARSE_LOCATION);
+ assertGranted(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_BACKGROUND_LOCATION);
+ revokePermission(ACCESS_COARSE_LOCATION);
+ killApp();
+ assertDenied(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_COARSE_LOCATION);
+ assertDenied(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_BACKGROUND_LOCATION);
+ uninstallApp();
+ }
+
+ @Test
+ public void testNoRepromptWhenUserFixed() throws Throwable {
+ // If a permission has been USER_FIXED to not granted, then revoking the permission group
+ // should leave the USER_FIXED flag.
+ installApp();
+ grantPermission(APP_PKG_NAME, ACCESS_FINE_LOCATION);
+ setPermissionFlags(APP_PKG_NAME, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_USER_FIXED);
+ revokePermission(ACCESS_FINE_LOCATION);
+ placeAppInBackground();
+ assertDenied(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD,
+ ACCESS_FINE_LOCATION);
+ int flags = getPermissionFlags(APP_PKG_NAME, ACCESS_BACKGROUND_LOCATION);
+ assertEquals(FLAG_PERMISSION_USER_FIXED, flags & FLAG_PERMISSION_USER_FIXED);
+ uninstallApp();
+ }
+
+
+ private void installApp() {
+ runShellCommandOrThrow("pm install -r " + APK);
+ }
+
+ private void keepAppInForeground(long timeoutMillis) {
+ new Thread(() -> {
+ long start = System.currentTimeMillis();
+ while (System.currentTimeMillis() < start + timeoutMillis) {
+ runWithShellPermissionIdentity(() -> {
+ if (mActivityManager.getPackageImportance(APP_PKG_NAME)
+ > IMPORTANCE_FOREGROUND) {
+ runShellCommand("am start-activity -W -n " + APP_PKG_NAME
+ + "/.RevokePermission");
+ }
+ });
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+ }).start();
+ }
+
+ private void placeAppInBackground() {
+ boolean[] hasExited = {false};
+ try {
+ new Thread(() -> {
+ while (!hasExited[0]) {
+ mUiDevice.pressHome();
+ mUiDevice.pressBack();
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }).start();
+ eventually(() -> {
+ runWithShellPermissionIdentity(() -> {
+ if (mActivityManager.getPackageImportance(APP_PKG_NAME)
+ <= IMPORTANCE_FOREGROUND) {
+ throw new AssertionError("Unable to exit application");
+ }
+ });
+ });
+ } finally {
+ hasExited[0] = true;
+ }
+ }
+
+ /**
+ * Start the app. The app will revoke the permission.
+ */
+ private void revokePermission(String permName) {
+ revokePermissions(new String[] { permName });
+ }
+
+ private void revokePermissions(String[] permissions) {
+ runShellCommand("am start-activity -W -n " + APP_PKG_NAME + "/.RevokePermission"
+ + " --esa permissions " + String.join(",", permissions));
+ PackageManager pkgMgr = mContext.getPackageManager();
+ eventually(() -> runWithShellPermissionIdentity(() -> {
+ for (int i = 0; i < permissions.length; i++) {
+ if ((pkgMgr.getPermissionInfo(permissions[i], 0).getProtection()
+ & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
+ int permissionFlags = pkgMgr.getPermissionFlags(permissions[i], APP_PKG_NAME,
+ Process.myUserHandle());
+ Assert.assertTrue((permissionFlags & FLAG_PERMISSION_ONE_TIME) != 0);
+ }
+ }
+ }));
+ }
+
+ private void killApp() {
+ runShellCommand("am force-stop " + APP_PKG_NAME);
+ }
+
+ private void assertGrantedState(String s, String permissionName, int permissionGranted,
+ long timeoutMillis) {
+ eventually(() -> Assert.assertEquals(s, permissionGranted,
+ mContext.getPackageManager().checkPermission(permissionName, APP_PKG_NAME)),
+ timeoutMillis);
+ }
+
+ private void assertGranted(long timeoutMillis, String permissionName) {
+ assertGrantedState("Permission was never granted", permissionName,
+ PackageManager.PERMISSION_GRANTED, timeoutMillis);
+ }
+
+ private void assertDenied(long timeoutMillis, String permissionName) {
+ assertGrantedState("Permission was never revoked", permissionName,
+ PackageManager.PERMISSION_DENIED, timeoutMillis);
+ }
+
+ private void waitUntilPermissionRevoked(long timeoutMillis, String permName) throws Throwable {
+ try {
+ eventually(() -> {
+ PackageInfo appInfo = mContext.getPackageManager().getPackageInfo(APP_PKG_NAME,
+ GET_PERMISSIONS);
+
+ for (int i = 0; i < appInfo.requestedPermissions.length; i++) {
+ if (appInfo.requestedPermissions[i].equals(permName)
+ && (
+ (appInfo.requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED)
+ == 0)) {
+ return;
+ }
+ }
+
+ fail(permName + " not revoked");
+ }, timeoutMillis);
+ } catch (RuntimeException e) {
+ throw e.getCause();
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/RuntimePermissionPresentationInfoTest.java b/tests/cts/permission/src/android/permission/cts/RuntimePermissionPresentationInfoTest.java
new file mode 100644
index 000000000..9294c0aff
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/RuntimePermissionPresentationInfoTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.permission.RuntimePermissionPresentationInfo;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link RuntimePermissionPresentationInfoTest}
+ */
+@RunWith(AndroidJUnit4.class)
+public class RuntimePermissionPresentationInfoTest {
+ @Test
+ public void runtimePermissionLabelSet() {
+ assertThat(new RuntimePermissionPresentationInfo("test", true,
+ true).getLabel()).isEqualTo("test");
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void runtimePermissionLabelSetNull() {
+ RuntimePermissionPresentationInfo info = new RuntimePermissionPresentationInfo(null, true,
+ true);
+ }
+
+ @Test
+ public void runtimePermissionGrantedCanBeTrue() {
+ assertThat(new RuntimePermissionPresentationInfo("", true, true).isGranted()).isTrue();
+ }
+
+ @Test
+ public void runtimePermissionGrantedCanBeFalse() {
+ assertThat(new RuntimePermissionPresentationInfo("", false, true).isGranted()).isFalse();
+ }
+
+ @Test
+ public void runtimePermissionStandardCanBeTrue() {
+ assertThat(new RuntimePermissionPresentationInfo("", true, true).isStandard()).isTrue();
+ }
+
+ @Test
+ public void runtimePermissionStandardCanBeFalse() {
+ assertThat(new RuntimePermissionPresentationInfo("", true, false).isStandard()).isFalse();
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/SafetyCenterUtils.kt b/tests/cts/permission/src/android/permission/cts/SafetyCenterUtils.kt
new file mode 100644
index 000000000..7ca9b138d
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/SafetyCenterUtils.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.app.Instrumentation
+import android.app.UiAutomation
+import android.content.Context
+import android.content.Intent
+import android.content.res.Resources
+import android.os.Build
+import android.os.UserHandle
+import android.provider.DeviceConfig
+import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterManager
+import androidx.annotation.RequiresApi
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
+import com.android.safetycenter.internaldata.SafetyCenterIds
+import com.android.safetycenter.internaldata.SafetyCenterIssueId
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey
+import org.junit.Assert
+
+object SafetyCenterUtils {
+ /** Name of the flag that determines whether SafetyCenter is enabled. */
+ const val PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ /** Returns whether the device supports Safety Center. */
+ @JvmStatic
+ fun deviceSupportsSafetyCenter(context: Context): Boolean {
+ return context.resources.getBoolean(
+ Resources.getSystem().getIdentifier("config_enableSafetyCenter", "bool", "android")
+ )
+ }
+
+ /** Enabled or disable Safety Center */
+ @JvmStatic
+ fun setSafetyCenterEnabled(enabled: Boolean) {
+ setDeviceConfigPrivacyProperty(PROPERTY_SAFETY_CENTER_ENABLED, enabled.toString())
+ }
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ @JvmStatic
+ fun startSafetyCenterActivity(context: Context) {
+ context.startActivity(
+ Intent(Intent.ACTION_SAFETY_CENTER)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ )
+ }
+
+ @JvmStatic
+ fun assertSafetyCenterStarted() {
+ // CollapsingToolbar title can't be found by text, so using description instead.
+ waitFindObject(By.desc("Security & privacy"))
+ }
+
+ @JvmStatic
+ fun setDeviceConfigPrivacyProperty(
+ propertyName: String,
+ value: String,
+ uiAutomation: UiAutomation = instrumentation.uiAutomation
+ ) {
+ runWithShellPermissionIdentity(uiAutomation) {
+ val valueWasSet =
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ /* name = */ propertyName,
+ /* value = */ value,
+ /* makeDefault = */ false
+ )
+ check(valueWasSet) { "Could not set $propertyName to $value" }
+ }
+ }
+
+ @JvmStatic
+ fun deleteDeviceConfigPrivacyProperty(
+ propertyName: String,
+ uiAutomation: UiAutomation = instrumentation.uiAutomation
+ ) {
+ runWithShellPermissionIdentity(uiAutomation) {
+ DeviceConfig.deleteProperty(DeviceConfig.NAMESPACE_PRIVACY, propertyName)
+ }
+ }
+
+ @JvmStatic
+ private fun getSafetyCenterIssues(
+ automation: UiAutomation = instrumentation.uiAutomation
+ ): List<SafetyCenterIssue> {
+ val safetyCenterManager =
+ instrumentation.targetContext.getSystemService(SafetyCenterManager::class.java)
+ val issues = ArrayList<SafetyCenterIssue>()
+ runWithShellPermissionIdentity(automation) {
+ val safetyCenterData = safetyCenterManager!!.safetyCenterData
+ issues.addAll(safetyCenterData.issues)
+ }
+ return issues
+ }
+
+ @JvmStatic
+ fun assertSafetyCenterIssueExist(
+ sourceId: String,
+ issueId: String,
+ issueTypeId: String,
+ automation: UiAutomation = instrumentation.uiAutomation
+ ) {
+ val safetyCenterIssueId = safetyCenterIssueId(sourceId, issueId, issueTypeId)
+ Assert.assertTrue(
+ "Expect issues in safety center",
+ getSafetyCenterIssues(automation).any { safetyCenterIssueId == it.id }
+ )
+ }
+
+ @JvmStatic
+ fun assertSafetyCenterIssueDoesNotExist(
+ sourceId: String,
+ issueId: String,
+ issueTypeId: String,
+ automation: UiAutomation = instrumentation.uiAutomation
+ ) {
+ val safetyCenterIssueId = safetyCenterIssueId(sourceId, issueId, issueTypeId)
+ Assert.assertTrue(
+ "Expect no issue in safety center",
+ getSafetyCenterIssues(automation).none { safetyCenterIssueId == it.id }
+ )
+ }
+
+ private fun safetyCenterIssueId(sourceId: String, sourceIssueId: String, issueTypeId: String) =
+ SafetyCenterIds.encodeToString(
+ SafetyCenterIssueId.newBuilder()
+ .setSafetyCenterIssueKey(
+ SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(sourceId)
+ .setSafetySourceIssueId(sourceIssueId)
+ .setUserId(UserHandle.myUserId())
+ .build()
+ )
+ .setIssueTypeId(issueTypeId)
+ .build()
+ )
+}
diff --git a/tests/cts/permission/src/android/permission/cts/SdkSandboxPermissionTest.java b/tests/cts/permission/src/android/permission/cts/SdkSandboxPermissionTest.java
new file mode 100644
index 000000000..88fcaec45
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/SdkSandboxPermissionTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for permission handling for sdk sandbox uid range.
+ */
+@AppModeFull(reason = "Instant apps can't access PermissionManager")
+@RunWith(AndroidJUnit4ClassRunner.class)
+public class SdkSandboxPermissionTest {
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ public void testSdkSandboxHasInternetPermission() throws Exception {
+ final Context ctx = getInstrumentation().getContext();
+ int ret = ctx.checkPermission(
+ Manifest.permission.INTERNET,
+ /* pid= */ -1 /* invalid pid */,
+ Process.toSdkSandboxUid(19999));
+ assertThat(ret).isEqualTo(PackageManager.PERMISSION_GRANTED);
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ public void testSdkSandboxDoesNotHaveFineLocationPermission() throws Exception {
+ final Context ctx = getInstrumentation().getContext();
+ int ret = ctx.checkPermission(
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ /* pid= */ -1 /* invalid pid */,
+ Process.toSdkSandboxUid(19999));
+ assertThat(ret).isEqualTo(PackageManager.PERMISSION_DENIED);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/SecureElementPermissionTest.java b/tests/cts/permission/src/android/permission/cts/SecureElementPermissionTest.java
new file mode 100644
index 000000000..1f04b1ccf
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/SecureElementPermissionTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static org.junit.Assert.fail;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Process;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+@RunWith(JUnit4.class)
+public final class SecureElementPermissionTest {
+ // Needed because SECURE_ELEMENT_PRIVILEGED_PERMISSION is a systemapi
+ public static final String SECURE_ELEMENT_PRIVILEGED_PERMISSION =
+ "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
+
+ @Test
+ public void testSecureElementPrivilegedPermission() {
+ PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+
+ List<Integer> specialUids = Arrays.asList(Process.SYSTEM_UID, Process.PHONE_UID);
+
+ List<PackageInfo> holding = pm.getPackagesHoldingPermissions(
+ new String[] { SECURE_ELEMENT_PRIVILEGED_PERMISSION },
+ PackageManager.MATCH_DISABLED_COMPONENTS);
+
+ List<Integer> nonSpecialPackages = holding.stream()
+ .map(pi -> {
+ try {
+ return pm.getPackageUid(pi.packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return Process.INVALID_UID;
+ }
+ })
+ .filter(uid -> !specialUids.contains(uid))
+ .collect(Collectors.toList());
+
+ if (nonSpecialPackages.size() > 1) {
+ fail("Only one app on the device is allowed to hold the " +
+ "SECURE_ELEMENT_PRIVILEGED_OPERATION permission.");
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/ServicePermissionTest.java b/tests/cts/permission/src/android/permission/cts/ServicePermissionTest.java
new file mode 100644
index 000000000..6c10f1d31
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/ServicePermissionTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The security designs of many system features require that a special
+ * permission is only ever granted to the core system (typically
+ * {@code system_server}), since it's the only process that should be binding
+ * into sensitive app code.
+ * <p>
+ * No apps outside the {@code system_server} should <em>ever</em> attempt to
+ * acquire these permissions.
+ */
+public class ServicePermissionTest extends AndroidTestCase {
+ public static String[] sServicePermissions = {
+ android.Manifest.permission.ACCOUNT_MANAGER,
+ android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
+ android.Manifest.permission.BIND_AUTOFILL_SERVICE,
+ android.Manifest.permission.BIND_CHOOSER_TARGET_SERVICE,
+ android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE,
+ // android.Manifest.permission.BIND_DEVICE_ADMIN,
+ android.Manifest.permission.BIND_DREAM_SERVICE,
+ android.Manifest.permission.BIND_INPUT_METHOD,
+ android.Manifest.permission.BIND_MIDI_DEVICE_SERVICE,
+ // android.Manifest.permission.BIND_NFC_SERVICE,
+ android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE,
+ android.Manifest.permission.BIND_PRINT_SERVICE,
+ // android.Manifest.permission.BIND_QUICK_SETTINGS_TILE,
+ android.Manifest.permission.BIND_TEXT_SERVICE,
+ android.Manifest.permission.BIND_VOICE_INTERACTION,
+ android.Manifest.permission.BIND_VPN_SERVICE,
+ android.Manifest.permission.BIND_VR_LISTENER_SERVICE,
+ };
+
+ public void testServicePermissions() {
+ final PackageManager pm = getContext().getPackageManager();
+
+ final List<String> failures = new ArrayList<>();
+ for (String perm : sServicePermissions) {
+ final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(
+ new String[] { perm }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ for (PackageInfo pi : holding) {
+ if (!Objects.equals("android", pi.packageName)) {
+ failures.add(perm + " held by " + pi.packageName);
+ }
+ }
+ }
+ if (!failures.isEmpty()) {
+ fail("Found permissions granted to packages outside of the core system: "
+ + failures.toString());
+ }
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java b/tests/cts/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java
new file mode 100644
index 000000000..8609e3379
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.content.Context.DEVICE_POLICY_SERVICE;
+import static android.content.Context.FINGERPRINT_SERVICE;
+import static android.content.Context.SHORTCUT_SERVICE;
+import static android.content.Context.USB_SERVICE;
+import static android.content.Context.WALLPAPER_SERVICE;
+import static android.content.Context.WIFI_AWARE_SERVICE;
+import static android.content.Context.WIFI_P2P_SERVICE;
+import static android.content.Context.WIFI_SERVICE;
+
+import static org.junit.Assert.assertNull;
+
+import android.content.Context;
+import android.platform.test.annotations.AppModeInstant;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Some services are not available to instant apps, see {@link Context#getSystemService}.
+ */
+@AppModeInstant
+@RunWith(AndroidJUnit4.class)
+public class ServicesInstantAppsCannotAccessTests {
+ @Test
+ public void cannotGetDevicePolicyManager() {
+ assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
+ DEVICE_POLICY_SERVICE));
+ }
+
+ @Test
+ public void cannotGetFingerprintManager() {
+ assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
+ FINGERPRINT_SERVICE));
+ }
+
+ @Test
+ public void cannotGetShortcutManager() {
+ assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
+ SHORTCUT_SERVICE));
+ }
+
+ @Test
+ public void cannotGetUsbManager() {
+ assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
+ USB_SERVICE));
+ }
+
+ @Test
+ public void cannotGetWallpaperManager() {
+ assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
+ WALLPAPER_SERVICE));
+ }
+
+ @Test
+ public void cannotGetWifiP2pManager() {
+ assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
+ WIFI_P2P_SERVICE));
+ }
+
+ @Test
+ public void cannotGetWifiManager() {
+ assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
+ WIFI_SERVICE));
+ }
+
+ @Test
+ public void cannotGetWifiAwareManager() {
+ assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
+ WIFI_AWARE_SERVICE));
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/SharedUidPermissionsTest.java b/tests/cts/permission/src/android/permission/cts/SharedUidPermissionsTest.java
new file mode 100644
index 000000000..4966a870b
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/SharedUidPermissionsTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.INTERNET;
+import static android.Manifest.permission.READ_CONTACTS;
+import static android.permission.cts.PermissionUtils.grantPermission;
+import static android.permission.cts.PermissionUtils.install;
+import static android.permission.cts.PermissionUtils.isPermissionGranted;
+import static android.permission.cts.PermissionUtils.revokePermission;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
+ + "to grant permissions to them.")
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+public class SharedUidPermissionsTest {
+ /** The package name of all apps used in the test */
+ private static final String PKG_THAT_REQUESTS_PERMISSIONS =
+ "android.permission.cts.appthatrequestpermission";
+ private static final String PKG_THAT_REQUESTS_NO_PERMISSIONS =
+ "android.permission.cts.appthatrequestnopermission";
+
+ private static final String TMP_DIR = "/data/local/tmp/cts-permission/";
+ private static final String APK_THAT_REQUESTS_PERMISSIONS =
+ TMP_DIR + "CtsAppWithSharedUidThatRequestsPermissions.apk";
+ private static final String APK_THAT_REQUESTS_NO_PERMISSIONS =
+ TMP_DIR + "CtsAppWithSharedUidThatRequestsNoPermissions.apk";
+
+ @Before
+ @After
+ public void uninstallTestApps() {
+ uninstallApp(PKG_THAT_REQUESTS_PERMISSIONS);
+ uninstallApp(PKG_THAT_REQUESTS_NO_PERMISSIONS);
+ }
+
+ @Test
+ public void packageGainsRuntimePermissionsWhenJoiningSharedUid() throws Exception {
+ install(APK_THAT_REQUESTS_PERMISSIONS);
+ grantPermission(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS);
+ install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS)).isTrue();
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isTrue();
+ }
+
+ @Test
+ public void packageGainsNormalPermissionsWhenJoiningSharedUid() throws Exception {
+ install(APK_THAT_REQUESTS_PERMISSIONS);
+ install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_PERMISSIONS, INTERNET)).isTrue();
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, INTERNET)).isTrue();
+ }
+
+ @Test
+ public void grantingRuntimePermissionAffectsAllPackageInSharedUid() throws Exception {
+ install(APK_THAT_REQUESTS_PERMISSIONS);
+ install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+ grantPermission(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS);
+
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS)).isTrue();
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isTrue();
+ }
+
+ @Test
+ public void revokingRuntimePermissionAffectsAllPackageInSharedUid() throws Exception {
+ install(APK_THAT_REQUESTS_PERMISSIONS);
+ install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+ grantPermission(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS);
+ revokePermission(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS);
+
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS)).isFalse();
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isFalse();
+ }
+
+ @Test
+ public void runtimePermissionsCanBeRevokedOnPackageThatDoesNotDeclarePermission()
+ throws Exception {
+ install(APK_THAT_REQUESTS_PERMISSIONS);
+ install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+ grantPermission(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS);
+ revokePermission(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS);
+
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS)).isFalse();
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isFalse();
+ }
+
+ @Test
+ @FlakyTest
+ public void runtimePermissionsCanBeGrantedOnPackageThatDoesNotDeclarePermission()
+ throws Exception {
+ install(APK_THAT_REQUESTS_PERMISSIONS);
+ install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+ grantPermission(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS);
+
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS)).isTrue();
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isTrue();
+ }
+
+ @Test
+ public void sharedUidLoosesRuntimePermissionWhenLastAppDeclaringItGetsUninstalled()
+ throws Exception {
+ install(APK_THAT_REQUESTS_PERMISSIONS);
+ install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+ grantPermission(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS);
+ uninstallApp(PKG_THAT_REQUESTS_PERMISSIONS);
+
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isFalse();
+ }
+
+ @Test
+ @FlakyTest
+ public void sharedUidLoosesNormalPermissionWhenLastAppDeclaringItGetsUninstalled()
+ throws Exception {
+ install(APK_THAT_REQUESTS_PERMISSIONS);
+ install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+ uninstallApp(PKG_THAT_REQUESTS_PERMISSIONS);
+
+ assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, INTERNET)).isFalse();
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/ShellCommandPermissionTest.java b/tests/cts/permission/src/android/permission/cts/ShellCommandPermissionTest.java
new file mode 100644
index 000000000..54562d5ee
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/ShellCommandPermissionTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test shell command capability enforcement
+ */
+@RunWith(AndroidJUnit4.class)
+public class ShellCommandPermissionTest {
+
+ static final int EXPECTED_ERROR_CODE = 255;
+
+ /**
+ * Runs the given command, waits for it to exit, and verifies the return
+ * code indicates failure.
+ */
+ private void executeShellCommandAndWaitForError(String command)
+ throws Exception {
+ try {
+ java.lang.Process proc = Runtime.getRuntime().exec(command);
+ assertThat(proc.waitFor()).isEqualTo(EXPECTED_ERROR_CODE);
+ } catch (InterruptedException e) {
+ fail("Unsuccessful shell command");
+ }
+ }
+
+ @Test
+ public void testTraceIpc() throws Exception {
+ executeShellCommandAndWaitForError(
+ "cmd activity trace-ipc stop --dump-file /data/system/last-fstrim");
+ }
+
+ @Test
+ public void testDumpheap() throws Exception {
+ executeShellCommandAndWaitForError(
+ "cmd activity dumpheap system_server /data/system/last-fstrim");
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/ShellPermissionTest.java b/tests/cts/permission/src/android/permission/cts/ShellPermissionTest.java
new file mode 100644
index 000000000..c4c66564c
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/ShellPermissionTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SystemUserOnly;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Tests that shell has acceptable permissions.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ShellPermissionTest {
+ private static final String LOG_TAG = ShellPermissionTest.class.getSimpleName();
+
+ /** Permissions that shell is NOT permitted to have. */
+ private static final String[] BLACKLISTED_PERMISSIONS = {
+ "android.permission.MANAGE_USERS",
+ "android.permission.NETWORK_STACK",
+ "android.permission.MANAGE_WIFI_COUNTRY_CODE",
+ };
+
+ private static final Context sContext = InstrumentationRegistry.getTargetContext();
+
+ /**
+ * Verify that the shell uid does not have any of the permissions listed in
+ * {@link #BLACKLISTED_PERMISSIONS}.
+ */
+ @Test
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages. Also the shell "
+ + "is never an instant app, hence this test does not matter for instant apps.")
+ public void testBlacklistedPermissions() throws Exception {
+ final Set<String> blacklist = new HashSet<>(Arrays.asList(BLACKLISTED_PERMISSIONS));
+
+ final PackageManager pm = sContext.getPackageManager();
+ int uid = UserHandle.getUid(UserHandle.myUserId(), UserHandle.getAppId(Process.SHELL_UID));
+ final String[] pkgs = pm.getPackagesForUid(uid);
+ Log.d(LOG_TAG, "SHELL_UID: " + Process.SHELL_UID + " myUserId: "
+ + UserHandle.myUserId() + " uid: " + uid + " pkgs.length: " + pkgs.length);
+ assertNotNull("No SHELL packages were found", pkgs);
+ assertNotEquals("SHELL package list had 0 size", 0, pkgs.length);
+ String pkg = pkgs[0];
+
+ final PackageInfo packageInfo = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
+ assertNotNull("No permissions found for " + pkg, packageInfo.requestedPermissions);
+
+ for (String permission : packageInfo.requestedPermissions) {
+ Log.d(LOG_TAG, "SHELL as " + pkg + " uses permission " + permission + " uid: "
+ + uid);
+ assertFalse("SHELL as " + pkg + " contains the illegal permission " + permission,
+ blacklist.contains(permission));
+ }
+ }
+
+ @Test
+ @SystemUserOnly
+ @AppModeFull(reason = "Instant apps cannot read properties of other packages. Also the shell "
+ + "is never an instant app, hence this test does not matter for instant apps.")
+ public void testBlacklistedPermissionsForSystemUser() throws Exception {
+ testBlacklistedPermissions();
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/SmsManagerPermissionTest.java b/tests/cts/permission/src/android/permission/cts/SmsManagerPermissionTest.java
new file mode 100644
index 000000000..dd0d9f234
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/SmsManagerPermissionTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permission.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.telephony.SmsManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+/**
+ * Test that sending SMS and MMS messages requires permissions.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SmsManagerPermissionTest {
+
+ private static final String SOURCE_ADDRESS = "+15550000000";
+ private static final String DESTINATION_ADDRESS = "+15550000001";
+
+ private boolean mHasTelephony;
+ private SmsManager mSmsManager;
+ private Context mContext;
+ private TelephonyManager mTelephonyManager;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
+ mHasTelephony = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY);
+ assumeTrue(mHasTelephony); // Don't run these tests if FEATURE_TELEPHONY is not available.
+
+ Log.d("SmsManagerPermissionTest", "mSubId=" + subId);
+
+ mSmsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
+ assertNotNull(mSmsManager);
+ }
+
+ @Test
+ public void testSendTextMessage() {
+ assertFalse("[RERUN] Device does not have SIM card. Use a suitable SIM Card.",
+ isSimCardAbsent());
+
+ assertThrows(SecurityException.class, () -> mSmsManager.sendTextMessage(
+ DESTINATION_ADDRESS, SOURCE_ADDRESS, "Message text", null, null));
+ }
+
+ @Test
+ public void testSendTextMessageWithoutPersisting() {
+ assertFalse("[RERUN] Device does not have SIM card. Use a suitable SIM Card.",
+ isSimCardAbsent());
+
+ assertThrows(SecurityException.class, () -> mSmsManager.sendTextMessageWithoutPersisting(
+ DESTINATION_ADDRESS, SOURCE_ADDRESS, "Message text", null, null));
+ }
+
+ @Test
+ public void testSendMultipartTextMessage() {
+ assertFalse("[RERUN] Device does not have SIM card. Use a suitable SIM Card.",
+ isSimCardAbsent());
+
+ ArrayList<String> messageParts = new ArrayList<>();
+ messageParts.add("Message text");
+ assertThrows(SecurityException.class, () -> mSmsManager.sendMultipartTextMessage(
+ DESTINATION_ADDRESS, SOURCE_ADDRESS, messageParts, null, null));
+ }
+
+ @Test
+ public void testSendDataMessage() {
+ assertFalse("[RERUN] Device does not have SIM card. Use a suitable SIM Card.",
+ isSimCardAbsent());
+
+ assertThrows(SecurityException.class, () -> mSmsManager.sendDataMessage(
+ DESTINATION_ADDRESS, SOURCE_ADDRESS, (short) 1, new byte[]{0, 0, 0}, null, null));
+ }
+
+ @Test
+ public void testSendMultimediaMessage() {
+ assertFalse("[RERUN] Device does not have SIM card. Use a suitable SIM Card.",
+ isSimCardAbsent());
+
+ // Ideally we would provide an Uri to an existing resource, to make sure the
+ // SecurityException is not due to the invalid Uri.
+ Uri uri = Uri.parse("android.resource://android.permission.cts/some-image.png");
+ assertThrows(SecurityException.class,
+ () -> mSmsManager.sendMultimediaMessage(mContext, uri, "", null, null));
+ }
+
+ private boolean isSimCardAbsent() {
+ return ((mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_ABSENT)
+ || (SubscriptionManager.getDefaultSmsSubscriptionId()
+ == SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java b/tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java
new file mode 100644
index 000000000..a509b3bfe
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.READ_CALL_LOG;
+import static android.Manifest.permission.READ_CONTACTS;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.permission.cts.PermissionUtils.getAppOp;
+import static android.permission.cts.PermissionUtils.getPermissionFlags;
+import static android.permission.cts.PermissionUtils.getPermissions;
+import static android.permission.cts.PermissionUtils.grantPermission;
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permission.cts.PermissionUtils.revokePermission;
+import static android.permission.cts.PermissionUtils.setPermissionFlags;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.UiAutomation;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SystemUserOnly;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests how split permissions behave.
+ *
+ * <ul>
+ * <li>Default permission grant behavior</li>
+ * <li>Changes to the grant state during upgrade of apps with split permissions</li>
+ * <li>Special behavior of background location</li>
+ * </ul>
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Instant apps cannot read state of other packages.")
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+public class SplitPermissionTest {
+ /** The package name of all apps used in the test */
+ private static final String APP_PKG = "android.permission.cts.appthatrequestpermission";
+
+ private static final String TMP_DIR = "/data/local/tmp/cts-permission/";
+ private static final String APK_CONTACTS_16 =
+ TMP_DIR + "CtsAppThatRequestsContactsPermission16.apk";
+ private static final String APK_CONTACTS_15 =
+ TMP_DIR + "CtsAppThatRequestsContactsPermission15.apk";
+ private static final String APK_CONTACTS_CALLLOG_16 =
+ TMP_DIR + "CtsAppThatRequestsContactsAndCallLogPermission16.apk";
+ private static final String APK_STORAGE_29 =
+ TMP_DIR + "CtsAppThatRequestsStoragePermission29.apk";
+ private static final String APK_STORAGE_28 =
+ TMP_DIR + "CtsAppThatRequestsStoragePermission28.apk";
+ private static final String APK_LOCATION_29 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission29.apk";
+ private static final String APK_LOCATION_28 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission28.apk";
+ private static final String APK_LOCATION_22 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission22.apk";
+ private static final String APK_LOCATION_BACKGROUND_28 =
+ TMP_DIR + "CtsAppThatRequestsLocationAndBackgroundPermission28.apk";
+ private static final String APK_LOCATION_BACKGROUND_29 =
+ TMP_DIR + "CtsAppThatRequestsLocationAndBackgroundPermission29.apk";
+ private static final String APK_SHARED_UID_LOCATION_29 =
+ TMP_DIR + "CtsAppWithSharedUidThatRequestsLocationPermission29.apk";
+ private static final String APK_SHARED_UID_LOCATION_28 =
+ TMP_DIR + "CtsAppWithSharedUidThatRequestsLocationPermission28.apk";
+
+ private static final UiAutomation sUiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
+ /**
+ * Assert that {@link #APP_PKG} requests a certain permission.
+ *
+ * @param permName The permission that needs to be requested
+ */
+ private void assertRequestsPermission(@NonNull String permName) throws Exception {
+ assertThat(getPermissions(APP_PKG)).contains(permName);
+ }
+
+ /**
+ * Assert that {@link #APP_PKG} <u>does not</u> request a certain permission.
+ *
+ * @param permName The permission that needs to be not requested
+ */
+ private void assertNotRequestsPermission(@NonNull String permName) throws Exception {
+ assertThat(getPermissions(APP_PKG)).doesNotContain(permName);
+ }
+
+ /**
+ * Assert that a permission is granted to {@link #APP_PKG}.
+ *
+ * @param permName The permission that needs to be granted
+ */
+ private void assertPermissionGranted(@NonNull String permName) throws Exception {
+ eventually(() -> assertWithMessage(permName + " is granted").that(
+ isGranted(APP_PKG, permName)).isTrue());
+ }
+
+ /**
+ * Assert that a permission is <u>not </u> granted to {@link #APP_PKG}.
+ *
+ * @param permName The permission that should not be granted
+ */
+ private void assertPermissionRevoked(@NonNull String permName) throws Exception {
+ assertWithMessage(permName + " is granted").that(isGranted(APP_PKG, permName)).isFalse();
+ }
+
+ /**
+ * Install an APK.
+ *
+ * @param apkFile The apk to install
+ */
+ public void install(@NonNull String apkFile) {
+ PermissionUtils.install(apkFile);
+ }
+
+ @After
+ public void uninstallTestApp() {
+ uninstallApp(APP_PKG);
+ }
+
+ /**
+ * Apps with a targetSDK after the split should <u>not</u> have been added implicitly the new
+ * permission.
+ */
+ @Test
+ public void permissionsDoNotSplitWithHighTargetSDK() throws Exception {
+ install(APK_LOCATION_29);
+
+ assertRequestsPermission(ACCESS_COARSE_LOCATION);
+ assertNotRequestsPermission(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * Apps with a targetSDK after the split should <u>not</u> have been added implicitly the new
+ * permission.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void permissionsDoNotSplitWithHighTargetSDKPreM() throws Exception {
+ install(APK_CONTACTS_16);
+
+ assertRequestsPermission(READ_CONTACTS);
+ assertNotRequestsPermission(READ_CALL_LOG);
+ }
+
+ /**
+ * Apps with a targetSDK before the split should have been added implicitly the new permission.
+ */
+ @Test
+ public void permissionsSplitWithLowTargetSDK() throws Exception {
+ install(APK_LOCATION_28);
+
+ assertRequestsPermission(ACCESS_COARSE_LOCATION);
+ assertRequestsPermission(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * Apps with a targetSDK before the split should have been added implicitly the new permission.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void permissionsSplitWithLowTargetSDKPreM() throws Exception {
+ install(APK_CONTACTS_15);
+
+ assertRequestsPermission(READ_CONTACTS);
+ assertRequestsPermission(READ_CALL_LOG);
+ }
+
+ /**
+ * Permissions are revoked by default for post-M apps
+ */
+ @Test
+ public void nonInheritedStateHighTargetSDK() throws Exception {
+ install(APK_LOCATION_29);
+
+ assertPermissionRevoked(ACCESS_COARSE_LOCATION);
+ }
+
+ /**
+ * Permissions are granted by default for pre-M apps
+ */
+ @Test
+ public void nonInheritedStateHighLowTargetSDKPreM() throws Exception {
+ install(APK_CONTACTS_15);
+
+ assertPermissionGranted(READ_CONTACTS);
+ }
+
+ /**
+ * Permissions are revoked by default for post-M apps. This also applies to permissions added
+ * implicitly due to splits.
+ */
+ @Test
+ public void nonInheritedStateLowTargetSDK() throws Exception {
+ install(APK_LOCATION_28);
+
+ assertPermissionRevoked(ACCESS_COARSE_LOCATION);
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * Permissions are granted by default for pre-M apps. This also applies to permissions added
+ * implicitly due to splits.
+ */
+ @Test
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void nonInheritedStateLowTargetSDKPreM() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ install(APK_CONTACTS_15);
+
+ assertPermissionGranted(READ_CONTACTS);
+ assertPermissionGranted(READ_CALL_LOG);
+ }
+
+ /**
+ * The background location permission granted by default for pre-M apps.
+ */
+ @Test
+ public void backgroundLocationPermissionDefaultGrantPreM() throws Exception {
+ install(APK_LOCATION_22);
+
+ assertPermissionGranted(ACCESS_COARSE_LOCATION);
+ assertPermissionGranted(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * If a permission was granted before the split happens, the new permission should inherit the
+ * granted state.
+ */
+ @FlakyTest(bugId = 152580253)
+ @MtsIgnore(bugId = 152580253)
+ @Test
+ public void inheritGrantedPermissionState() throws Exception {
+ install(APK_LOCATION_29);
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ install(APK_LOCATION_28);
+
+ assertPermissionGranted(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * If a permission was granted before the split happens, the new permission should inherit the
+ * granted state.
+ *
+ * <p>App using a shared uid
+ */
+ @Test
+ public void inheritGrantedPermissionStateSharedUidApp() throws Exception {
+ install(APK_SHARED_UID_LOCATION_29);
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ install(APK_SHARED_UID_LOCATION_28);
+
+ assertPermissionGranted(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * If a permission has flags before the split happens, the new permission should inherit the
+ * flags.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @FlakyTest(bugId = 152580253)
+ @MtsIgnore(bugId = 152580253)
+ @Test
+ public void inheritFlagsPreM() {
+ install(APK_CONTACTS_16);
+ setPermissionFlags(APP_PKG, READ_CONTACTS, FLAG_PERMISSION_USER_SET,
+ FLAG_PERMISSION_USER_SET);
+
+ install(APK_CONTACTS_15);
+
+ assertEquals(FLAG_PERMISSION_USER_SET,
+ getPermissionFlags(APP_PKG, READ_CALL_LOG) & FLAG_PERMISSION_USER_SET);
+ }
+
+ /**
+ * If a permission has flags before the split happens, the new permission should inherit the
+ * flags.
+ */
+ @FlakyTest(bugId = 152580253)
+ @MtsIgnore(bugId = 152580253)
+ @Test
+ public void inheritFlags() {
+ install(APK_LOCATION_29);
+ setPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION, FLAG_PERMISSION_USER_SET,
+ FLAG_PERMISSION_USER_SET);
+
+ install(APK_LOCATION_28);
+
+ assertEquals(FLAG_PERMISSION_USER_SET,
+ getPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION) & FLAG_PERMISSION_USER_SET);
+ }
+
+ /**
+ * If a permission was granted before the split happens, the new permission should inherit the
+ * granted state.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void inheritGrantedPermissionStatePreM() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ install(APK_CONTACTS_16);
+
+ install(APK_CONTACTS_15);
+
+ assertPermissionGranted(READ_CALL_LOG);
+ }
+
+ /**
+ * If a permission was revoked before the split happens, the new permission should inherit the
+ * revoked state.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void inheritRevokedPermissionState() throws Exception {
+ install(APK_LOCATION_29);
+
+ install(APK_LOCATION_28);
+
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * If a permission was revoked before the split happens, the new permission should inherit the
+ * revoked state.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void inheritRevokedPermissionStatePreM() throws Exception {
+ install(APK_CONTACTS_16);
+ revokePermission(APP_PKG, READ_CONTACTS);
+
+ install(APK_CONTACTS_15);
+
+ /*
+ * Ideally the new permission should inherit from it's base permission, but this is tricky
+ * to implement.
+ * The new permissions need to be reviewed, hence the pre-review state really does not
+ * matter anyway.
+ */
+ // assertPermissionRevoked(READ_CALL_LOG);
+ assertThat(getPermissionFlags(APP_PKG, READ_CALL_LOG)
+ & FLAG_PERMISSION_REVIEW_REQUIRED).isEqualTo(FLAG_PERMISSION_REVIEW_REQUIRED);
+ }
+
+ /**
+ * It should be possible to grant a permission implicitly added due to a split.
+ */
+ @Test
+ public void grantNewSplitPermissionState() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ assertPermissionGranted(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * It should be possible to grant a permission implicitly added due to a split.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void grantNewSplitPermissionStatePreM() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ install(APK_CONTACTS_15);
+ revokePermission(APP_PKG, READ_CONTACTS);
+
+ grantPermission(APP_PKG, READ_CALL_LOG);
+
+ assertPermissionGranted(READ_CALL_LOG);
+ }
+
+ /**
+ * It should be possible to revoke a permission implicitly added due to a split.
+ */
+ @Test
+ public void revokeNewSplitPermissionState() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ revokePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * It should be possible to revoke a permission implicitly added due to a split.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void revokeNewSplitPermissionStatePreM() throws Exception {
+ install(APK_CONTACTS_15);
+
+ revokePermission(APP_PKG, READ_CALL_LOG);
+
+ assertPermissionRevoked(READ_CALL_LOG);
+ }
+
+ /**
+ * An implicit permission should get revoked when the app gets updated and now requests the
+ * permission.
+ */
+ @Test
+ public void newPermissionGetRevokedOnUpgrade() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ install(APK_LOCATION_BACKGROUND_29);
+
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * An implicit background permission should get revoked when the app gets updated and now
+ * requests the permission. Revoking a background permission should have changed the app-op of
+ * the foreground permission.
+ */
+ @Test
+ public void newBackgroundPermissionGetRevokedOnUpgrade() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ install(APK_LOCATION_BACKGROUND_29);
+
+ eventually(() -> assertWithMessage("foreground app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
+ }
+
+ /**
+ * An implicit permission should get revoked when the app gets updated and now requests the
+ * permission. This even happens if the app is not targeting the SDK the permission was split
+ * in.
+ */
+ @Test
+ public void newPermissionGetRevokedOnUpgradeBeforeSplitSDK() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ // Background location was introduced in SDK 29. Hence an app targeting 28 is usually
+ // unaware of this permission. If the app declares that it is aware by adding the permission
+ // in the manifest the permission will get revoked. This allows the app to request the
+ // permission from the user.
+ install(APK_LOCATION_BACKGROUND_28);
+
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * An implicit permission should <u>not</u> get revoked when the app gets updated as pre-M apps
+ * cannot deal with revoked permissions. Hence only the user should ever explicitly do that.
+ */
+ @Test
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void newPermissionGetRevokedOnUpgradePreM() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ install(APK_CONTACTS_15);
+
+ install(APK_CONTACTS_CALLLOG_16);
+
+ assertPermissionGranted(READ_CALL_LOG);
+ }
+
+ /**
+ * When a requested permission was granted before upgrade it should still be granted.
+ */
+ @Test
+ public void oldPermissionStaysGrantedOnUpgrade() throws Exception {
+ install(APK_LOCATION_28);
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ install(APK_LOCATION_BACKGROUND_29);
+
+ assertPermissionGranted(ACCESS_COARSE_LOCATION);
+ }
+
+ /**
+ * When a requested permission was granted before upgrade it should still be granted.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void oldPermissionStaysGrantedOnUpgradePreM() throws Exception {
+ install(APK_CONTACTS_15);
+
+ install(APK_CONTACTS_CALLLOG_16);
+
+ assertPermissionGranted(READ_CONTACTS);
+ }
+
+ /**
+ * When a requested permission was revoked before upgrade it should still be revoked.
+ */
+ @Test
+ public void oldPermissionStaysRevokedOnUpgrade() throws Exception {
+ install(APK_LOCATION_28);
+
+ install(APK_LOCATION_BACKGROUND_29);
+
+ assertPermissionRevoked(ACCESS_COARSE_LOCATION);
+ }
+
+ /**
+ * When a requested permission was revoked before upgrade it should still be revoked.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void oldPermissionStaysRevokedOnUpgradePreM() throws Exception {
+ install(APK_CONTACTS_15);
+ revokePermission(APP_PKG, READ_CONTACTS);
+
+ install(APK_CONTACTS_CALLLOG_16);
+
+ assertPermissionRevoked(READ_CONTACTS);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/SplitPermissionsSystemTest.java b/tests/cts/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
new file mode 100755
index 000000000..776a1065e
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.ACCESS_MEDIA_LOCATION;
+import static android.Manifest.permission.BLUETOOTH;
+import static android.Manifest.permission.BLUETOOTH_ADMIN;
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_SCAN;
+import static android.Manifest.permission.BODY_SENSORS;
+import static android.Manifest.permission.BODY_SENSORS_BACKGROUND;
+import static android.Manifest.permission.READ_CALL_LOG;
+import static android.Manifest.permission.READ_CONTACTS;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.READ_MEDIA_AUDIO;
+import static android.Manifest.permission.READ_MEDIA_IMAGES;
+import static android.Manifest.permission.READ_MEDIA_VIDEO;
+import static android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.Manifest.permission.WRITE_CALL_LOG;
+import static android.Manifest.permission.WRITE_CONTACTS;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.os.Build;
+import android.permission.PermissionManager;
+import android.permission.PermissionManager.SplitPermissionInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiLevelUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+public class SplitPermissionsSystemTest {
+
+ private static final int NO_TARGET = Build.VERSION_CODES.CUR_DEVELOPMENT + 1;
+
+ private List<SplitPermissionInfo> mSplitPermissions;
+
+ @Before
+ public void before() {
+ Context context = InstrumentationRegistry.getContext();
+ PermissionManager permissionManager = (PermissionManager) context.getSystemService(
+ Context.PERMISSION_SERVICE);
+ mSplitPermissions = permissionManager.getSplitPermissions();
+ }
+
+ @Test
+ public void validateAndroidSystem() {
+ assumeTrue(ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q));
+
+ Set<SplitPermissionInfo> seenSplits = new HashSet<>(6);
+
+ for (SplitPermissionInfo split : mSplitPermissions) {
+ String splitPermission = split.getSplitPermission();
+ boolean isAndroid = splitPermission.startsWith("android");
+
+ if (!isAndroid) {
+ continue;
+ }
+
+ assertThat(seenSplits).doesNotContain(split);
+ seenSplits.add(split);
+
+ List<String> newPermissions = split.getNewPermissions();
+
+ switch (splitPermission) {
+ case ACCESS_FINE_LOCATION:
+ // Q declares multiple for ACCESS_FINE_LOCATION, so assert both exist
+ if (newPermissions.contains(ACCESS_COARSE_LOCATION)) {
+ assertSplit(split, NO_TARGET, ACCESS_COARSE_LOCATION);
+ } else {
+ assertSplit(split, Build.VERSION_CODES.Q, ACCESS_BACKGROUND_LOCATION);
+ }
+ break;
+ case WRITE_EXTERNAL_STORAGE:
+ if (newPermissions.contains(READ_EXTERNAL_STORAGE)) {
+ assertSplit(split, NO_TARGET, READ_EXTERNAL_STORAGE);
+ } else if (newPermissions.contains(ACCESS_MEDIA_LOCATION)) {
+ assertSplit(split, Build.VERSION_CODES.Q, ACCESS_MEDIA_LOCATION);
+ } else if (newPermissions.contains(READ_MEDIA_AUDIO)) {
+ assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_AUDIO);
+ } else if (newPermissions.contains(READ_MEDIA_VIDEO)) {
+ assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_VIDEO);
+ } else if (newPermissions.contains(READ_MEDIA_IMAGES)) {
+ assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_IMAGES);
+ }
+ break;
+ case READ_CONTACTS:
+ assertSplit(split, Build.VERSION_CODES.JELLY_BEAN, READ_CALL_LOG);
+ break;
+ case WRITE_CONTACTS:
+ assertSplit(split, Build.VERSION_CODES.JELLY_BEAN, WRITE_CALL_LOG);
+ break;
+ case ACCESS_COARSE_LOCATION:
+ assertSplit(split, Build.VERSION_CODES.Q, ACCESS_BACKGROUND_LOCATION);
+ break;
+ case READ_EXTERNAL_STORAGE:
+ if (newPermissions.contains(ACCESS_MEDIA_LOCATION)) {
+ assertSplit(split, Build.VERSION_CODES.Q, ACCESS_MEDIA_LOCATION);
+ } else if (newPermissions.contains(READ_MEDIA_AUDIO)) {
+ assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_AUDIO);
+ } else if (newPermissions.contains(READ_MEDIA_VIDEO)) {
+ assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_VIDEO);
+ } else if (newPermissions.contains(READ_MEDIA_IMAGES)) {
+ assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_IMAGES);
+ }
+ break;
+ case READ_PRIVILEGED_PHONE_STATE:
+ assertSplit(split, NO_TARGET, READ_PHONE_STATE);
+ break;
+ case BLUETOOTH_CONNECT:
+ assertSplit(split, Build.VERSION_CODES.S, BLUETOOTH, BLUETOOTH_ADMIN);
+ break;
+ case BLUETOOTH_SCAN:
+ assertSplit(split, Build.VERSION_CODES.S, BLUETOOTH, BLUETOOTH_ADMIN);
+ break;
+ case BODY_SENSORS:
+ assertSplit(split, Build.VERSION_CODES.TIRAMISU, BODY_SENSORS_BACKGROUND);
+ break;
+ case ACCESS_MEDIA_LOCATION:
+ case READ_MEDIA_IMAGES:
+ case READ_MEDIA_VIDEO:
+ assertSplit(split, READ_MEDIA_VISUAL_USER_SELECTED);
+ break;
+ }
+ }
+
+ assertEquals(24, seenSplits.size());
+ }
+
+ private void assertSplit(SplitPermissionInfo split, int targetSdk, String... permission) {
+ assertThat(split.getNewPermissions()).containsExactlyElementsIn(permission);
+ assertThat(split.getTargetSdk()).isEqualTo(targetSdk);
+ }
+
+ private void assertSplit(SplitPermissionInfo split, String... permission) {
+ assertThat(split.getNewPermissions()).containsExactlyElementsIn(permission);
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/StorageEscalationTest.kt b/tests/cts/permission/src/android/permission/cts/StorageEscalationTest.kt
new file mode 100644
index 000000000..2458baeb2
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/StorageEscalationTest.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.Manifest.permission.ACCESS_MEDIA_LOCATION
+import android.Manifest.permission.READ_EXTERNAL_STORAGE
+import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+import android.app.Instrumentation
+import android.app.UiAutomation
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Process
+import android.os.UserHandle
+import android.platform.test.annotations.AppModeFull
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assert.assertTrue
+import org.junit.Assume.assumeNoException
+import org.junit.Before
+import org.junit.Test
+
+@AppModeFull
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class StorageEscalationTest {
+ companion object {
+ private const val APK_DIRECTORY = "/data/local/tmp/cts-permission"
+ const val APP_APK_PATH_28 = "$APK_DIRECTORY/CtsStorageEscalationApp28.apk"
+ const val APP_APK_PATH_29_SCOPED = "$APK_DIRECTORY/CtsStorageEscalationApp29Scoped.apk"
+ const val APP_APK_PATH_29_FULL = "$APK_DIRECTORY/CtsStorageEscalationApp29Full.apk"
+ const val APP_PACKAGE_NAME = "android.permission.cts.storageescalation"
+ const val DELAY_TIME_MS: Long = 200
+ val permissions =
+ listOf<String>(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, ACCESS_MEDIA_LOCATION)
+ }
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context: Context = instrumentation.context
+ private val uiAutomation: UiAutomation = instrumentation.uiAutomation
+ private var secondaryUserId: Int? = null
+
+ @Before
+ @After
+ fun uninstallApp() {
+ SystemUtil.runShellCommand("pm uninstall $APP_PACKAGE_NAME --user ALL")
+ }
+
+ private fun installPackage(apk: String) {
+ var userString = ""
+ secondaryUserId?.let { userId -> userString = " --user $userId" }
+ val result = SystemUtil.runShellCommandOrThrow("pm install -r$userString $apk")
+ assertTrue(
+ "Expected output to contain \"Success\", but was \"$result\"",
+ result.contains("Success")
+ )
+ }
+
+ private fun createSecondaryUser() {
+ val createUserOutput: String = SystemUtil.runShellCommand("pm create-user secondary")
+ var formatException: Exception? = null
+ val userId =
+ try {
+ createUserOutput.split(" id ".toRegex())[1].trim { it <= ' ' }.toInt()
+ } catch (e: Exception) {
+ formatException = e
+ -1
+ }
+ assumeNoException("Failed to parse userId from $createUserOutput", formatException)
+ SystemUtil.runShellCommand("am start-user -w $userId")
+ secondaryUserId = userId
+ }
+
+ @After
+ fun removeSecondaryUser() {
+ secondaryUserId?.let { userId ->
+ SystemUtil.runShellCommand("pm remove-user $userId")
+ secondaryUserId = null
+ }
+ }
+
+ private fun grantStoragePermissions() {
+ for (permName in permissions) {
+ var user = Process.myUserHandle()
+ secondaryUserId?.let { user = UserHandle.of(it) }
+ uiAutomation.grantRuntimePermissionAsUser(APP_PACKAGE_NAME, permName, user)
+ }
+ }
+
+ private fun assertStoragePermissionState(granted: Boolean) {
+ for (permName in permissions) {
+ var userContext = context
+ secondaryUserId?.let { userId ->
+ SystemUtil.runWithShellPermissionIdentity {
+ userContext =
+ context.createPackageContextAsUser(
+ APP_PACKAGE_NAME,
+ 0,
+ UserHandle.of(userId)
+ )
+ }
+ }
+ Assert.assertEquals(
+ granted,
+ userContext.packageManager.checkPermission(permName, APP_PACKAGE_NAME) ==
+ PackageManager.PERMISSION_GRANTED
+ )
+ }
+ }
+
+ @Test
+ fun testCannotEscalateWithSdkDowngrade() {
+ runStorageEscalationTest(APP_APK_PATH_29_SCOPED, APP_APK_PATH_28)
+ }
+
+ @Test
+ fun testCannotEscalateWithNewManifestLegacyRequest() {
+ runStorageEscalationTest(APP_APK_PATH_29_SCOPED, APP_APK_PATH_29_FULL)
+ }
+
+ @Test
+ fun testCannotEscalateWithSdkDowngradeSecondary() {
+ createSecondaryUser()
+ runStorageEscalationTest(APP_APK_PATH_29_SCOPED, APP_APK_PATH_28)
+ }
+
+ @Test
+ fun testCannotEscalateWithNewManifestLegacyRequestSecondary() {
+ createSecondaryUser()
+ runStorageEscalationTest(APP_APK_PATH_29_SCOPED, APP_APK_PATH_29_FULL)
+ }
+
+ private fun runStorageEscalationTest(startPackageApk: String, finishPackageApk: String) {
+ installPackage(startPackageApk)
+ grantStoragePermissions()
+ assertStoragePermissionState(granted = true)
+ installPackage(finishPackageApk)
+ // permission revoke is async, so wait a short period
+ Thread.sleep(DELAY_TIME_MS)
+ assertStoragePermissionState(granted = false)
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/TvPermissionTest.java b/tests/cts/permission/src/android/permission/cts/TvPermissionTest.java
new file mode 100644
index 000000000..e61b2667d
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/TvPermissionTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.ContentValues;
+import android.content.pm.PackageManager;
+import android.media.tv.TvContract;
+import android.net.Uri;
+import android.platform.test.annotations.AppModeFull;
+import android.test.AndroidTestCase;
+
+/**
+ * Tests for TV API related permissions.
+ */
+public class TvPermissionTest extends AndroidTestCase {
+ private static final String DUMMY_INPUT_ID = "dummy";
+
+ private boolean mHasTvInputFramework;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mHasTvInputFramework = getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_LIVE_TV);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void verifyInsert(Uri uri, String tableName) throws Exception {
+ try {
+ ContentValues values = new ContentValues();
+ getContext().getContentResolver().insert(uri, values);
+ fail("Accessing " + tableName + " table should require WRITE_EPG_DATA permission.");
+ } catch (SecurityException e) {
+ // Expected exception
+ } catch (IllegalArgumentException e) {
+ // TvProvider is not visable for instant app
+ }
+ }
+
+ public void verifyUpdate(Uri uri, String tableName) throws Exception {
+ try {
+ ContentValues values = new ContentValues();
+ getContext().getContentResolver().update(uri, values, null, null);
+ fail("Accessing " + tableName + " table should require WRITE_EPG_DATA permission.");
+ } catch (SecurityException e) {
+ // Expected exception
+ } catch (IllegalArgumentException e) {
+ // TvProvider is not visable for instant app
+ }
+ }
+
+ public void verifyDelete(Uri uri, String tableName) throws Exception {
+ try {
+ getContext().getContentResolver().delete(uri, null, null);
+ fail("Accessing " + tableName + " table should require WRITE_EPG_DATA permission.");
+ } catch (SecurityException e) {
+ // Expected exception
+ } catch (IllegalArgumentException e) {
+ // TvProvider is not visable for instant app
+ }
+ }
+
+ @AppModeFull
+ public void testInsertChannels() throws Exception {
+ if (!mHasTvInputFramework) return;
+ verifyInsert(TvContract.Channels.CONTENT_URI, "channels");
+ }
+
+ @AppModeFull
+ public void testUpdateChannels() throws Exception {
+ if (!mHasTvInputFramework) return;
+ verifyUpdate(TvContract.Channels.CONTENT_URI, "channels");
+ }
+
+ @AppModeFull
+ public void testDeleteChannels() throws Exception {
+ if (!mHasTvInputFramework) return;
+ verifyDelete(TvContract.Channels.CONTENT_URI, "channels");
+ }
+
+ @AppModeFull
+ public void testInsertPrograms() throws Exception {
+ if (!mHasTvInputFramework) return;
+ verifyInsert(TvContract.Programs.CONTENT_URI, "programs");
+ }
+
+ @AppModeFull
+ public void testUpdatePrograms() throws Exception {
+ if (!mHasTvInputFramework) return;
+ verifyUpdate(TvContract.Programs.CONTENT_URI, "programs");
+ }
+
+ @AppModeFull
+ public void testDeletePrograms() throws Exception {
+ if (!mHasTvInputFramework) return;
+ verifyDelete(TvContract.Programs.CONTENT_URI, "programs");
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt b/tests/cts/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
new file mode 100644
index 000000000..4414402ff
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permission.cts
+
+import android.Manifest.permission.CAMERA
+import android.Manifest.permission.RECORD_AUDIO
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Process
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.UiObjectNotFoundException
+import com.android.compatibility.common.util.SystemUtil
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
+import java.util.regex.Pattern
+import org.junit.After
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+
+/**
+ * Tests that the permissioncontroller behaves normally when an app defines a permission in the
+ * android.permission-group.UNDEFINED group
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class UndefinedGroupPermissionTest {
+ private var mInstrumentation: Instrumentation? = null
+ private var mUiDevice: UiDevice? = null
+ private var mContext: Context? = null
+ private var mPm: PackageManager? = null
+ private var mAllowButtonText: Pattern? = null
+ private var mDenyButtonText: Pattern? = null
+
+ @Before
+ fun install() {
+ SystemUtil.runShellCommand("pm uninstall $APP_PKG_NAME")
+ SystemUtil.runShellCommandOrThrow(
+ "pm install -r " + TEST_APP_DEFINES_UNDEFINED_PERMISSION_GROUP_ELEMENT_APK
+ )
+ }
+
+ @Before
+ fun setup() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation()
+ mUiDevice = UiDevice.getInstance(mInstrumentation!!)
+ mContext = mInstrumentation?.targetContext
+ mPm = mContext?.packageManager
+ val permissionControllerResources =
+ mContext
+ ?.createPackageContext(mContext?.packageManager?.permissionControllerPackageName, 0)
+ ?.resources
+ mAllowButtonText =
+ Pattern.compile(
+ Pattern.quote(
+ requireNotNull(
+ permissionControllerResources?.getString(
+ permissionControllerResources.getIdentifier(
+ "grant_dialog_button_allow",
+ "string",
+ "com.android.permissioncontroller"
+ )
+ )
+ )
+ ),
+ Pattern.CASE_INSENSITIVE or Pattern.UNICODE_CASE
+ )
+ mDenyButtonText =
+ Pattern.compile(
+ Pattern.quote(
+ requireNotNull(
+ permissionControllerResources?.getString(
+ permissionControllerResources.getIdentifier(
+ "grant_dialog_button_deny",
+ "string",
+ "com.android.permissioncontroller"
+ )
+ )
+ )
+ ),
+ Pattern.CASE_INSENSITIVE or Pattern.UNICODE_CASE
+ )
+ }
+
+ @Before
+ fun wakeUpScreenAndUnlock() {
+ SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP")
+ SystemUtil.runShellCommand("input keyevent KEYCODE_MENU")
+ }
+
+ @Test
+ fun testOtherGroupPermissionsNotGranted_1() {
+ testOtherGroupPermissionsNotGranted(CAMERA, RECORD_AUDIO)
+ }
+
+ @Test
+ fun testOtherGroupPermissionsNotGranted_2() {
+ testOtherGroupPermissionsNotGranted(TEST, RECORD_AUDIO)
+ }
+
+ @Test
+ fun testOtherGroupPermissionsNotGranted_3() {
+ testOtherGroupPermissionsNotGranted(CAMERA, TEST)
+ }
+
+ /** When the custom permission is granted nothing else gets granted as a byproduct. */
+ @Test
+ fun testCustomPermissionGrantedAlone() {
+ Assert.assertEquals(
+ PackageManager.PERMISSION_DENIED,
+ mPm!!.checkPermission(CAMERA, APP_PKG_NAME)
+ )
+ Assert.assertEquals(
+ PackageManager.PERMISSION_DENIED,
+ mPm!!.checkPermission(RECORD_AUDIO, APP_PKG_NAME)
+ )
+ Assert.assertEquals(
+ PackageManager.PERMISSION_DENIED,
+ mPm!!.checkPermission(TEST, APP_PKG_NAME)
+ )
+ eventually {
+ startRequestActivity(arrayOf(TEST))
+ mUiDevice!!.waitForIdle()
+ Thread.sleep(2000)
+ findAllowButton().click()
+ }
+ eventually {
+ Assert.assertEquals(
+ PackageManager.PERMISSION_DENIED,
+ mPm!!.checkPermission(CAMERA, APP_PKG_NAME)
+ )
+ Assert.assertEquals(
+ PackageManager.PERMISSION_DENIED,
+ mPm!!.checkPermission(RECORD_AUDIO, APP_PKG_NAME)
+ )
+ Assert.assertEquals(
+ PackageManager.PERMISSION_GRANTED,
+ mPm!!.checkPermission(TEST, APP_PKG_NAME)
+ )
+ }
+ }
+
+ @After
+ fun uninstall() {
+ SystemUtil.runShellCommand("pm uninstall $APP_PKG_NAME")
+ }
+
+ fun findAllowButton(): UiObject2 {
+ return if (
+ mContext?.packageManager?.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) == true
+ ) {
+ waitFindObject(By.text(mAllowButtonText!!), 2000)
+ } else {
+ waitFindObject(
+ By.res("com.android.permissioncontroller:id/permission_allow_button"),
+ 2000
+ )
+ }
+ }
+
+ /**
+ * If app has one permission granted, then it can't grant itself another permission for free.
+ */
+ fun testOtherGroupPermissionsNotGranted(grantedPerm: String, targetPermission: String) {
+ // Grant the permission in the background
+ SystemUtil.runWithShellPermissionIdentity {
+ mPm!!.grantRuntimePermission(APP_PKG_NAME, grantedPerm, Process.myUserHandle())
+ }
+ Assert.assertEquals(
+ "$grantedPerm not granted.",
+ PackageManager.PERMISSION_GRANTED,
+ mPm!!.checkPermission(grantedPerm, APP_PKG_NAME)
+ )
+
+ // If the dialog shows, success. If not then either the UI is broken or the permission was
+ // granted in the background.
+ eventually {
+ startRequestActivity(arrayOf(targetPermission))
+ mUiDevice!!.waitForIdle()
+ try {
+ if (
+ mContext?.packageManager?.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) ==
+ true
+ ) {
+ waitFindObject(By.text(mDenyButtonText!!), 2000)
+ } else if (
+ mContext?.packageManager?.hasSystemFeature(PackageManager.FEATURE_WATCH) == true
+ ) {
+ waitFindObject(By.res(ALLOW_BUTTON), 2000)
+ } else {
+ waitFindObject(By.res(GRANT_DIALOG), 2000)
+ }
+ } catch (e: UiObjectNotFoundException) {
+ Assert.assertEquals(
+ "grant dialog never showed.",
+ PackageManager.PERMISSION_GRANTED,
+ mPm!!.checkPermission(targetPermission, APP_PKG_NAME)
+ )
+ }
+ }
+ Assert.assertEquals(
+ PackageManager.PERMISSION_DENIED,
+ mPm!!.checkPermission(targetPermission, APP_PKG_NAME)
+ )
+ }
+
+ private fun startRequestActivity(permissions: Array<String>) {
+ mContext!!.startActivity(
+ Intent()
+ .setComponent(ComponentName(APP_PKG_NAME, "$APP_PKG_NAME.RequestPermissions"))
+ .putExtra(EXTRA_PERMISSIONS, permissions)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ )
+ }
+
+ companion object {
+ private const val TEST_APP_DEFINES_UNDEFINED_PERMISSION_GROUP_ELEMENT_APK =
+ "/data/local/tmp/cts-permission/AppThatDefinesUndefinedPermissionGroupElement.apk"
+ private const val APP_PKG_NAME = "android.permission.cts.appthatrequestpermission"
+ private const val EXTRA_PERMISSIONS =
+ "android.permission.cts.appthatrequestpermission.extra.PERMISSIONS"
+ private const val GRANT_DIALOG = "com.android.permissioncontroller:id/grant_dialog"
+ private const val ALLOW_BUTTON =
+ "com.android.permissioncontroller:id/permission_allow_button"
+ const val TEST = "android.permission.cts.appthatrequestpermission.TEST"
+ }
+}
diff --git a/tests/cts/permission/src/android/permission/cts/appthataccesseslocation/IAccessLocationOnCommand.aidl b/tests/cts/permission/src/android/permission/cts/appthataccesseslocation/IAccessLocationOnCommand.aidl
new file mode 100644
index 000000000..be92ed160
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/appthataccesseslocation/IAccessLocationOnCommand.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthataccesseslocation;
+
+interface IAccessLocationOnCommand {
+ /** Access location on command */
+ void accessLocation();
+} \ No newline at end of file
diff --git a/tests/cts/permission/telephony/Android.bp b/tests/cts/permission/telephony/Android.bp
new file mode 100644
index 000000000..5ded57ab3
--- /dev/null
+++ b/tests/cts/permission/telephony/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsPermissionTestCasesTelephony",
+ defaults: ["cts_defaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "mcts-permission",
+ ],
+ // Include both the 32 and 64 bit versions
+ compile_multilib: "both",
+ static_libs: [
+ "ctstestrunner-axt",
+ "compatibility-device-util-axt",
+ ],
+ srcs: ["src/**/*.java"],
+ sdk_version: "test_current",
+}
diff --git a/tests/cts/permission/telephony/AndroidManifest.xml b/tests/cts/permission/telephony/AndroidManifest.xml
new file mode 100644
index 000000000..0349880e2
--- /dev/null
+++ b/tests/cts/permission/telephony/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.telephony" android:targetSandboxVersion="2">
+
+ <!--
+ The CTS stubs package cannot be used as the target application here,
+ since that requires many permissions to be set. Instead, specify this
+ package itself as the target and include any stub activities needed.
+
+ This test package uses the default InstrumentationTestRunner, because
+ the InstrumentationCtsTestRunner is only available in the stubs
+ package. That runner cannot be added to this package either, since it
+ relies on hidden APIs.
+ -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.permission.cts.telephony"
+ android:label="CTS tests of android.permission">
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/cts/permission/telephony/AndroidTest.xml b/tests/cts/permission/telephony/AndroidTest.xml
new file mode 100644
index 000000000..13ee78bcc
--- /dev/null
+++ b/tests/cts/permission/telephony/AndroidTest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Telephony Permission test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+
+ <!-- Telephony permission tests do not use any permission not available to instant apps. -->
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <option name="config-descriptor:metadata" key="parameter" value="run_on_sdk_sandbox" />
+
+ <!-- Disable package verifier before installing APKs -->
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+
+ <!-- Install main test suite apk -->
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPermissionTestCasesTelephony.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.permission.cts.telephony" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+</configuration>
diff --git a/tests/cts/permission/telephony/OWNERS b/tests/cts/permission/telephony/OWNERS
new file mode 100644
index 000000000..446cf1a00
--- /dev/null
+++ b/tests/cts/permission/telephony/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+# Bug component: 20868
+include platform/cts:/tests/tests/telephony/OWNERS \ No newline at end of file
diff --git a/tests/cts/permission/telephony/src/android/permission/cts/telephony/TelephonyManagerPermissionTest.java b/tests/cts/permission/telephony/src/android/permission/cts/telephony/TelephonyManagerPermissionTest.java
new file mode 100644
index 000000000..3605be21a
--- /dev/null
+++ b/tests/cts/permission/telephony/src/android/permission/cts/telephony/TelephonyManagerPermissionTest.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.telephony;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Test the non-location-related functionality of TelephonyManager.
+ */
+@RunWith(AndroidJUnit4.class)
+public class TelephonyManagerPermissionTest {
+
+ private boolean mHasTelephony;
+ TelephonyManager mTelephonyManager = null;
+ private AudioManager mAudioManager;
+
+ @Before
+ public void setUp() throws Exception {
+ mHasTelephony = getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY);
+ mTelephonyManager =
+ (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
+ assertNotNull(mTelephonyManager);
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+ assertNotNull(mAudioManager);
+ }
+
+ /**
+ * Verify that TelephonyManager.getDeviceId requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void testGetDeviceId() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ String id = mTelephonyManager.getDeviceId();
+ fail("Got device ID: " + id);
+ } catch (SecurityException e) {
+ // expected
+ }
+ try {
+ String id = mTelephonyManager.getDeviceId(0);
+ fail("Got device ID: " + id);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that TelephonyManager.getLine1Number requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void testGetLine1Number() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ String nmbr = mTelephonyManager.getLine1Number();
+ fail("Got line 1 number: " + nmbr);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that TelephonyManager.getSimSerialNumber requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void testGetSimSerialNumber() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ String nmbr = mTelephonyManager.getSimSerialNumber();
+ fail("Got SIM serial number: " + nmbr);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that TelephonyManager.getSubscriberId requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void testGetSubscriberId() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ String sid = mTelephonyManager.getSubscriberId();
+ fail("Got subscriber id: " + sid);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that TelephonyManager.getVoiceMailNumber requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void testVoiceMailNumber() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ String vmnum = mTelephonyManager.getVoiceMailNumber();
+ fail("Got voicemail number: " + vmnum);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+ /**
+ * Verify that AudioManager.setMode requires Permission.
+ * <p>
+ * Requires Permissions:
+ * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} and
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE} for
+ * {@link AudioManager#MODE_IN_CALL}.
+ */
+ @Test
+ public void testSetMode() {
+ if (!mHasTelephony) {
+ return;
+ }
+ int audioMode = mAudioManager.getMode();
+ mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+ assertEquals(audioMode, mAudioManager.getMode());
+ }
+
+ /**
+ * Tests that isManualNetworkSelectionAllowed requires permission
+ * Expects a security exception since the caller does not have carrier privileges.
+ */
+ @Test
+ public void testIsManualNetworkSelectionAllowedWithoutPermission() {
+ if (!mHasTelephony) {
+ return;
+ }
+ try {
+ mTelephonyManager.isManualNetworkSelectionAllowed();
+ fail("Expected SecurityException. App does not have carrier privileges.");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ /**
+ * Tests that getManualNetworkSelectionPlmn requires permission
+ * Expects a security exception since the caller does not have carrier privileges.
+ */
+ @Test
+ public void testGetManualNetworkSelectionPlmnWithoutPermission() {
+ if (!mHasTelephony) {
+ return;
+ }
+ try {
+ mTelephonyManager.getManualNetworkSelectionPlmn();
+ fail("Expected SecurityException. App does not have carrier privileges.");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ /**
+ * Verify that Telephony related broadcasts are protected.
+ */
+ @Test
+ public void testProtectedBroadcasts() {
+ if (!mHasTelephony) {
+ return;
+ }
+ try {
+ Intent intent = new Intent("android.intent.action.SIM_STATE_CHANGED");
+ getContext().sendBroadcast(intent);
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {}
+ try {
+ Intent intent = new Intent("android.intent.action.SERVICE_STATE");
+ getContext().sendBroadcast(intent);
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {}
+ try {
+ Intent intent = new Intent("android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED");
+ getContext().sendBroadcast(intent);
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {}
+ try {
+ Intent intent = new Intent(
+ "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED");
+ getContext().sendBroadcast(intent);
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {}
+ try {
+ Intent intent = new Intent(
+ "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED");
+ getContext().sendBroadcast(intent);
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {}
+ try {
+ Intent intent = new Intent(
+ "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED");
+ getContext().sendBroadcast(intent);
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {}
+ try {
+ Intent intent = new Intent("android.intent.action.SIG_STR");
+ getContext().sendBroadcast(intent);
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {}
+ try {
+ Intent intent = new Intent("android.provider.Telephony.SECRET_CODE");
+ getContext().sendBroadcast(intent);
+ fail("SecurityException expected!");
+ } catch (SecurityException e) {}
+ }
+
+ /**
+ * Verify that TelephonyManager.getImei requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void testGetImei() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ String imei = mTelephonyManager.getImei();
+ fail("Got IMEI: " + imei);
+ } catch (SecurityException e) {
+ // expected
+ }
+ try {
+ String imei = mTelephonyManager.getImei(0);
+ fail("Got IMEI: " + imei);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that getNetworkType and getDataNetworkType requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void testGetNetworkType() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ mTelephonyManager.getNetworkType();
+ fail("getNetworkType did not throw a SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ mTelephonyManager.getDataNetworkType();
+ fail("getDataNetworkType did not throw a SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Tests that getNetworkSelectionMode requires permission
+ * Expects a security exception since the caller does not have carrier privileges.
+ */
+ @Test
+ public void testGetNetworkSelectionModeWithoutPermission() {
+ if (!mHasTelephony) {
+ return;
+ }
+ assertThrowsSecurityException(() -> mTelephonyManager.getNetworkSelectionMode(),
+ "Expected SecurityException. App does not have carrier privileges.");
+ }
+
+ /**
+ * Tests that setNetworkSelectionModeAutomatic requires permission
+ * Expects a security exception since the caller does not have carrier privileges.
+ */
+ @Test
+ public void testSetNetworkSelectionModeAutomaticWithoutPermission() {
+ if (!mHasTelephony) {
+ return;
+ }
+ assertThrowsSecurityException(() -> mTelephonyManager.setNetworkSelectionModeAutomatic(),
+ "Expected SecurityException. App does not have carrier privileges.");
+ }
+
+ /**
+ * Verify that setForbiddenPlmns requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ */
+ @Test
+ public void testSetForbiddenPlmns() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ mTelephonyManager.setForbiddenPlmns(new ArrayList<String>());
+ fail("SetForbiddenPlmns did not throw a SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ static final int PHONE_STATE_PERMISSION_MASK =
+ PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
+ | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
+ | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
+
+ static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
+ PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
+ | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
+ | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
+ | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
+ | PhoneStateListener.LISTEN_BARRING_INFO;
+
+ static final int PHONE_PERMISSIONS_MASK =
+ PHONE_STATE_PERMISSION_MASK | PRECISE_PHONE_STATE_PERMISSION_MASK;
+
+ /**
+ * Verify the documented permissions for PhoneStateListener.
+ */
+ @Test
+ public void testListen() {
+ PhoneStateListener psl = new PhoneStateListener((Runnable r) -> { });
+
+ try {
+ for (int i = 1; i != 0; i = i << 1) {
+ if ((i & PHONE_PERMISSIONS_MASK) == 0) continue;
+ final int listenBit = i;
+ assertThrowsSecurityException(() -> mTelephonyManager.listen(psl, listenBit),
+ "Expected a security exception for " + Integer.toHexString(i));
+ }
+ } finally {
+ mTelephonyManager.listen(psl, PhoneStateListener.LISTEN_NONE);
+ }
+ }
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
+ // An actual version of assertThrows() was added in JUnit5
+ private static <T extends Throwable> void assertThrows(Class<T> clazz, Runnable r,
+ String message) {
+ try {
+ r.run();
+ } catch (Exception expected) {
+ assertTrue(clazz.isAssignableFrom(expected.getClass()));
+ return;
+ }
+ fail(message);
+ }
+
+ private static void assertThrowsSecurityException(Runnable r, String message) {
+ assertThrows(SecurityException.class, r, message);
+ }
+
+ /**
+ * Verify that TelephonyManager.getPrimaryImei requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}.
+ */
+ @Test
+ public void testGetPrimaryImei() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ try {
+ String primaryImei = mTelephonyManager.getPrimaryImei();
+ fail("Received Primary Imei value: " + primaryImei);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that getCarrierRestrictionStatus requires permission
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void getCarrierRestrictionStatus_Exception() {
+ if (!mHasTelephony) {
+ return;
+ }
+ LinkedBlockingQueue<Integer> carrierRestrictionStatusResult = new LinkedBlockingQueue<>(1);
+ try {
+ mTelephonyManager.getCarrierRestrictionStatus(getContext().getMainExecutor(),
+ carrierRestrictionStatusResult::offer);
+ // Test case fail, if the API don't catch the security exception.
+ fail();
+ } catch (SecurityException ex) {
+ // expecting the security exception.
+ } catch (Exception ex) {
+ // The test case should fail if other than security exception comes.
+ fail();
+ }
+ }
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp
new file mode 100644
index 000000000..6f0bcf111
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAdversarialPermissionDefinerApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ certificate: ":cts-testkey1",
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/AndroidManifest.xml
new file mode 100644
index 000000000..d28fba87c
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.AdversarialPermissionDefinerApp">
+
+ <permission android:name="android.permission.cts.revokepermissionwhenremoved.TestPermission"
+ android:protectionLevel="dangerous"
+ android:label="TestPermission"
+ android:description="@string/test_permission" />
+
+ <application>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/res/values/strings.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/res/values/strings.xml
new file mode 100644
index 000000000..bfb3e1e2b
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="test_permission">Test Permission</string>
+</resources>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp
new file mode 100644
index 000000000..41f01e981
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAdversarialPermissionUserApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ certificate: ":cts-testkey2",
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/AndroidManifest.xml
new file mode 100644
index 000000000..f514d549a
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.userapp">
+
+ <uses-permission android:name="android.permission.cts.revokepermissionwhenremoved.TestPermission" />
+
+ <application>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp
new file mode 100644
index 000000000..a3e1f13d2
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsInstallPermissionDefinerApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+ certificate: ":cts-testkey1",
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/AndroidManifest.xml
new file mode 100644
index 000000000..2df67431b
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.installpermissiondefinerapp">
+
+ <permission
+ android:name="android.permission.cts.revokepermissionwhenremoved.TestInstallPermission"
+ android:protectionLevel="normal" />
+
+ <application />
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp
new file mode 100644
index 000000000..caaa8e898
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsInstallPermissionEscalatorApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+ certificate: ":cts-testkey1",
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/AndroidManifest.xml
new file mode 100644
index 000000000..6320618c5
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.installpermissionescalatorapp">
+
+ <permission
+ android:name="android.permission.cts.revokepermissionwhenremoved.TestInstallPermission"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="dangerous" />
+
+ <application />
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp
new file mode 100644
index 000000000..d9ca4c8ea
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsInstallPermissionUserApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+ certificate: ":cts-testkey2",
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/AndroidManifest.xml
new file mode 100644
index 000000000..acfafa986
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.installpermissionuserapp">
+
+ <uses-permission android:name="android.permission.cts.revokepermissionwhenremoved.TestInstallPermission" />
+
+ <application />
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/AndroidManifest.xml
new file mode 100644
index 000000000..7a0e40554
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.installtimepermissionuserapp">
+
+ <uses-permission android:name="android.permission.cts.revokepermissionwhenremoved.TestInstalltimePermission" />
+
+ <application>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp
new file mode 100644
index 000000000..b4ea30ada
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsRuntimePermissionDefinerApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+ certificate: ":cts-testkey1",
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/AndroidManifest.xml
new file mode 100644
index 000000000..d3cf6d0aa
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.runtimepermissiondefinerapp">
+
+ <permission android:name="android.permission.cts.revokepermissionwhenremoved.TestRuntimePermission"
+ android:protectionLevel="dangerous"
+ android:label="TestPermission"
+ android:description="@string/test_permission" />
+
+ <application>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/res/values/strings.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/res/values/strings.xml
new file mode 100644
index 000000000..bfb3e1e2b
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="test_permission">Test Permission</string>
+</resources>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp
new file mode 100644
index 000000000..22c6ccd6f
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsRuntimePermissionUserApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+ certificate: ":cts-testkey2",
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/AndroidManifest.xml
new file mode 100644
index 000000000..d977e46e4
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.runtimepermissionuserapp">
+
+ <uses-permission android:name="android.permission.cts.revokepermissionwhenremoved.TestRuntimePermission" />
+
+ <application>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp
new file mode 100644
index 000000000..5627a3d36
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsVictimPermissionDefinerApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ certificate: ":cts-testkey1",
+}
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/AndroidManifest.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/AndroidManifest.xml
new file mode 100644
index 000000000..3fb0abd29
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.VictimPermissionDefinerApp">
+ <permission android:name="android.permission.cts.revokepermissionwhenremoved.TestPermission"
+ android:protectionLevel="signature"
+ android:label="Test Permission"
+ android:description="@string/test_permission" />
+ <application>
+ </application>
+</manifest>
diff --git a/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/res/values/strings.xml b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/res/values/strings.xml
new file mode 100644
index 000000000..bfb3e1e2b
--- /dev/null
+++ b/tests/cts/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="test_permission">Test Permission</string>
+</resources>
diff --git a/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/Android.bp b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/Android.bp
new file mode 100644
index 000000000..3651b6b7d
--- /dev/null
+++ b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAccessRemoteDeviceCamera",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ min_sdk_version: "34",
+ target_sdk_version: "35",
+}
diff --git a/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml
new file mode 100644
index 000000000..211e415bd
--- /dev/null
+++ b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionmultidevice.cts.accessremotedevicecamera">
+
+ <uses-permission android:name="android.permission.CAMERA" />
+
+ <application>
+ <activity android:name=".RequestPermissionActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt
new file mode 100644
index 000000000..773dfa778
--- /dev/null
+++ b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt
@@ -0,0 +1,22 @@
+package android.permissionmultidevice.cts.accessremotedevicecamera
+
+import android.Manifest
+import android.app.Activity
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Bundle
+
+class RequestPermissionActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val deviceId =
+ intent.getIntExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID,
+ Context.DEVICE_ID_DEFAULT
+ )
+
+ requestPermissions(arrayOf(Manifest.permission.CAMERA), 1001, deviceId)
+ }
+}
diff --git a/tests/cts/permissionmultidevice/Android.bp b/tests/cts/permissionmultidevice/Android.bp
new file mode 100644
index 000000000..61ac6541d
--- /dev/null
+++ b/tests/cts/permissionmultidevice/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsPermissionMultiDeviceTestCases",
+ defaults: ["mts-target-sdk-version-current"],
+ sdk_version: "test_current",
+ min_sdk_version: "30",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "modules-utils-build_system",
+ "cts-wm-util",
+ "flag-junit",
+ "android.companion.virtual.flags-aconfig-java",
+ "permission-test-util-lib",
+ "permission-multidevice-test-util-lib",
+ "android.permission.flags-aconfig-java",
+ ],
+ data: [
+ ":CtsAccessRemoteDeviceCamera",
+ ],
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/cts/permissionmultidevice/AndroidManifest.xml b/tests/cts/permissionmultidevice/AndroidManifest.xml
new file mode 100644
index 000000000..e7c993d57
--- /dev/null
+++ b/tests/cts/permissionmultidevice/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionmultidevice.cts">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.permissionmultidevice.cts"
+ android:label="CTS permission multi-device tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/cts/permissionmultidevice/AndroidTest.xml b/tests/cts/permissionmultidevice/AndroidTest.xml
new file mode 100644
index 000000000..2b43fd01c
--- /dev/null
+++ b/tests/cts/permissionmultidevice/AndroidTest.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Config for CTS permission multi-device test cases">
+
+ <option name="test-suite-tag" value="cts" />
+
+ <option name="config-descriptor:metadata" key="component" value="permissions" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="run_on_sdk_sandbox" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk34ModuleController" />
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ <option name="screen-always-on" value="on" />
+ <option name="disable-device-config-sync" value="true" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer">
+ <option name="flag-value"
+ value="permissions/com.android.permission.flags.device_aware_permission_grant=true"/>
+ <option name="flag-value"
+ value="virtual_devices/android.companion.virtual.flags.stream_permissions=true"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPermissionMultiDeviceTestCases.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="CtsAccessRemoteDeviceCamera.apk->/data/local/tmp/cts-permissionmultidevice/CtsAccessRemoteDeviceCamera.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="appops set android.permissionmultidevice.cts REQUEST_INSTALL_PACKAGES allow" />
+ <!-- disable DeprecatedAbi warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_abi_dialog 1" />
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1" />
+ <!-- Ensure all broadcasts are dispatched prior to running our tests, to make sure they
+ aren't polluted by `BOOT_COMPLETED` or similar broadcasts still being delivered, which
+ causes our `ActivityManager#waitForBroadcastIdle()` calls to timeout. -->
+ <option name="run-command" value="am wait-for-broadcast-idle" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
+ <!-- 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>
+
+ <!-- Create place to store apks -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/cts-permissionmultidevice" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/cts-permissionmultidevice"/>
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.permissionmultidevice.cts" />
+ <option name="runtime-hint" value="5m" />
+ </test>
+
+</configuration>
diff --git a/tests/cts/permissionmultidevice/OWNERS b/tests/cts/permissionmultidevice/OWNERS
new file mode 100644
index 000000000..fb6099cf7
--- /dev/null
+++ b/tests/cts/permissionmultidevice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 137825
+
+include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/tests/cts/permissionmultidevice/TEST_MAPPNG b/tests/cts/permissionmultidevice/TEST_MAPPNG
new file mode 100644
index 000000000..80a2cf2ce
--- /dev/null
+++ b/tests/cts/permissionmultidevice/TEST_MAPPNG
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsPermissionMultiDeviceTestCases"
+ }
+ ]
+}
diff --git a/tests/cts/permissionmultidevice/TestUtils/Android.bp b/tests/cts/permissionmultidevice/TestUtils/Android.bp
new file mode 100644
index 000000000..aeef5d134
--- /dev/null
+++ b/tests/cts/permissionmultidevice/TestUtils/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "permission-multidevice-test-util-lib",
+ sdk_version: "test_current",
+ min_sdk_version: "34",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "compatibility-device-util-axt",
+ "kotlinx-coroutines-android",
+ "CtsVirtualDeviceCommonLib",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ ],
+}
diff --git a/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/FakeVirtualDeviceRule.kt b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/FakeVirtualDeviceRule.kt
new file mode 100644
index 000000000..0eff95a3d
--- /dev/null
+++ b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/FakeVirtualDeviceRule.kt
@@ -0,0 +1,75 @@
+package android.permissionmultidevice.cts
+
+import android.companion.virtual.VirtualDeviceManager
+import android.companion.virtual.VirtualDeviceParams
+import android.content.Context
+import android.graphics.PixelFormat
+import android.hardware.display.DisplayManager
+import android.hardware.display.VirtualDisplayConfig
+import android.media.ImageReader
+import android.virtualdevice.cts.common.FakeAssociationRule
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import com.android.compatibility.common.util.SystemUtil
+import com.google.common.truth.Truth
+import org.junit.Assume
+
+/** A test rule that creates a virtual device for the duration of the test. */
+class FakeVirtualDeviceRule : FakeAssociationRule() {
+
+ private val imageReader =
+ ImageReader.newInstance(
+ /* width= */ DISPLAY_WIDTH,
+ /* height= */ DISPLAY_HEIGHT,
+ PixelFormat.RGBA_8888,
+ /* maxImages= */ 1
+ )
+
+ private lateinit var virtualDeviceManager: VirtualDeviceManager
+ lateinit var virtualDevice: VirtualDeviceManager.VirtualDevice
+ var virtualDisplayId: Int = -1
+
+ override fun before() {
+ // Call FakeAssociationRule#before() to create a CDM association to be used by VDM
+ super.before()
+
+ SystemUtil.callWithShellPermissionIdentity {
+ val virtualDeviceManager =
+ getApplicationContext<Context>().getSystemService(VirtualDeviceManager::class.java)
+ Assume.assumeNotNull(virtualDeviceManager)
+ this.virtualDeviceManager = virtualDeviceManager!!
+ virtualDevice =
+ virtualDeviceManager.createVirtualDevice(
+ associationInfo.id,
+ VirtualDeviceParams.Builder().build()
+ )
+ val display =
+ virtualDevice.createVirtualDisplay(
+ VirtualDisplayConfig.Builder("testDisplay", DISPLAY_WIDTH, DISPLAY_HEIGHT, 240)
+ .setSurface(imageReader.surface)
+ .setFlags(
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC or
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED or
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+ )
+ .build(),
+ Runnable::run,
+ null
+ )
+ Truth.assertThat(display).isNotNull()
+ virtualDisplayId = display!!.display.displayId
+ }
+ }
+
+ override fun after() {
+ // Call FakeAssociationRule#after() to remote CDM association
+ super.after()
+
+ SystemUtil.callWithShellPermissionIdentity { virtualDevice.close() }
+ imageReader.close()
+ }
+
+ companion object {
+ private const val DISPLAY_HEIGHT = 1920
+ private const val DISPLAY_WIDTH = 1080
+ }
+}
diff --git a/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PackageManagementUtils.kt b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PackageManagementUtils.kt
new file mode 100644
index 000000000..9294bcdd9
--- /dev/null
+++ b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PackageManagementUtils.kt
@@ -0,0 +1,38 @@
+package android.permissionmultidevice.cts
+
+import com.android.compatibility.common.util.SystemUtil
+import com.android.modules.utils.build.SdkLevel
+import org.junit.Assert
+
+object PackageManagementUtils {
+ fun installPackage(
+ apkPath: String,
+ reinstall: Boolean = false,
+ grantRuntimePermissions: Boolean = false,
+ expectSuccess: Boolean = true,
+ installSource: String? = null
+ ) {
+ val output =
+ SystemUtil.runShellCommandOrThrow(
+ "pm install${if (SdkLevel.isAtLeastU()) " --bypass-low-target-sdk-block" else ""} " +
+ "${if (reinstall) " -r" else ""}${
+ if (grantRuntimePermissions) " -g"
+ else ""
+ }${if (installSource != null) " -i $installSource" else ""} $apkPath"
+ )
+ .trim()
+
+ if (expectSuccess) {
+ Assert.assertEquals("Success", output)
+ } else {
+ Assert.assertNotEquals("Success", output)
+ }
+ }
+
+ fun uninstallPackage(packageName: String, requireSuccess: Boolean = true) {
+ val output = SystemUtil.runShellCommand("pm uninstall $packageName").trim()
+ if (requireSuccess) {
+ Assert.assertEquals("Success", output)
+ }
+ }
+}
diff --git a/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt
new file mode 100644
index 000000000..fa58fc9f7
--- /dev/null
+++ b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt
@@ -0,0 +1,32 @@
+package android.permissionmultidevice.cts
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.provider.Settings
+import org.junit.Assert
+
+object PermissionUtils {
+ fun assertAppHasPermissionForDevice(
+ context: Context,
+ packageName: String,
+ permissionName: String,
+ deviceId: Int,
+ expectPermissionGranted: Boolean
+ ) {
+ val checkPermissionResult =
+ context
+ .createDeviceContext(deviceId)
+ .packageManager
+ .checkPermission(permissionName, packageName)
+
+ if (expectPermissionGranted) {
+ Assert.assertEquals(PackageManager.PERMISSION_GRANTED, checkPermissionResult)
+ } else {
+ Assert.assertEquals(PackageManager.PERMISSION_DENIED, checkPermissionResult)
+ }
+ }
+
+ fun getHostDeviceName(context: Context): String {
+ return Settings.Global.getString(context.contentResolver, Settings.Global.DEVICE_NAME)
+ }
+}
diff --git a/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/UiAutomatorUtils.kt b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/UiAutomatorUtils.kt
new file mode 100644
index 000000000..f3b8eecbf
--- /dev/null
+++ b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/UiAutomatorUtils.kt
@@ -0,0 +1,56 @@
+package android.permissionmultidevice.cts
+
+import android.os.SystemClock
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.StaleObjectException
+import androidx.test.uiautomator.UiObject2
+import com.android.compatibility.common.util.UiAutomatorUtils2
+import com.google.common.truth.Truth
+
+object UiAutomatorUtils {
+ fun waitFindObject(selector: BySelector): UiObject2 {
+ return findObjectWithRetry({ t -> UiAutomatorUtils2.waitFindObject(selector, t) })!!
+ }
+
+ fun waitFindObject(selector: BySelector, timeoutMillis: Long): UiObject2 {
+ return findObjectWithRetry(
+ { t -> UiAutomatorUtils2.waitFindObject(selector, t) },
+ timeoutMillis
+ )!!
+ }
+
+ fun click(selector: BySelector, timeoutMillis: Long = 20_000) {
+ waitFindObject(selector, timeoutMillis).click()
+ }
+
+ fun findTextForView(selector: BySelector): String {
+ val timeoutMs = 10000L
+
+ var exception: Exception? = null
+ var view: UiObject2? = null
+ try {
+ view = waitFindObject(selector, timeoutMs)
+ } catch (e: Exception) {
+ exception = e
+ }
+ Truth.assertThat(exception).isNull()
+ Truth.assertThat(view).isNotNull()
+ return view!!.text
+ }
+
+ private fun findObjectWithRetry(
+ automatorMethod: (timeoutMillis: Long) -> UiObject2?,
+ timeoutMillis: Long = 20_000L
+ ): UiObject2? {
+ val startTime = SystemClock.elapsedRealtime()
+ return try {
+ automatorMethod(timeoutMillis)
+ } catch (e: StaleObjectException) {
+ val remainingTime = timeoutMillis - (SystemClock.elapsedRealtime() - startTime)
+ if (remainingTime <= 0) {
+ throw e
+ }
+ automatorMethod(remainingTime)
+ }
+ }
+}
diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt
new file mode 100644
index 000000000..09f4c7f08
--- /dev/null
+++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionmultidevice.cts
+
+import android.Manifest
+import android.app.ActivityOptions
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.permission.flags.Flags
+import android.permissionmultidevice.cts.PackageManagementUtils.installPackage
+import android.permissionmultidevice.cts.PackageManagementUtils.uninstallPackage
+import android.permissionmultidevice.cts.PermissionUtils.assertAppHasPermissionForDevice
+import android.permissionmultidevice.cts.PermissionUtils.getHostDeviceName
+import android.permissionmultidevice.cts.UiAutomatorUtils.click
+import android.permissionmultidevice.cts.UiAutomatorUtils.findTextForView
+import android.permissionmultidevice.cts.UiAutomatorUtils.waitFindObject
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.AdoptShellPermissionsRule
+import com.android.compatibility.common.util.SystemUtil
+import com.google.common.truth.Truth
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = "VanillaIceCream")
+class DeviceAwarePermissionGrantTest {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val defaultDeviceContext = instrumentation.targetContext
+
+ @get:Rule(order = 0)
+ val mAdoptShellPermissionsRule =
+ AdoptShellPermissionsRule(
+ instrumentation.uiAutomation,
+ Manifest.permission.CREATE_VIRTUAL_DEVICE
+ )
+
+ @get:Rule(order = 1) var mFakeVirtualDeviceRule = FakeVirtualDeviceRule()
+
+ @Rule @JvmField val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
+ @Before
+ fun setup() {
+ installPackage(APP_APK_PATH_STREAMING)
+ }
+
+ @After
+ fun cleanup() {
+ uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false)
+ }
+
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ @Test
+ fun onHostDevice_requestPermissionForHostDevice_shouldGrantPermission() {
+ testGrantPermissionForDevice(
+ Display.DEFAULT_DISPLAY,
+ DEVICE_ID_DEFAULT,
+ false,
+ "",
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnRemoteDevice = false
+ )
+ }
+
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ @Test
+ fun onHostDevice_requestPermissionForRemoteDevice_shouldGrantPermission() {
+ testGrantPermissionForDevice(
+ Display.DEFAULT_DISPLAY,
+ mFakeVirtualDeviceRule.virtualDevice.deviceId,
+ true,
+ DEFAULT_REMOTE_DEVICE_NAME,
+ expectPermissionGrantedOnDefaultDevice = false,
+ expectPermissionGrantedOnRemoteDevice = true
+ )
+ }
+
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ @Test
+ fun onRemoteDevice_requestPermissionForHostDevice_shouldGrantPermission() {
+ testGrantPermissionForDevice(
+ mFakeVirtualDeviceRule.virtualDisplayId,
+ DEVICE_ID_DEFAULT,
+ true,
+ getHostDeviceName(defaultDeviceContext),
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnRemoteDevice = false
+ )
+ }
+
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ @Test
+ fun onRemoteDevice_requestPermissionForRemoteDevice_shouldGrantPermission() {
+ testGrantPermissionForDevice(
+ mFakeVirtualDeviceRule.virtualDisplayId,
+ mFakeVirtualDeviceRule.virtualDevice.deviceId,
+ true,
+ DEFAULT_REMOTE_DEVICE_NAME,
+ expectPermissionGrantedOnDefaultDevice = false,
+ expectPermissionGrantedOnRemoteDevice = true
+ )
+ }
+
+ private fun testGrantPermissionForDevice(
+ displayId: Int,
+ targetDeviceId: Int,
+ showDeviceName: Boolean,
+ expectedDeviceNameInDialog: String,
+ expectPermissionGrantedOnDefaultDevice: Boolean,
+ expectPermissionGrantedOnRemoteDevice: Boolean
+ ) {
+ assertAppHasPermissionForDevice(
+ defaultDeviceContext,
+ APP_PACKAGE_NAME,
+ Manifest.permission.CAMERA,
+ DEVICE_ID_DEFAULT,
+ false
+ )
+
+ assertAppHasPermissionForDevice(
+ defaultDeviceContext,
+ APP_PACKAGE_NAME,
+ Manifest.permission.CAMERA,
+ mFakeVirtualDeviceRule.virtualDevice.deviceId,
+ false
+ )
+
+ requestPermissionOnDevice(displayId, targetDeviceId)
+
+ if (showDeviceName) {
+ assertPermissionMessageContainsDeviceName(displayId, expectedDeviceNameInDialog)
+ }
+
+ SystemUtil.eventually { click(By.displayId(displayId).res(ALLOW_BUTTON)) }
+
+ assertAppHasPermissionForDevice(
+ defaultDeviceContext,
+ APP_PACKAGE_NAME,
+ Manifest.permission.CAMERA,
+ DEVICE_ID_DEFAULT,
+ expectPermissionGrantedOnDefaultDevice
+ )
+
+ assertAppHasPermissionForDevice(
+ defaultDeviceContext,
+ APP_PACKAGE_NAME,
+ Manifest.permission.CAMERA,
+ mFakeVirtualDeviceRule.virtualDevice.deviceId,
+ expectPermissionGrantedOnRemoteDevice
+ )
+ }
+
+ private fun requestPermissionOnDevice(displayId: Int, targetDeviceId: Int) {
+ val options = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle()
+
+ val intent =
+ Intent()
+ .setComponent(
+ ComponentName(APP_PACKAGE_NAME, "$APP_PACKAGE_NAME.RequestPermissionActivity")
+ )
+ .putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, targetDeviceId)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ defaultDeviceContext.startActivity(intent, options)
+ }
+
+ private fun assertPermissionMessageContainsDeviceName(displayId: Int, deviceName: String) {
+ waitFindObject(By.displayId(displayId).res(PERMISSION_MESSAGE_ID))
+ val text = findTextForView(By.displayId(displayId).res(PERMISSION_MESSAGE_ID))
+ Truth.assertThat(text).contains(deviceName)
+ }
+
+ companion object {
+ const val APK_DIRECTORY = "/data/local/tmp/cts-permissionmultidevice"
+ const val APP_APK_PATH_STREAMING = "${APK_DIRECTORY}/CtsAccessRemoteDeviceCamera.apk"
+ const val APP_PACKAGE_NAME = "android.permissionmultidevice.cts.accessremotedevicecamera"
+ const val PERMISSION_MESSAGE_ID = "com.android.permissioncontroller:id/permission_message"
+ const val DEFAULT_REMOTE_DEVICE_NAME = "remote device"
+ const val ALLOW_BUTTON =
+ "com.android.permissioncontroller:id/permission_allow_foreground_only_button"
+ const val DEVICE_ID_DEFAULT = 0
+ }
+}
diff --git a/tests/cts/permissionmultiuser/Android.bp b/tests/cts/permissionmultiuser/Android.bp
new file mode 100644
index 000000000..b86b02205
--- /dev/null
+++ b/tests/cts/permissionmultiuser/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsPermissionMultiUserTestCases",
+ defaults: ["mts-target-sdk-version-current"],
+ sdk_version: "test_current",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ min_sdk_version: "30",
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "Harrier",
+ "modules-utils-build_system",
+ "Nene",
+ ],
+ data: [
+ ":CtsRequestLocationApp",
+ ],
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "mcts-permission",
+ ],
+}
diff --git a/tests/cts/permissionmultiuser/AndroidManifest.xml b/tests/cts/permissionmultiuser/AndroidManifest.xml
new file mode 100644
index 000000000..15bc3af34
--- /dev/null
+++ b/tests/cts/permissionmultiuser/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionmultiuser.cts">
+
+ <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.permissionmultiuser.cts"
+ android:label="CTS multi-user tests for permissions">
+ </instrumentation>
+</manifest>
diff --git a/tests/cts/permissionmultiuser/AndroidTest.xml b/tests/cts/permissionmultiuser/AndroidTest.xml
new file mode 100644
index 000000000..10fd4e7a5
--- /dev/null
+++ b/tests/cts/permissionmultiuser/AndroidTest.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Config for CTS permissionmultiuser test cases">
+
+ <option name="test-suite-tag" value="cts" />
+
+ <option name="config-descriptor:metadata" key="component" value="permissions" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="multiuser" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="run_on_sdk_sandbox" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ <option name="disable-device-config-sync" value="true" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPermissionMultiUserTestCases.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="CtsRequestLocationApp.apk->/data/local/tmp/cts-permissionmultiuser/CtsRequestLocationApp.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="appops set android.permissionmultiuser.cts REQUEST_INSTALL_PACKAGES allow" />
+ <!-- disable DeprecatedAbi warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_abi_dialog 1" />
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
+ </target_preparer>
+
+ <!-- Create place to store apks -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/cts-permissionmultiuser" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/cts-permissionmultiuser"/>
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.permissionmultiuser.cts" />
+ <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile" />
+ <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser" />
+ <option name="runtime-hint" value="5m" />
+ </test>
+
+</configuration>
diff --git a/tests/cts/permissionmultiuser/OWNERS b/tests/cts/permissionmultiuser/OWNERS
new file mode 100644
index 000000000..fb6099cf7
--- /dev/null
+++ b/tests/cts/permissionmultiuser/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 137825
+
+include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/tests/cts/permissionmultiuser/RequestLocationApp/Android.bp b/tests/cts/permissionmultiuser/RequestLocationApp/Android.bp
new file mode 100644
index 000000000..d645e15d7
--- /dev/null
+++ b/tests/cts/permissionmultiuser/RequestLocationApp/Android.bp
@@ -0,0 +1,25 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsRequestLocationApp",
+ target_sdk_version: "30",
+ min_sdk_version: "30",
+}
diff --git a/tests/cts/permissionmultiuser/RequestLocationApp/AndroidManifest.xml b/tests/cts/permissionmultiuser/RequestLocationApp/AndroidManifest.xml
new file mode 100644
index 000000000..e5e7609eb
--- /dev/null
+++ b/tests/cts/permissionmultiuser/RequestLocationApp/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionmultiuser.cts.requestlocation">
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <application>
+ </application>
+</manifest>
diff --git a/tests/cts/permissionmultiuser/TEST_MAPPING b/tests/cts/permissionmultiuser/TEST_MAPPING
new file mode 100644
index 000000000..48f5ef537
--- /dev/null
+++ b/tests/cts/permissionmultiuser/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsPermissionMultiUserTestCases"
+ }
+ ]
+}
diff --git a/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt b/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt
new file mode 100644
index 000000000..beade31ac
--- /dev/null
+++ b/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionmultiuser.cts
+
+import android.app.Instrumentation
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_MUTABLE
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.app.UiAutomation
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Context.RECEIVER_EXPORTED
+import android.content.Intent
+import android.content.Intent.ACTION_REVIEW_APP_DATA_SHARING_UPDATES
+import android.content.IntentFilter
+import android.content.pm.PackageInstaller
+import android.content.pm.PackageInstaller.EXTRA_STATUS
+import android.content.pm.PackageInstaller.EXTRA_STATUS_MESSAGE
+import android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID
+import android.content.pm.PackageInstaller.STATUS_SUCCESS
+import android.content.pm.PackageInstaller.SessionParams
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE
+import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.os.Build
+import android.os.PersistableBundle
+import android.os.SystemClock
+import android.os.UserHandle
+import android.provider.DeviceConfig
+import android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.BySelector
+import android.support.test.uiautomator.StaleObjectException
+import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.UiObject2
+import android.util.Log
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.bedstead.harrier.BedsteadJUnit4
+import com.android.bedstead.harrier.DeviceState
+import com.android.bedstead.harrier.annotations.EnsureHasPermission
+import com.android.bedstead.harrier.annotations.EnsureSecureSettingSet
+import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature
+import com.android.bedstead.harrier.annotations.RequireNotWatch
+import com.android.bedstead.harrier.annotations.RequireRunOnAdditionalUser
+import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile
+import com.android.bedstead.harrier.annotations.RequireSdkVersion
+import com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS
+import com.android.compatibility.common.util.ApiTest
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.waitForBroadcasts
+import com.android.compatibility.common.util.UiAutomatorUtils
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.After
+import org.junit.Assert
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests the UI that displays information about apps' updates to their data sharing policies when
+ * device has multiple users.
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@RequireSdkVersion(min = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+@RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+@RequireDoesNotHaveFeature(FEATURE_LEANBACK)
+@RequireNotWatch(reason = "Data sharing update page is unavailable on watch")
+@RunWith(BedsteadJUnit4::class)
+@EnsureSecureSettingSet(key = "user_setup_complete", value = "1")
+class AppDataSharingUpdatesTest {
+
+ @get:Rule
+ val deviceConfigSafetyLabelChangeNotificationsEnabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED,
+ true.toString()
+ )
+
+ @get:Rule
+ val deviceConfigDataSharingUpdatesPeriod =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_DATA_SHARING_UPDATE_PERIOD_MILLIS,
+ "600000"
+ )
+
+ /**
+ * This rule serves to limit the max number of safety labels that can be persisted, so that
+ * repeated tests don't overwhelm the disk storage on the device.
+ */
+ @get:Rule
+ val deviceConfigMaxSafetyLabelsPersistedPerApp =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP,
+ "2"
+ )
+
+ @Before
+ fun registerInstallSessionResultReceiver() {
+ context.registerReceiver(
+ installSessionResultReceiver,
+ IntentFilter(INSTALL_ACTION_CALLBACK),
+ RECEIVER_EXPORTED
+ )
+ }
+
+ @After
+ fun unregisterInstallSessionResultReceiver() {
+ try {
+ context.unregisterReceiver(installSessionResultReceiver)
+ } catch (ignored: IllegalArgumentException) {}
+ }
+
+ @Test
+ @EnsureHasPermission(INTERACT_ACROSS_USERS)
+ @RequireRunOnWorkProfile
+ @ApiTest(apis = ["android.content.Intent#ACTION_REVIEW_APP_DATA_SHARING_UPDATES"])
+ fun openDataSharingUpdatesPage_workProfile_whenAppHasUpdateAndLocationGranted_showUpdates() {
+ installPackageViaSession(LOCATION_PACKAGE_APK_PATH, createAppMetadataWithNoSharing())
+ waitForBroadcasts()
+ installPackageViaSession(
+ LOCATION_PACKAGE_APK_PATH,
+ createAppMetadataWithLocationSharingNoAds()
+ )
+ waitForBroadcasts()
+ grantLocationPermission(LOCATION_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivityForUser(deviceState.initialUser().userHandle())
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(LOCATION_PACKAGE_NAME_SUBSTRING), true)
+ } finally {
+ pressBack()
+ uninstallPackage(LOCATION_PACKAGE_NAME)
+ }
+ }
+
+ @Test
+ @EnsureHasPermission(INTERACT_ACROSS_USERS)
+ @RequireRunOnAdditionalUser
+ @ApiTest(apis = ["android.content.Intent#ACTION_REVIEW_APP_DATA_SHARING_UPDATES"])
+ fun openDataSharingUpdatesPage_additionalUser_whenAppHasUpdateAndLocationGranted_showUpdates() {
+ installPackageViaSession(LOCATION_PACKAGE_APK_PATH, createAppMetadataWithNoSharing())
+ waitForBroadcasts()
+ installPackageViaSession(
+ LOCATION_PACKAGE_APK_PATH,
+ createAppMetadataWithLocationSharingNoAds()
+ )
+ waitForBroadcasts()
+ grantLocationPermission(LOCATION_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivityForUser(deviceState.additionalUser().userHandle())
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(LOCATION_PACKAGE_NAME_SUBSTRING), true)
+ } finally {
+ pressBack()
+ uninstallPackage(LOCATION_PACKAGE_NAME)
+ }
+
+ deviceState.initialUser().switchTo()
+
+ startAppDataSharingUpdatesActivityForUser(deviceState.initialUser().userHandle())
+
+ try {
+ // Verify that state does not leak across users.
+ assertNoUpdatesPresent()
+ findView(By.textContains(LOCATION_PACKAGE_NAME_SUBSTRING), false)
+ } finally {
+ pressBack()
+ }
+ }
+
+ /** Companion object for [AppDataSharingUpdatesTest]. */
+ companion object {
+ @JvmField @ClassRule @Rule val deviceState: DeviceState = DeviceState()
+
+ @JvmStatic
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context: Context = instrumentation.context
+ @JvmStatic private val uiAutomation: UiAutomation = instrumentation.uiAutomation
+ @JvmStatic private val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+ @JvmStatic private val packageManager: PackageManager = context.packageManager
+ @JvmStatic private val packageInstaller = packageManager.packageInstaller
+ private data class SessionResult(val status: Int?)
+ private val TAG = AppDataSharingUpdatesTest::class.simpleName
+
+ private const val APK_DIRECTORY = "/data/local/tmp/cts-permissionmultiuser"
+ private const val LOCATION_PACKAGE_NAME = "android.permissionmultiuser.cts.requestlocation"
+ private const val LOCATION_PACKAGE_APK_PATH = "CtsRequestLocationApp.apk"
+ private const val INSTALL_ACTION_CALLBACK = "AppDataSharingUpdatesTest.install_callback"
+ private const val PACKAGE_INSTALLER_TIMEOUT = 60000L
+ private const val IDLE_TIMEOUT_MILLIS: Long = 1000
+ private const val TIMEOUT_MILLIS: Long = 20000
+
+ private const val KEY_VERSION = "version"
+ private const val KEY_SAFETY_LABELS = "safety_labels"
+ private const val KEY_DATA_SHARED = "data_shared"
+ private const val KEY_DATA_LABELS = "data_labels"
+ private const val KEY_PURPOSES = "purposes"
+ private const val INITIAL_SAFETY_LABELS_VERSION = 1L
+ private const val INITIAL_TOP_LEVEL_VERSION = 1L
+ private const val LOCATION_CATEGORY = "location"
+ private const val APPROX_LOCATION = "approx_location"
+ private const val PURPOSE_FRAUD_PREVENTION_SECURITY = 4
+
+ private const val DATA_SHARING_UPDATES = "Data sharing updates for location"
+ private const val DATA_SHARING_UPDATES_SUBTITLE =
+ "These apps have changed the way they may share your location data. They may not" +
+ " have shared it before, or may now share it for advertising or marketing" +
+ " purposes."
+ private const val DATA_SHARING_NO_UPDATES_MESSAGE = "No updates at this time"
+ private const val UPDATES_IN_LAST_30_DAYS = "Updated within 30 days"
+ private const val DATA_SHARING_UPDATES_FOOTER_MESSAGE =
+ "The developers of these apps provided info about their data sharing practices" +
+ " to an app store. They may update it over time.\n\nData sharing" +
+ " practices may vary based on your app version, use, region, and age."
+ private const val LOCATION_PACKAGE_NAME_SUBSTRING = "android.permissionmultiuser"
+ private const val PROPERTY_DATA_SHARING_UPDATE_PERIOD_MILLIS =
+ "data_sharing_update_period_millis"
+ private const val PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP =
+ "max_safety_labels_persisted_per_app"
+
+ private var installSessionResult = LinkedBlockingQueue<SessionResult>()
+
+ private val installSessionResultReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val status = intent.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID)
+ val msg = intent.getStringExtra(EXTRA_STATUS_MESSAGE)
+ Log.d(TAG, "status: $status, msg: $msg")
+
+ installSessionResult.offer(SessionResult(status))
+ }
+ }
+
+ /** Installs an app with the provided [appMetadata] */
+ private fun installPackageViaSession(
+ apkName: String,
+ appMetadata: PersistableBundle? = null,
+ packageSource: Int? = null
+ ) {
+ val session = createPackageInstallerSession(packageSource)
+ runWithShellPermissionIdentity {
+ writePackageInstallerSession(session, apkName)
+ if (appMetadata != null) {
+ setAppMetadata(session, appMetadata)
+ }
+ commitPackageInstallerSession(session)
+
+ // No need to click installer UI here due to running in shell permission identity
+ // and not needing user interaction to complete install.
+ // Install should have succeeded.
+ val result = getInstallSessionResult()
+ assertThat(result.status).isEqualTo(STATUS_SUCCESS)
+ }
+ }
+
+ private fun createPackageInstallerSession(
+ packageSource: Int? = null
+ ): PackageInstaller.Session {
+ val sessionParam = SessionParams(SessionParams.MODE_FULL_INSTALL)
+ if (packageSource != null) {
+ sessionParam.setPackageSource(packageSource)
+ }
+
+ val sessionId = packageInstaller.createSession(sessionParam)
+ return packageInstaller.openSession(sessionId)
+ }
+
+ private fun writePackageInstallerSession(
+ session: PackageInstaller.Session,
+ apkName: String
+ ) {
+ val apkFile = File(APK_DIRECTORY, apkName)
+ apkFile.inputStream().use { fileOnDisk ->
+ session
+ .openWrite(/* name= */ apkName, /* offsetBytes= */ 0, /* lengthBytes= */ -1)
+ .use { sessionFile -> fileOnDisk.copyTo(sessionFile) }
+ }
+ }
+
+ private fun commitPackageInstallerSession(session: PackageInstaller.Session) {
+ // PendingIntent that triggers a INSTALL_ACTION_CALLBACK broadcast that gets received by
+ // installSessionResultReceiver when install actions occur with this session
+ val installActionPendingIntent =
+ PendingIntent.getBroadcast(
+ context,
+ 0,
+ Intent(INSTALL_ACTION_CALLBACK).setPackage(context.packageName),
+ FLAG_UPDATE_CURRENT or FLAG_MUTABLE
+ )
+ session.commit(installActionPendingIntent.intentSender)
+ }
+
+ private fun setAppMetadata(session: PackageInstaller.Session, data: PersistableBundle) {
+ try {
+ session.setAppMetadata(data)
+ } catch (e: Exception) {
+ session.abandon()
+ throw e
+ }
+ }
+
+ private fun getInstallSessionResult(
+ timeout: Long = PACKAGE_INSTALLER_TIMEOUT
+ ): SessionResult {
+ return installSessionResult.poll(timeout, TimeUnit.MILLISECONDS)
+ ?: SessionResult(null /* status */)
+ }
+
+ private fun uninstallPackage(packageName: String) {
+ runShellCommand("pm uninstall $packageName").trim()
+ }
+
+ private fun pressBack() {
+ uiDevice.pressBack()
+ uiAutomation.waitForIdle(IDLE_TIMEOUT_MILLIS, TIMEOUT_MILLIS)
+ }
+
+ /** Returns an App Metadata [PersistableBundle] representation where no data is shared. */
+ private fun createAppMetadataWithNoSharing(): PersistableBundle {
+ return createMetadataWithDataShared(PersistableBundle())
+ }
+
+ /**
+ * Returns an App Metadata [PersistableBundle] representation where location data is shared,
+ * but not for advertising purpose.
+ */
+ private fun createAppMetadataWithLocationSharingNoAds(): PersistableBundle {
+ val locationBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(
+ APPROX_LOCATION,
+ PersistableBundle().apply {
+ putIntArray(
+ KEY_PURPOSES,
+ listOf(PURPOSE_FRAUD_PREVENTION_SECURITY).toIntArray()
+ )
+ }
+ )
+ }
+
+ val dataSharedBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(LOCATION_CATEGORY, locationBundle)
+ }
+
+ return createMetadataWithDataShared(dataSharedBundle)
+ }
+
+ /**
+ * Returns an App Metadata [PersistableBundle] representation where with the provided data
+ * shared.
+ */
+ private fun createMetadataWithDataShared(
+ dataSharedBundle: PersistableBundle
+ ): PersistableBundle {
+ val dataLabelBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(KEY_DATA_SHARED, dataSharedBundle)
+ }
+
+ val safetyLabelBundle =
+ PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_SAFETY_LABELS_VERSION)
+ putPersistableBundle(KEY_DATA_LABELS, dataLabelBundle)
+ }
+
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_TOP_LEVEL_VERSION)
+ putPersistableBundle(KEY_SAFETY_LABELS, safetyLabelBundle)
+ }
+ }
+
+ /**
+ * Starts activity with intent [ACTION_REVIEW_APP_DATA_SHARING_UPDATES] for the provided
+ * user.
+ */
+ fun startAppDataSharingUpdatesActivityForUser(userHandle: UserHandle) {
+ runWithShellPermissionIdentity {
+ context.startActivityAsUser(
+ Intent(ACTION_REVIEW_APP_DATA_SHARING_UPDATES).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ },
+ userHandle
+ )
+ }
+ }
+
+ private fun assertUpdatesPresent() {
+ findView(By.descContains(DATA_SHARING_UPDATES), true)
+ findView(By.textContains(DATA_SHARING_UPDATES_SUBTITLE), true)
+ findView(By.textContains(UPDATES_IN_LAST_30_DAYS), true)
+ findView(By.textContains(DATA_SHARING_UPDATES_FOOTER_MESSAGE), true)
+ }
+
+ private fun assertNoUpdatesPresent() {
+ findView(By.descContains(DATA_SHARING_UPDATES), true)
+ findView(By.textContains(DATA_SHARING_NO_UPDATES_MESSAGE), true)
+ findView(By.textContains(LOCATION_PACKAGE_NAME_SUBSTRING), false)
+ }
+
+ private fun grantLocationPermission(packageName: String) {
+ uiAutomation.grantRuntimePermission(
+ packageName,
+ android.Manifest.permission.ACCESS_FINE_LOCATION
+ )
+ }
+
+ protected fun waitFindObject(
+ selector: BySelector,
+ timeoutMillis: Long = 20_000L
+ ): UiObject2 {
+ uiAutomation.waitForIdle(IDLE_TIMEOUT_MILLIS, TIMEOUT_MILLIS)
+ val startTime = SystemClock.elapsedRealtime()
+ return try {
+ UiAutomatorUtils.waitFindObject(selector, timeoutMillis)
+ } catch (e: StaleObjectException) {
+ val remainingTime = timeoutMillis - (SystemClock.elapsedRealtime() - startTime)
+ if (remainingTime <= 0) {
+ throw e
+ }
+ UiAutomatorUtils.waitFindObject(selector, remainingTime)
+ }
+ }
+
+ private fun findView(selector: BySelector, expected: Boolean) {
+ val timeoutMillis =
+ if (expected) {
+ 20000L
+ } else {
+ 1000L
+ }
+
+ val exception =
+ try {
+ uiAutomation.waitForIdle(IDLE_TIMEOUT_MILLIS, TIMEOUT_MILLIS)
+ val startTime = SystemClock.elapsedRealtime()
+ try {
+ UiAutomatorUtils.waitFindObject(selector, timeoutMillis)
+ } catch (e: StaleObjectException) {
+ val remainingTime =
+ timeoutMillis - (SystemClock.elapsedRealtime() - startTime)
+ if (remainingTime <= 0) {
+ throw e
+ }
+ UiAutomatorUtils.waitFindObject(selector, remainingTime)
+ }
+ null
+ } catch (e: Exception) {
+ e
+ }
+ val actual = exception == null
+ val message =
+ if (expected) {
+ "Expected view $selector not found"
+ } else {
+ "Unexpected view found: $selector"
+ }
+ Assert.assertTrue(message, actual == expected)
+ }
+ }
+}
diff --git a/tests/cts/permissionpolicy/Android.bp b/tests/cts/permissionpolicy/Android.bp
new file mode 100644
index 000000000..7a481b7ff
--- /dev/null
+++ b/tests/cts/permissionpolicy/Android.bp
@@ -0,0 +1,68 @@
+//
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsPermissionPolicyTestCases",
+ defaults: ["cts_defaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "mcts-permission",
+ ],
+ libs: ["android.test.base"],
+ static_libs: [
+ "androidx.test.core",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "guava",
+ "androidx.test.ext.junit-nodeps",
+ "truth",
+ "permission-test-util-lib",
+ "androidx.test.rules",
+ ],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ sdk_version: "test_current",
+ data: [
+ ":CtsLocationPermissionsUserSdk22",
+ ":CtsLocationPermissionsUserSdk29",
+ ":CtsSMSCallLogPermissionsUserSdk22",
+ ":CtsSMSCallLogPermissionsUserSdk29",
+ ":CtsStoragePermissionsUserDefaultSdk22",
+ ":CtsStoragePermissionsUserDefaultSdk28",
+ ":CtsStoragePermissionsUserDefaultSdk29",
+ ":CtsStoragePermissionsUserOptInSdk22",
+ ":CtsStoragePermissionsUserOptInSdk28",
+ ":CtsStoragePermissionsUserOptOutSdk29",
+ ":CtsStoragePermissionsPreservedUserOptOutSdk30",
+ ":CtsLegacyStorageNotIsolatedWithSharedUid",
+ ":CtsLegacyStorageIsolatedWithSharedUid",
+ ":CtsLegacyStorageRestrictedWithSharedUid",
+ ":CtsLegacyStorageRestrictedSdk28WithSharedUid",
+ ":CtsStoragePermissionsUserOptOutSdk30",
+ ":CtsSMSRestrictedWithSharedUid",
+ ":CtsSMSNotRestrictedWithSharedUid",
+ ":CtsProcessOutgoingCalls",
+ ],
+}
diff --git a/tests/cts/permissionpolicy/AndroidManifest.xml b/tests/cts/permissionpolicy/AndroidManifest.xml
new file mode 100755
index 000000000..53ddc59e5
--- /dev/null
+++ b/tests/cts/permissionpolicy/AndroidManifest.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts" android:targetSandboxVersion="2">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ This app contains tests to verify specialized permissions, that require the app to have
+ some permissions.
+ -->
+
+ <!-- need ability to send sms, to test that SMS's cannot be received -->
+ <uses-permission android:name="android.permission.SEND_SMS"/>
+
+ <!-- needs read phone numbers to get current phone number for R+ -->
+ <uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>
+
+ <!-- needs read phone status to get current phone subscription info for R+ -->
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+
+ <!-- need app that has WRITE_SETTINGS but not WRITE_SECURE_SETTINGS -->
+ <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+
+ <!-- need app that has CALL_PHONE but not PROCESS_OUTGOING_CALL -->
+ <uses-permission android:name="android.permission.CALL_PHONE"/>
+
+ <!-- need app that has RECORD_AUDIO but not CAPTURE_AUDIO_OUTPUT -->
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+ <!-- need app that has READ_CONTACTS but not READ_PROFILE -->
+ <uses-permission android:name="android.permission.READ_CONTACTS"/>
+
+ <!-- need app that has WRITE_CONTACTS but not WRITE_PROFILE -->
+ <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+ <!-- need a permission that would ordinarily be granted, but has a maxSdkVersion that
+ causes it to be withheld under the current API level -->
+ <uses-permission
+ android:name="android.permission.INTERNET"
+ android:maxSdkVersion="18"/>
+
+
+ <!-- need a permission that will be granted -->
+ <uses-permission
+ android:name="android.permission.ACCESS_NETWORK_STATE"
+ android:maxSdkVersion="9000"/>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.permissionpolicy.cts"
+ android:label="More CTS tests for permissions">
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/cts/permissionpolicy/AndroidTest.xml b/tests/cts/permissionpolicy/AndroidTest.xml
new file mode 100644
index 000000000..7fddaca52
--- /dev/null
+++ b/tests/cts/permissionpolicy/AndroidTest.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Permission Policy test cases">
+
+ <option name="test-suite-tag" value="cts" />
+ <option name="not-shardable" value="true" />
+
+ <option name="config-descriptor:metadata" key="component" value="permissions" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
+ <option name="config-descriptor:metadata" key="parameter" value="run_on_sdk_sandbox" />
+ <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
+
+ <!-- TODO(b/245579250): update to Sdk34 once sdk finalized -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPermissionPolicyTestCases.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ <option name="disable-device-config-sync" value="true" />
+ </target_preparer>
+
+ <!-- Create place to store apks -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/cts-permissionpolicy" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/cts-permissionpolicy-permissionpolicy"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="CtsLocationPermissionsUserSdk22.apk->/data/local/tmp/cts-permissionpolicy/CtsLocationPermissionsUserSdk22.apk" />
+ <option name="push" value="CtsLocationPermissionsUserSdk29.apk->/data/local/tmp/cts-permissionpolicy/CtsLocationPermissionsUserSdk29.apk" />
+ <option name="push" value="CtsSMSCallLogPermissionsUserSdk22.apk->/data/local/tmp/cts-permissionpolicy/CtsSMSCallLogPermissionsUserSdk22.apk" />
+ <option name="push" value="CtsSMSCallLogPermissionsUserSdk29.apk->/data/local/tmp/cts-permissionpolicy/CtsSMSCallLogPermissionsUserSdk29.apk" />
+ <option name="push" value="CtsStoragePermissionsUserDefaultSdk22.apk->/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserDefaultSdk22.apk" />
+ <option name="push" value="CtsStoragePermissionsUserDefaultSdk28.apk->/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserDefaultSdk28.apk" />
+ <option name="push" value="CtsStoragePermissionsUserDefaultSdk29.apk->/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserDefaultSdk29.apk" />
+ <option name="push" value="CtsStoragePermissionsUserOptInSdk22.apk->/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserOptInSdk22.apk" />
+ <option name="push" value="CtsStoragePermissionsUserOptInSdk28.apk->/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserOptInSdk28.apk" />
+ <option name="push" value="CtsStoragePermissionsUserOptOutSdk29.apk->/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserOptOutSdk29.apk" />
+ <option name="push" value="CtsLegacyStorageNotIsolatedWithSharedUid.apk->/data/local/tmp/cts-permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid.apk" />
+ <option name="push" value="CtsLegacyStorageIsolatedWithSharedUid.apk->/data/local/tmp/cts-permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid.apk" />
+ <option name="push" value="CtsLegacyStorageRestrictedWithSharedUid.apk->/data/local/tmp/cts-permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid.apk" />
+ <option name="push" value="CtsLegacyStorageRestrictedSdk28WithSharedUid.apk->/data/local/tmp/cts-permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid.apk" />
+ <option name="push" value="CtsStoragePermissionsUserOptOutSdk30.apk->/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserOptOutSdk30.apk" />
+ <option name="push" value="CtsStoragePermissionsPreservedUserOptOutSdk30.apk->/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30.apk" />
+ <option name="push" value="CtsSMSRestrictedWithSharedUid.apk->/data/local/tmp/cts-permissionpolicy/CtsSMSRestrictedWithSharedUid.apk" />
+ <option name="push" value="CtsSMSNotRestrictedWithSharedUid.apk->/data/local/tmp/cts-permissionpolicy/CtsSMSNotRestrictedWithSharedUid.apk" />
+ <option name="push" value="CtsProcessOutgoingCalls.apk->/data/local/tmp/cts-permissionpolicy/CtsProcessOutgoingCalls.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <!-- disable DeprecatedAbi warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_abi_dialog 1" />
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.permissionpolicy.cts" />
+ <option name="runtime-hint" value="2m" />
+ </test>
+
+</configuration>
diff --git a/tests/cts/permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid/Android.bp b/tests/cts/permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
new file mode 100644
index 000000000..146bdceae
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsLegacyStorageIsolatedWithSharedUid",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 000000000..d221b1284
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.legacystoragewithshareduid.isolated"
+ android:versionCode="1"
+ android:sharedUserId="android.permissionpolicy.cts.restrictedpermissionuser.shareduid">
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application android:label="CtsLegacyStorageIsolatedWithSharedUid" />
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp b/tests/cts/permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
new file mode 100644
index 000000000..c4bc761ce
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsLegacyStorageNotIsolatedWithSharedUid",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 000000000..69188d392
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.legacystoragewithshareduid.notisolated"
+ android:versionCode="1"
+ android:sharedUserId="android.permissionpolicy.cts.restrictedpermissionuser.shareduid">
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+
+ <application android:label="CtsLegacyStorageNotIsolatedWithSharedUid"
+ android:requestLegacyExternalStorage="true" />
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp b/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
new file mode 100644
index 000000000..2373fc1e2
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsLegacyStorageRestrictedSdk28WithSharedUid",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml
new file mode 100644
index 000000000..cf09f33a3
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.legacystoragewithshareduid.restrictedsdk28"
+ android:versionCode="1"
+ android:sharedUserId="android.permissionpolicy.cts.restrictedpermissionuser.shareduid">
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application android:label="CtsLegacyStorageRestrictedSdk28WithSharedUid" />
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid/Android.bp b/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
new file mode 100644
index 000000000..523f74224
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsLegacyStorageRestrictedWithSharedUid",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 000000000..3e9acc9aa
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.legacystoragewithshareduid.restricted"
+ android:versionCode="1"
+ android:sharedUserId="android.permissionpolicy.cts.restrictedpermissionuser.shareduid">
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application android:label="CtsLegacyStorageRestrictedWithSharedUid" />
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk22/Android.bp b/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk22/Android.bp
new file mode 100644
index 000000000..787cbaebe
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk22/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsLocationPermissionsUserSdk22",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+
+ // TODO: Uncomment when uncommenting the test
+ // srcs: ["src/**/*.java"]
+
+}
diff --git a/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk22/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk22/AndroidManifest.xml
new file mode 100644
index 000000000..f0732755f
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk22/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22"/>
+
+ <application android:label="CtsLocationPermissionsUserSdk22">
+ </application>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk29/Android.bp b/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk29/Android.bp
new file mode 100644
index 000000000..93c8b72b3
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk29/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsLocationPermissionsUserSdk29",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+
+ // TODO: Uncomment when uncommenting the test
+ // srcs: ["src/**/*.java"]
+
+}
diff --git a/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk29/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk29/AndroidManifest.xml
new file mode 100644
index 000000000..21c73cc07
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsLocationPermissionsUserSdk29/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <application android:label="CtsLocationPermissionsUserSdk29">
+ </application>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/Android.bp b/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/Android.bp
new file mode 100644
index 000000000..ef6f44b5a
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsProcessOutgoingCalls",
+ defaults: ["cts_defaults"],
+ sdk_version: "test_current",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+}
diff --git a/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/AndroidManifest.xml
new file mode 100644
index 000000000..254d7d9ce
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.receivecallbroadcast">
+
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+
+ <application>
+ <activity android:name=".ProcessOutgoingCallReceiver$BaseActivity" android:exported="true"/>
+ <receiver android:name=".ProcessOutgoingCallReceiver" android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
+ </intent-filter>
+ </receiver>
+ </application>
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/src/android/permissionpolicy/cts/receivecallbroadcast/ProcessOutgoingCallReceiver.kt b/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/src/android/permissionpolicy/cts/receivecallbroadcast/ProcessOutgoingCallReceiver.kt
new file mode 100644
index 000000000..901810aa1
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsProcessOutgoingCalls/src/android/permissionpolicy/cts/receivecallbroadcast/ProcessOutgoingCallReceiver.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts.receivecallbroadcast
+
+import android.app.Activity
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+
+class ProcessOutgoingCallReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ context!!.sendBroadcast(
+ Intent(ACTION_TEST_APP_RECEIVED_OUTGOING_CALL).setPackage(TEST_CLASS_PKG_NAME)
+ )
+ }
+
+ class BaseActivity : Activity()
+}
+
+const val TEST_CLASS_PKG_NAME = "android.permissionpolicy.cts"
+const val ACTION_TEST_APP_RECEIVED_OUTGOING_CALL =
+ "android.permissionpolicy.cts.TEST_APP_RECEIVED_CALL"
diff --git a/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk22/Android.bp b/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk22/Android.bp
new file mode 100644
index 000000000..b864a4e26
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk22/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsSMSCallLogPermissionsUserSdk22",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+
+ // TODO: Uncomment when uncommenting the test
+ // srcs: ["src/**/*.java"]
+
+}
diff --git a/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk22/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk22/AndroidManifest.xml
new file mode 100644
index 000000000..3d1207360
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk22/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- SMS -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
+ <uses-permission android:name="android.permission.RECEIVE_MMS" />
+ <uses-permission android:name="android.permission.READ_CELL_BROADCASTS" />
+
+ <!-- CallLog -->
+ <uses-permission android:name="android.permission.READ_CALL_LOG" />
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22"/>
+
+ <application android:label="CtsSMSCallLogPermissionsUserSdk22">
+ </application>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk29/Android.bp b/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk29/Android.bp
new file mode 100644
index 000000000..d3a2e30f0
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk29/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsSMSCallLogPermissionsUserSdk29",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+
+ // TODO: Uncomment when uncommenting the test
+ // srcs: ["src/**/*.java"]
+
+}
diff --git a/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk29/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk29/AndroidManifest.xml
new file mode 100644
index 000000000..035e2e495
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsSMSCallLogPermissionsUserSdk29/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- SMS -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
+ <uses-permission android:name="android.permission.RECEIVE_MMS" />
+ <uses-permission android:name="android.permission.READ_CELL_BROADCASTS" />
+
+ <!-- CallLog -->
+ <uses-permission android:name="android.permission.READ_CALL_LOG" />
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+
+ <application android:label="CtsSMSCallLogPermissionsUserSdk29">
+ </application>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsSMSNotRestrictedWithSharedUid/Android.bp b/tests/cts/permissionpolicy/CtsSMSNotRestrictedWithSharedUid/Android.bp
new file mode 100644
index 000000000..ab90dba35
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsSMSNotRestrictedWithSharedUid/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsSMSNotRestrictedWithSharedUid",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 000000000..109a9e8df
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.smswithshareduid.notrestricted"
+ android:versionCode="1"
+ android:sharedUserId="android.permissionpolicy.cts.restrictedpermissionuser.shareduid">
+
+ <uses-permission android:name="android.permission.READ_SMS" />
+
+ <application android:label="CtsSMSNotRestrictedWithSharedUid" />
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsSMSRestrictedWithSharedUid/Android.bp b/tests/cts/permissionpolicy/CtsSMSRestrictedWithSharedUid/Android.bp
new file mode 100644
index 000000000..8820ab776
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsSMSRestrictedWithSharedUid/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsSMSRestrictedWithSharedUid",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 000000000..cb44afdd1
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.smswithshareduid.restricted"
+ android:versionCode="1"
+ android:sharedUserId="android.permissionpolicy.cts.restrictedpermissionuser.shareduid">
+
+ <uses-permission android:name="android.permission.READ_SMS" />
+
+ <application android:label="CtsSMSRestrictedWithSharedUid" />
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp b/tests/cts/permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp
new file mode 100644
index 000000000..6c76c7485
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStoragePermissionsPreservedUserOptOutSdk30",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30/AndroidManifest.xml
new file mode 100644
index 000000000..48c4f37c9
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- Storage -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk android:targetSdkVersion="30"/>
+
+ <application android:label="CtsStoragePermissionsPreservedUserOptOutSdk30"
+ android:preserveLegacyExternalStorage="true"/>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk22/Android.bp b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk22/Android.bp
new file mode 100644
index 000000000..bb817f780
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk22/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStoragePermissionsUserDefaultSdk22",
+ defaults: ["cts_defaults"],
+}
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk22/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk22/AndroidManifest.xml
new file mode 100644
index 000000000..543b9ebb8
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk22/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- Storage -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22"/>
+
+ <application android:label="CtsStoragePermissionsUserDefaultSdk22" />
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk28/Android.bp b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk28/Android.bp
new file mode 100644
index 000000000..60cb316f6
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk28/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStoragePermissionsUserDefaultSdk28",
+ defaults: ["cts_defaults"],
+}
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk28/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk28/AndroidManifest.xml
new file mode 100644
index 000000000..77920de15
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk28/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- Storage -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
+
+ <application android:label="CtsStoragePermissionsUserDefaultSdk28" />
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk29/Android.bp b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk29/Android.bp
new file mode 100644
index 000000000..d3d016a63
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk29/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStoragePermissionsUserDefaultSdk29",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "29",
+}
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk29/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk29/AndroidManifest.xml
new file mode 100644
index 000000000..e96452fd2
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk29/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- Storage -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk android:targetSdkVersion="29"/>
+
+ <application android:label="CtsStoragePermissionsUserDefaultSdk29" />
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk30/Android.bp b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk30/Android.bp
new file mode 100644
index 000000000..751342e2f
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk30/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStoragePermissionsUserOptOutSdk30",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk30/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk30/AndroidManifest.xml
new file mode 100644
index 000000000..b5c71b373
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserDefaultSdk30/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- Storage -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+
+ <uses-sdk android:targetSdkVersion="30"/>
+
+ <application android:label="CtsStoragePermissionsUserOptOutSdk30"
+ android:requestLegacyExternalStorage="true"/>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk22/Android.bp b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk22/Android.bp
new file mode 100644
index 000000000..21e6aceef
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk22/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStoragePermissionsUserOptInSdk22",
+ defaults: ["cts_defaults"],
+}
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk22/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk22/AndroidManifest.xml
new file mode 100644
index 000000000..466d60157
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk22/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- Storage -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22"/>
+
+ <application android:label="CtsStoragePermissionsUserOptInSdk22"
+ android:requestLegacyExternalStorage="false"/>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk28/Android.bp b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk28/Android.bp
new file mode 100644
index 000000000..c7f30a8b6
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk28/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStoragePermissionsUserOptInSdk28",
+ defaults: ["cts_defaults"],
+}
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk28/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk28/AndroidManifest.xml
new file mode 100644
index 000000000..151bbbfea
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptInSdk28/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- Storage -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
+
+ <application android:label="CtsStoragePermissionsUserOptInSdk28"
+ android:requestLegacyExternalStorage="false"/>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptOutSdk29/Android.bp b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptOutSdk29/Android.bp
new file mode 100644
index 000000000..8ad13f798
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptOutSdk29/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsStoragePermissionsUserOptOutSdk29",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+}
diff --git a/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptOutSdk29/AndroidManifest.xml b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptOutSdk29/AndroidManifest.xml
new file mode 100644
index 000000000..e41ee7759
--- /dev/null
+++ b/tests/cts/permissionpolicy/CtsStoragePermissionsUserOptOutSdk29/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionpolicy.cts.restrictedpermissionuser"
+ android:versionCode="1">
+
+ <!-- Storage -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29"/>
+
+ <application android:label="CtsStoragePermissionsUserOptOutSdk29"
+ android:requestLegacyExternalStorage="true"/>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/OWNERS b/tests/cts/permissionpolicy/OWNERS
new file mode 100644
index 000000000..395269207
--- /dev/null
+++ b/tests/cts/permissionpolicy/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 137825
+
+include platform/frameworks/base:/core/java/android/permission/OWNERS
+
+per-file NoLocationPermissionTest.java = tgunn@google.com
+per-file RestrictedStoragePermissionSharedUidTest.java = nandana@google.com
+per-file RestrictedStoragePermissionTest.java = nandana@google.com
diff --git a/tests/cts/permissionpolicy/res/raw/OWNERS b/tests/cts/permissionpolicy/res/raw/OWNERS
new file mode 100644
index 000000000..6e1a91b88
--- /dev/null
+++ b/tests/cts/permissionpolicy/res/raw/OWNERS
@@ -0,0 +1,8 @@
+hackbod@google.com
+patb@google.com
+yamasani@google.com
+michaelwr@google.com
+narayan@google.com
+roosa@google.com
+per-file automotive_android_manifest.xml = skeys@google.com
+per-file automotive_android_manifest.xml = file:platform/packages/services/Car:/OWNERS
diff --git a/tests/cts/permissionpolicy/res/raw/android_manifest.xml b/tests/cts/permissionpolicy/res/raw/android_manifest.xml
new file mode 100644
index 000000000..a8c2e90cc
--- /dev/null
+++ b/tests/cts/permissionpolicy/res/raw/android_manifest.xml
@@ -0,0 +1,8230 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/AndroidManifest.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android" coreApp="true" android:sharedUserId="android.uid.system"
+ android:sharedUserLabel="@string/android_system_label">
+
+ <!-- ================================================ -->
+ <!-- Special broadcasts that only the system can send -->
+ <!-- ================================================ -->
+ <eat-comment />
+
+ <protected-broadcast android:name="android.intent.action.SCREEN_OFF" />
+ <protected-broadcast android:name="android.intent.action.SCREEN_ON" />
+ <protected-broadcast android:name="android.intent.action.USER_PRESENT" />
+ <protected-broadcast android:name="android.intent.action.TIME_SET" />
+ <protected-broadcast android:name="android.intent.action.TIME_TICK" />
+ <protected-broadcast android:name="android.intent.action.TIMEZONE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.DATE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.PRE_BOOT_COMPLETED" />
+ <protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" />
+ <protected-broadcast android:name="android.intent.action.MY_PACKAGE_REPLACED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED_INTERNAL" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_LOADED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_ENABLE_ROLLBACK" />
+ <protected-broadcast android:name="android.intent.action.CANCEL_ENABLE_ROLLBACK" />
+ <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENSION_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY" />
+ <protected-broadcast android:name="android.intent.action.DISTRACTING_PACKAGES_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
+ <protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
+ <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.SPLIT_CONFIGURATION_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.APPLICATION_LOCALE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.BATTERY_LEVEL_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
+ <protected-broadcast android:name="android.intent.action.BATTERY_OKAY" />
+ <protected-broadcast android:name="android.intent.action.ACTION_POWER_CONNECTED" />
+ <protected-broadcast android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
+ <protected-broadcast android:name="android.intent.action.ACTION_SHUTDOWN" />
+ <protected-broadcast android:name="android.intent.action.CHARGING" />
+ <protected-broadcast android:name="android.intent.action.DISCHARGING" />
+ <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_LOW" />
+ <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_OK" />
+ <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_FULL" />
+ <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_NOT_FULL" />
+ <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
+ <protected-broadcast android:name="android.intent.action.REBOOT" />
+ <protected-broadcast android:name="android.intent.action.DOCK_EVENT" />
+ <protected-broadcast android:name="android.intent.action.THERMAL_EVENT" />
+ <protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
+ <protected-broadcast android:name="android.intent.action.USER_ADDED" />
+ <protected-broadcast android:name="android.intent.action.USER_REMOVED" />
+ <protected-broadcast android:name="android.intent.action.USER_STARTING" />
+ <protected-broadcast android:name="android.intent.action.USER_STARTED" />
+ <protected-broadcast android:name="android.intent.action.USER_STOPPING" />
+ <protected-broadcast android:name="android.intent.action.USER_STOPPED" />
+ <protected-broadcast android:name="android.intent.action.USER_BACKGROUND" />
+ <protected-broadcast android:name="android.intent.action.USER_FOREGROUND" />
+ <protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
+ <protected-broadcast android:name="android.intent.action.USER_INITIALIZE" />
+ <protected-broadcast android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION" />
+ <protected-broadcast android:name="android.intent.action.DOMAINS_NEED_VERIFICATION" />
+ <protected-broadcast android:name="android.intent.action.OVERLAY_ADDED" />
+ <protected-broadcast android:name="android.intent.action.OVERLAY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
+ <protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
+ <protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
+
+ <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
+ <protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
+ <protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
+ <protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
+ <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
+ <protected-broadcast android:name="android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED" />
+ <protected-broadcast android:name="android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED" />
+ <protected-broadcast android:name="android.os.action.LOW_POWER_STANDBY_PORTS_CHANGED" />
+ <protected-broadcast android:name="android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED" />
+
+ <!-- @deprecated This is rarely used and will be phased out soon. -->
+ <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
+
+ <protected-broadcast android:name="android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL" />
+
+ <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
+ <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
+ <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIORITIZED" />
+ <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE_PRIORITIZED" />
+ <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
+ <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
+ <protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
+
+ <protected-broadcast android:name="android.app.action.USER_ADDED" />
+ <protected-broadcast android:name="android.app.action.USER_REMOVED" />
+ <protected-broadcast android:name="android.app.action.USER_STARTED" />
+ <protected-broadcast android:name="android.app.action.USER_STOPPED" />
+ <protected-broadcast android:name="android.app.action.USER_SWITCHED" />
+
+ <protected-broadcast android:name="android.app.action.BUGREPORT_SHARING_DECLINED" />
+ <protected-broadcast android:name="android.app.action.BUGREPORT_FAILED" />
+ <protected-broadcast android:name="android.app.action.BUGREPORT_SHARE" />
+ <protected-broadcast android:name="android.app.action.SHOW_DEVICE_MONITORING_DIALOG" />
+ <protected-broadcast android:name="android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.INCIDENT_REPORT_READY" />
+
+ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" />
+ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" />
+ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DISABLED" />
+ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLED" />
+ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED" />
+ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_RESTORED" />
+
+ <protected-broadcast android:name="android.os.action.SETTING_RESTORED" />
+
+ <protected-broadcast android:name="android.app.backup.intent.CLEAR" />
+ <protected-broadcast android:name="android.app.backup.intent.INIT" />
+
+ <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.UUID" />
+ <protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
+ <protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.NAME_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.NAME_FAILED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
+ <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
+ <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REPLY" />
+ <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" />
+ <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
+ <protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" />
+ <protected-broadcast android:name="android.bluetooth.device.action.BATTERY_LEVEL_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
+ <protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
+ <protected-broadcast
+ android:name="android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
+ <protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_DEVICE_AVAILABLE" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE" />
+ <protected-broadcast
+ android:name="android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.avrcp-controller.profile.action.BROWSE_CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.avrcp-controller.profile.action.FOLDER_LIST" />
+ <protected-broadcast
+ android:name="android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT" />
+ <protected-broadcast
+ android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.input.profile.action.IDLE_TIME_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
+ <protected-broadcast
+ android:name="android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED" />
+ <protected-broadcast
+ android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
+ <protected-broadcast
+ android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
+ <protected-broadcast
+ android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONF_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.action.TETHERING_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
+ <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
+ <protected-broadcast android:name="android.btopp.intent.action.LIST" />
+ <protected-broadcast android:name="android.btopp.intent.action.OPEN_OUTBOUND" />
+ <protected-broadcast android:name="android.btopp.intent.action.HIDE_COMPLETE" />
+ <protected-broadcast android:name="android.btopp.intent.action.CONFIRM" />
+ <protected-broadcast android:name="android.btopp.intent.action.HIDE" />
+ <protected-broadcast android:name="android.btopp.intent.action.RETRY" />
+ <protected-broadcast android:name="android.btopp.intent.action.OPEN" />
+ <protected-broadcast android:name="android.btopp.intent.action.OPEN_INBOUND" />
+ <protected-broadcast android:name="android.btopp.intent.action.TRANSFER_COMPLETE" />
+ <protected-broadcast android:name="android.btopp.intent.action.ACCEPT" />
+ <protected-broadcast android:name="android.btopp.intent.action.DECLINE" />
+ <protected-broadcast android:name="com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN" />
+ <protected-broadcast android:name="com.android.bluetooth.pbap.authchall" />
+ <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
+ <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
+ <protected-broadcast android:name="com.android.bluetooth.pbap.authcancelled" />
+ <protected-broadcast android:name="com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT" />
+ <protected-broadcast android:name="com.android.bluetooth.sap.action.DISCONNECT_ACTION" />
+
+ <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
+
+ <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_DETACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_HANDSHAKE" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
+
+ <protected-broadcast android:name="android.intent.action.HEADSET_PLUG" />
+ <protected-broadcast android:name="android.media.action.HDMI_AUDIO_PLUG" />
+ <protected-broadcast android:name="android.media.action.MICROPHONE_MUTE_CHANGED" />
+ <protected-broadcast android:name="android.media.action.SPEAKERPHONE_STATE_CHANGED" />
+
+ <protected-broadcast android:name="android.media.AUDIO_BECOMING_NOISY" />
+ <protected-broadcast android:name="android.media.RINGER_MODE_CHANGED" />
+ <protected-broadcast android:name="android.media.VIBRATE_SETTING_CHANGED" />
+ <protected-broadcast android:name="android.media.VOLUME_CHANGED_ACTION" />
+ <protected-broadcast android:name="android.media.MASTER_VOLUME_CHANGED_ACTION" />
+ <protected-broadcast android:name="android.media.MASTER_MUTE_CHANGED_ACTION" />
+ <protected-broadcast android:name="android.media.MASTER_MONO_CHANGED_ACTION" />
+ <protected-broadcast android:name="android.media.MASTER_BALANCE_CHANGED_ACTION" />
+ <protected-broadcast android:name="android.media.SCO_AUDIO_STATE_CHANGED" />
+ <protected-broadcast android:name="android.media.ACTION_SCO_AUDIO_STATE_UPDATED" />
+
+ <protected-broadcast android:name="android.intent.action.MEDIA_REMOVED" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_UNMOUNTED" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_CHECKING" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_NOFS" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_MOUNTED" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_SHARED" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_UNSHARED" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_BAD_REMOVAL" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_UNMOUNTABLE" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_EJECT" />
+
+ <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL" />
+ <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+ <!-- @deprecated. Only {@link android.net.ConnectivityManager.CONNECTIVITY_ACTION} is sent. -->
+ <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" />
+ <protected-broadcast android:name="android.net.conn.DATA_ACTIVITY_CHANGE" />
+ <protected-broadcast android:name="android.net.conn.RESTRICT_BACKGROUND_CHANGED" />
+ <protected-broadcast android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />
+ <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED" />
+
+ <protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
+
+ <!-- For OMAPI -->
+ <protected-broadcast android:name="android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED" />
+
+ <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
+ <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+ <protected-broadcast android:name="android.nfc.action.REQUIRE_UNLOCK_FOR_NFC" />
+ <protected-broadcast android:name="com.android.nfc.action.LLCP_UP" />
+ <protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" />
+ <protected-broadcast android:name="com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.ALLOW_CONNECT" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.DENY_CONNECT" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.TIMEOUT_CONNECT" />
+ <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
+ <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
+ <protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
+ <!-- For NFC to BT handover -->
+ <protected-broadcast android:name="android.btopp.intent.action.WHITELIST_DEVICE" />
+ <protected-broadcast android:name="android.btopp.intent.action.STOP_HANDOVER_TRANSFER" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER" />
+
+ <protected-broadcast android:name="android.net.action.CLEAR_DNS_CACHE" />
+ <protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
+
+ <protected-broadcast android:name="android.os.UpdateLock.UPDATE_LOCK_CHANGED" />
+
+ <protected-broadcast android:name="android.intent.action.DREAMING_STARTED" />
+ <protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" />
+ <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
+
+ <protected-broadcast android:name="com.android.server.stats.action.TRIGGER_COLLECTION" />
+
+ <protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
+ <protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
+ <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
+ <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
+ <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
+ <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
+ <protected-broadcast android:name="com.android.internal.action.EUICC_FACTORY_RESET" />
+ <protected-broadcast android:name="com.android.server.usb.ACTION_OPEN_IN_APPS" />
+ <protected-broadcast android:name="com.android.server.am.DELETE_DUMPHEAP" />
+ <protected-broadcast android:name="com.android.server.net.action.SNOOZE_WARNING" />
+ <protected-broadcast android:name="com.android.server.net.action.SNOOZE_RAPID" />
+ <protected-broadcast android:name="com.android.server.wifi.ACTION_SHOW_SET_RANDOMIZATION_DETAILS" />
+ <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_APP" />
+ <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_APP" />
+ <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_DISMISSED" />
+ <protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_ALLOWED_CARRIER" />
+ <protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_DISALLOWED_CARRIER" />
+ <protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_DISMISSED" />
+ <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION" />
+ <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK" />
+ <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK" />
+ <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE" />
+ <protected-broadcast android:name="com.android.server.wifi.wakeup.DISMISS_NOTIFICATION" />
+ <protected-broadcast android:name="com.android.server.wifi.wakeup.OPEN_WIFI_PREFERENCES" />
+ <protected-broadcast android:name="com.android.server.wifi.wakeup.OPEN_WIFI_SETTINGS" />
+ <protected-broadcast android:name="com.android.server.wifi.wakeup.TURN_OFF_WIFI_WAKE" />
+ <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
+ <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.LINK_CONFIGURATION_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.CONFIGURED_NETWORKS_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.action.NETWORK_SETTINGS_RESET" />
+ <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT" />
+ <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_ICON" />
+ <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST" />
+ <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION" />
+ <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW" />
+ <protected-broadcast android:name="android.net.wifi.action.REFRESH_USER_PROVISIONING" />
+ <protected-broadcast android:name="android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION" />
+ <protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.supplicant.STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.p2p.STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.p2p.DISCOVERY_STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.p2p.THIS_DEVICE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.p2p.PEERS_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.p2p.CONNECTION_STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED" />
+ <protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
+ <!-- This broadcast is no longer sent in S but it should stay protected to avoid third party
+ apps broadcasting this and confusing old system apps that may not have been updated. -->
+ <protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" />
+ <protected-broadcast
+ android:name="android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED" />
+ <protected-broadcast android:name="android.net.scoring.SCORE_NETWORKS" />
+ <protected-broadcast android:name="android.net.scoring.SCORER_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE" />
+ <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE" />
+ <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
+ <protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" />
+ <protected-broadcast android:name="android.intent.action.APPLICATION_RESTRICTIONS_CHANGED" />
+ <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES" />
+ <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT" />
+ <protected-broadcast android:name="com.android.server.adb.WIRELESS_DEBUG_STATUS" />
+
+ <!-- Legacy -->
+ <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
+ <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
+
+ <protected-broadcast android:name="com.android.server.ACTION_TRIGGER_IDLE" />
+
+ <protected-broadcast android:name="android.intent.action.HDMI_PLUGGED" />
+
+ <protected-broadcast android:name="android.intent.action.PHONE_STATE" />
+
+ <protected-broadcast android:name="android.intent.action.SUB_DEFAULT_CHANGED" />
+
+ <protected-broadcast android:name="android.location.PROVIDERS_CHANGED" />
+ <protected-broadcast android:name="android.location.MODE_CHANGED" />
+ <protected-broadcast android:name="android.location.action.GNSS_CAPABILITIES_CHANGED" />
+
+ <protected-broadcast android:name="android.net.proxy.PAC_REFRESH" />
+
+ <protected-broadcast android:name="android.telecom.action.DEFAULT_DIALER_CHANGED" />
+ <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED" />
+ <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_CREATED" />
+ <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_LOST" />
+ <protected-broadcast android:name="android.intent.action.CONTENT_CHANGED" />
+ <protected-broadcast android:name="android.provider.Telephony.MMS_DOWNLOADED" />
+
+ <protected-broadcast
+ android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
+
+ <!-- Defined in RestrictionsManager -->
+ <protected-broadcast
+ android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
+ <!-- Defined in RestrictionsManager -->
+
+ <protected-broadcast android:name="android.intent.action.REQUEST_PERMISSION" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_STARTED" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_DONE" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_PROGRESS" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_DONE" />
+
+ <protected-broadcast android:name="android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED" />
+
+ <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE" />
+ <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" />
+
+ <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
+ <protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" />
+ <protected-broadcast android:name="android.app.action.RESET_PROTECTION_POLICY_CHANGED" />
+ <protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
+ <protected-broadcast android:name="android.app.action.MANAGED_USER_CREATED" />
+
+ <!-- Added in N -->
+ <protected-broadcast android:name="android.intent.action.ANR" />
+ <protected-broadcast android:name="android.intent.action.CALL" />
+ <protected-broadcast android:name="android.intent.action.CALL_PRIVILEGED" />
+ <protected-broadcast android:name="android.intent.action.DROPBOX_ENTRY_ADDED" />
+ <protected-broadcast android:name="android.intent.action.INPUT_METHOD_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.internal_sim_state_changed" />
+ <protected-broadcast android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
+ <protected-broadcast android:name="android.intent.action.PRECISE_CALL_STATE" />
+ <protected-broadcast android:name="android.intent.action.SUBSCRIPTION_PHONE_STATE" />
+ <protected-broadcast android:name="android.intent.action.USER_INFO_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.USER_UNLOCKED" />
+ <protected-broadcast android:name="android.intent.action.WALLPAPER_CHANGED" />
+
+ <protected-broadcast android:name="android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.app.action.CHOOSE_PRIVATE_KEY_ALIAS" />
+ <protected-broadcast android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
+ <protected-broadcast android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED" />
+ <protected-broadcast android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ <protected-broadcast android:name="android.app.action.LOCK_TASK_ENTERING" />
+ <protected-broadcast android:name="android.app.action.LOCK_TASK_EXITING" />
+ <protected-broadcast android:name="android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE" />
+ <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_CHANGED" />
+ <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_EXPIRING" />
+ <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_FAILED" />
+ <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" />
+ <protected-broadcast android:name="com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION" />
+ <protected-broadcast android:name="com.android.server.ACTION_PROFILE_OFF_DEADLINE" />
+ <protected-broadcast android:name="com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION" />
+
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+
+ <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
+ <protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
+ <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
+ <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
+ <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
+ <protected-broadcast android:name="android.content.syncmanager.SYNC_ALARM" />
+ <protected-broadcast android:name="android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION" />
+ <protected-broadcast android:name="android.media.STREAM_DEVICES_CHANGED_ACTION" />
+ <protected-broadcast android:name="android.media.STREAM_MUTE_CHANGED_ACTION" />
+ <protected-broadcast android:name="android.net.sip.SIP_SERVICE_UP" />
+ <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.os.action.CHARGING" />
+ <protected-broadcast android:name="android.os.action.DISCHARGING" />
+ <protected-broadcast android:name="android.search.action.SEARCHABLES_CHANGED" />
+ <protected-broadcast android:name="android.security.STORAGE_CHANGED" />
+ <protected-broadcast android:name="android.security.action.TRUST_STORE_CHANGED" />
+ <protected-broadcast android:name="android.security.action.KEYCHAIN_CHANGED" />
+ <protected-broadcast android:name="android.security.action.KEY_ACCESS_CHANGED" />
+ <protected-broadcast android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_REGISTERED" />
+ <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_UNREGISTERED" />
+ <protected-broadcast android:name="android.telecom.action.POST_CALL" />
+ <protected-broadcast android:name="android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION" />
+ <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.SECRET_CODE" />
+ <protected-broadcast android:name="android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION" />
+ <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_PLANS_CHANGED" />
+
+ <protected-broadcast android:name="com.android.bluetooth.btservice.action.ALARM_WAKEUP" />
+ <protected-broadcast android:name="com.android.server.action.NETWORK_STATS_POLL" />
+ <protected-broadcast android:name="com.android.server.action.NETWORK_STATS_UPDATED" />
+ <protected-broadcast android:name="com.android.server.timedetector.NetworkTimeUpdateService.action.POLL" />
+ <protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
+ <protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
+ <protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" />
+ <protected-broadcast android:name="com.android.settings.network.DELETE_SUBSCRIPTION" />
+ <protected-broadcast android:name="com.android.settings.network.SWITCH_TO_SUBSCRIPTION" />
+ <protected-broadcast android:name="com.android.settings.wifi.action.NETWORK_REQUEST" />
+
+ <protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
+ <protected-broadcast android:name="NotificationHistoryDatabase.CLEANUP" />
+ <protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
+ <protected-broadcast android:name="EventConditionProvider.EVALUATE" />
+ <protected-broadcast android:name="SnoozeHelper.EVALUATE" />
+ <protected-broadcast android:name="wifi_scan_available" />
+
+ <protected-broadcast android:name="action.cne.started" />
+ <protected-broadcast android:name="android.content.jobscheduler.JOB_DEADLINE_EXPIRED" />
+ <protected-broadcast android:name="android.intent.action.ACTION_UNSOL_RESPONSE_OEM_HOOK_RAW" />
+ <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_SUPL" />
+ <protected-broadcast android:name="android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED" />
+ <protected-broadcast android:name="android.os.storage.action.VOLUME_STATE_CHANGED" />
+ <protected-broadcast android:name="android.os.storage.action.DISK_SCANNED" />
+ <protected-broadcast android:name="com.android.server.action.UPDATE_TWILIGHT_STATE" />
+ <protected-broadcast android:name="com.android.server.action.RESET_TWILIGHT_AUTO" />
+ <protected-broadcast android:name="com.android.server.device_idle.STEP_IDLE_STATE" />
+ <protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" />
+ <protected-broadcast android:name="com.android.server.Wifi.action.TOGGLE_PNO" />
+ <protected-broadcast android:name="intent.action.ACTION_RF_BAND_INFO" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_RESOURCE_GRANTED" />
+ <protected-broadcast android:name="android.app.action.NETWORK_LOGS_AVAILABLE" />
+ <protected-broadcast android:name="android.app.action.SECURITY_LOGS_AVAILABLE" />
+ <protected-broadcast android:name="android.app.action.COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED" />
+
+ <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED" />
+ <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_CHANGED" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED" />
+ <protected-broadcast android:name="android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED" />
+ <protected-broadcast android:name="android.app.action.APP_BLOCK_STATE_CHANGED" />
+
+ <protected-broadcast android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
+ <protected-broadcast android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS" />
+
+ <protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
+
+ <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+ <protected-broadcast android:name="android.accounts.action.ACCOUNT_REMOVED" />
+ <protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
+
+ <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
+
+ <protected-broadcast android:name="android.net.sip.action.SIP_INCOMING_CALL" />
+ <protected-broadcast android:name="com.android.phone.SIP_ADD_PHONE" />
+ <protected-broadcast android:name="android.net.sip.action.SIP_REMOVE_PROFILE" />
+ <protected-broadcast android:name="android.net.sip.action.SIP_SERVICE_UP" />
+ <protected-broadcast android:name="android.net.sip.action.SIP_CALL_OPTION_CHANGED" />
+ <protected-broadcast android:name="android.net.sip.action.START_SIP" />
+
+ <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_CONNECTED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED" />
+
+ <protected-broadcast android:name="android.bluetooth.input.profile.action.HANDSHAKE" />
+ <protected-broadcast android:name="android.bluetooth.input.profile.action.REPORT" />
+
+ <protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
+
+ <protected-broadcast android:name="com.android.server.fingerprint.ACTION_LOCKOUT_RESET" />
+ <protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
+
+ <protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
+ <protected-broadcast android:name="android.server.notification.action.ENABLE_NAS" />
+ <protected-broadcast android:name="android.server.notification.action.DISABLE_NAS" />
+ <protected-broadcast android:name="android.server.notification.action.LEARNMORE_NAS" />
+
+ <protected-broadcast android:name="com.android.internal.location.ALARM_WAKEUP" />
+ <protected-broadcast android:name="com.android.internal.location.ALARM_TIMEOUT" />
+ <protected-broadcast android:name="android.intent.action.GLOBAL_BUTTON" />
+
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
+ <protected-broadcast android:name="com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK" />
+
+ <protected-broadcast android:name="android.intent.action.PROFILE_ACCESSIBLE" />
+ <protected-broadcast android:name="android.intent.action.PROFILE_INACCESSIBLE" />
+
+ <protected-broadcast android:name="com.android.server.retaildemo.ACTION_RESET_DEMO" />
+
+ <protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" />
+
+ <!-- Added in O -->
+ <protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
+ <protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
+ <protected-broadcast android:name="android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED" />
+
+ <protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
+ <protected-broadcast android:name="android.os.action.USER_RESTRICTIONS_CHANGED" />
+ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT" />
+ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED" />
+ <protected-broadcast android:name="android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
+ <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
+ <protected-broadcast android:name="com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" />
+
+ <!-- Made protected in P (was introduced in JB-MR2) -->
+ <protected-broadcast android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
+ <protected-broadcast android:name="android.telephony.euicc.action.OTA_STATUS_CHANGED" />
+
+ <!-- Added in P -->
+ <protected-broadcast android:name="android.app.action.PROFILE_OWNER_CHANGED" />
+ <protected-broadcast android:name="android.app.action.TRANSFER_OWNERSHIP_COMPLETE" />
+ <protected-broadcast android:name="android.app.action.AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE" />
+ <protected-broadcast android:name="android.app.action.STATSD_STARTED" />
+ <protected-broadcast android:name="com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET" />
+ <protected-broadcast android:name="com.android.server.biometrics.face.ACTION_LOCKOUT_RESET" />
+
+ <!-- For IdleController -->
+ <protected-broadcast android:name="android.intent.action.DOCK_IDLE" />
+ <protected-broadcast android:name="android.intent.action.DOCK_ACTIVE" />
+
+ <!-- Added in Q -->
+ <protected-broadcast android:name="android.content.pm.action.SESSION_UPDATED" />
+ <protected-broadcast android:name="android.settings.action.GRAYSCALE_CHANGED" />
+
+ <!-- For CarIdlenessTracker -->
+ <protected-broadcast android:name="com.android.server.jobscheduler.GARAGE_MODE_ON" />
+ <protected-broadcast android:name="com.android.server.jobscheduler.GARAGE_MODE_OFF" />
+ <protected-broadcast android:name="com.android.server.jobscheduler.FORCE_IDLE" />
+ <protected-broadcast android:name="com.android.server.jobscheduler.UNFORCE_IDLE" />
+
+ <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL" />
+
+ <protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" />
+
+ <!-- Added in R -->
+ <protected-broadcast android:name="android.app.action.RESET_PROTECTION_POLICY_CHANGED" />
+
+ <!-- For tether entitlement recheck-->
+ <protected-broadcast
+ android:name="com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM" />
+
+ <!-- Made protected in S (was added in R) -->
+ <protected-broadcast android:name="com.android.internal.intent.action.BUGREPORT_REQUESTED" />
+
+ <!-- Added in S -->
+ <protected-broadcast android:name="android.scheduling.action.REBOOT_READY" />
+ <protected-broadcast android:name="android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED" />
+ <protected-broadcast android:name="android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.app.action.SHOW_NEW_USER_DISCLAIMER" />
+
+ <!-- Moved from packages/services/Telephony in T -->
+ <protected-broadcast android:name="android.telecom.action.CURRENT_TTY_MODE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.SERVICE_STATE" />
+ <protected-broadcast android:name="android.intent.action.RADIO_TECHNOLOGY" />
+ <protected-broadcast android:name="android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.EMERGENCY_CALL_STATE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.SIG_STR" />
+ <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
+ <protected-broadcast android:name="android.intent.action.DATA_STALL_DETECTED" />
+ <protected-broadcast android:name="android.intent.action.SIM_STATE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
+ <protected-broadcast android:name="android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS" />
+ <protected-broadcast android:name="android.intent.action.ACTION_MDN_STATE_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.SERVICE_PROVIDERS_UPDATED" />
+ <protected-broadcast android:name="android.provider.Telephony.SIM_FULL" />
+ <protected-broadcast android:name="com.android.internal.telephony.carrier_key_download_alarm" />
+ <protected-broadcast android:name="com.android.internal.telephony.data-restart-trysetup" />
+ <protected-broadcast android:name="com.android.internal.telephony.data-stall" />
+ <protected-broadcast android:name="com.android.internal.telephony.provisioning_apn_alarm" />
+ <protected-broadcast android:name="android.intent.action.DATA_SMS_RECEIVED" />
+ <protected-broadcast android:name="android.provider.Telephony.SMS_RECEIVED" />
+ <protected-broadcast android:name="android.provider.Telephony.SMS_DELIVER" />
+ <protected-broadcast android:name="android.provider.Telephony.SMS_REJECTED" />
+ <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
+ <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
+ <protected-broadcast android:name="android.provider.Telephony.SMS_CB_RECEIVED" />
+ <protected-broadcast android:name="android.provider.action.SMS_EMERGENCY_CB_RECEIVED" />
+ <protected-broadcast android:name="android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED" />
+ <protected-broadcast android:name="android.provider.Telephony.SECRET_CODE" />
+ <protected-broadcast android:name="com.android.internal.stk.command" />
+ <protected-broadcast android:name="com.android.internal.stk.session_end" />
+ <protected-broadcast android:name="com.android.internal.stk.icc_status_change" />
+ <protected-broadcast android:name="com.android.internal.stk.alpha_notify" />
+ <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
+ <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED" />
+ <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE" />
+ <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
+ <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE" />
+ <protected-broadcast android:name="com.android.internal.telephony.PROVISION" />
+ <protected-broadcast android:name="com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED" />
+ <protected-broadcast android:name="com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED" />
+ <protected-broadcast android:name="com.android.intent.isim_refresh" />
+ <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_AVAILABLE" />
+ <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_UNAVAILABLE" />
+ <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_DIED" />
+ <protected-broadcast android:name="com.android.ims.ACTION_PRESENCE_CHANGED" />
+ <protected-broadcast android:name="com.android.ims.ACTION_PUBLISH_STATUS_CHANGED" />
+ <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
+ <protected-broadcast android:name="com.android.ims.IMS_SERVICE_DOWN" />
+ <protected-broadcast android:name="com.android.ims.IMS_INCOMING_CALL" />
+ <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" />
+ <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_DOWN" />
+ <protected-broadcast android:name="com.android.imsconnection.DISCONNECTED" />
+ <protected-broadcast android:name="com.android.intent.action.IMS_FEATURE_CHANGED" />
+ <protected-broadcast android:name="com.android.intent.action.IMS_CONFIG_CHANGED" />
+ <protected-broadcast android:name="android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR" />
+ <protected-broadcast android:name="com.android.phone.vvm.omtp.sms.REQUEST_SENT" />
+ <protected-broadcast android:name="com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT" />
+ <protected-broadcast android:name="com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED" />
+ <protected-broadcast android:name="com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO" />
+ <protected-broadcast android:name="com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD" />
+ <protected-broadcast android:name="com.android.internal.telephony.action.COUNTRY_OVERRIDE" />
+ <protected-broadcast android:name="com.android.internal.telephony.OPEN_DEFAULT_SMS_APP" />
+ <protected-broadcast android:name="com.android.internal.telephony.ACTION_TEST_OVERRIDE_CARRIER_ID" />
+ <protected-broadcast android:name="android.telephony.action.SIM_CARD_STATE_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.SIM_APPLICATION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.SIM_SLOT_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.TOGGLE_PROVISION" />
+ <protected-broadcast android:name="android.telephony.action.NETWORK_COUNTRY_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.MULTI_SIM_CONFIG_CHANGED" />
+ <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_RESET" />
+ <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_PCO_VALUE" />
+ <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE" />
+ <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_REDIRECTED" />
+ <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED" />
+ <protected-broadcast android:name="com.android.phone.settings.CARRIER_PROVISIONING" />
+ <protected-broadcast android:name="com.android.phone.settings.TRIGGER_CARRIER_PROVISIONING" />
+ <protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" />
+ <protected-broadcast android:name="android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED" />
+ <protected-broadcast android:name="android.intent.action.ACTION_MANAGED_ROAMING_IND" />
+ <protected-broadcast android:name="android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE" />
+
+ <!-- Added in T -->
+ <protected-broadcast android:name="android.app.action.LOST_MODE_LOCATION_UPDATE" />
+
+ <!-- ====================================================================== -->
+ <!-- RUNTIME PERMISSIONS -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Grouping for platform runtime permissions is not accessible to apps
+ @hide
+ @SystemApi
+ @TestApi
+ -->
+ <permission-group android:name="android.permission-group.UNDEFINED"
+ android:priority="100" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing user's contacts including personal profile -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for runtime permissions related to contacts and profiles on this
+ device. -->
+ <permission-group android:name="android.permission-group.CONTACTS"
+ android:icon="@drawable/perm_group_contacts"
+ android:label="@string/permgrouplab_contacts"
+ android:description="@string/permgroupdesc_contacts"
+ android:priority="100" />
+
+ <!-- Allows an application to read the user's contacts data.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.READ_CONTACTS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readContacts"
+ android:description="@string/permdesc_readContacts"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to write the user's contacts data.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.WRITE_CONTACTS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_writeContacts"
+ android:description="@string/permdesc_writeContacts"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to set default account for new contacts.
+ <p> This permission is only granted to system applications fulfilling the Contacts app role.
+ <p>Protection level: internal|role
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"
+ android:protectionLevel="internal|role" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing user's calendar -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for runtime permissions related to user's calendar. -->
+ <permission-group android:name="android.permission-group.CALENDAR"
+ android:icon="@drawable/perm_group_calendar"
+ android:label="@string/permgrouplab_calendar"
+ android:description="@string/permgroupdesc_calendar"
+ android:priority="200" />
+
+ <!-- Allows an application to read the user's calendar data.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.READ_CALENDAR"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readCalendar"
+ android:description="@string/permdesc_readCalendar"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to write the user's calendar data.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.WRITE_CALENDAR"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_writeCalendar"
+ android:description="@string/permdesc_writeCalendar"
+ android:protectionLevel="dangerous" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing and modifying user's SMS messages -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Allows accessing the messages on ICC
+ @hide Used internally. -->
+ <permission android:name="android.permission.ACCESS_MESSAGES_ON_ICC"
+ android:protectionLevel="signature" />
+
+ <!-- Used for runtime permissions related to user's SMS messages. -->
+ <permission-group android:name="android.permission-group.SMS"
+ android:icon="@drawable/perm_group_sms"
+ android:label="@string/permgrouplab_sms"
+ android:description="@string/permgroupdesc_sms"
+ android:priority="300" />
+
+ <!-- Allows an application to send SMS messages.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.SEND_SMS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_sendSms"
+ android:description="@string/permdesc_sendSms"
+ android:permissionFlags="costsMoney|hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to receive SMS messages.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.RECEIVE_SMS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_receiveSms"
+ android:description="@string/permdesc_receiveSms"
+ android:permissionFlags="hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to read SMS messages.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.READ_SMS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readSms"
+ android:description="@string/permdesc_readSms"
+ android:permissionFlags="hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to receive WAP push messages.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.RECEIVE_WAP_PUSH"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_receiveWapPush"
+ android:description="@string/permdesc_receiveWapPush"
+ android:permissionFlags="hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to monitor incoming MMS messages.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.RECEIVE_MMS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_receiveMms"
+ android:description="@string/permdesc_receiveMms"
+ android:permissionFlags="hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- @SystemApi @TestApi Allows an application to forward cell broadcast messages to the cell
+ broadcast module. This is required in order to bind to the cell broadcast service, and
+ ensures that only the system can forward messages to it.
+
+ <p>Protection level: signature
+
+ @hide -->
+ <permission android:name="android.permission.BIND_CELL_BROADCAST_SERVICE"
+ android:label="@string/permlab_bindCellBroadcastService"
+ android:description="@string/permdesc_bindCellBroadcastService"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @TestApi Allows an application to read previously received cell broadcast
+ messages and to register a content observer to get notifications when
+ a cell broadcast has been received and added to the database. For
+ emergency alerts, the database is updated immediately after the
+ alert dialog and notification sound/vibration/speech are presented.
+ The "read" column is then updated after the user dismisses the alert.
+ This enables supplementary emergency assistance apps to start loading
+ additional emergency information (if Internet access is available)
+ when the alert is first received, and to delay presenting the info
+ to the user until after the initial alert dialog is dismissed.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+
+ @hide Pending API council approval -->
+ <permission android:name="android.permission.READ_CELL_BROADCASTS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readCellBroadcasts"
+ android:description="@string/permdesc_readCellBroadcasts"
+ android:permissionFlags="hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- @SystemApi @hide Allows an application to communicate over satellite.
+ Only granted if the application is a system app.-->
+ <permission android:name="android.permission.SATELLITE_COMMUNICATION"
+ android:protectionLevel="role|signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to bind with satellite service.
+ Only granted if the application is a system app.-->
+ <permission android:name="android.permission.BIND_SATELLITE_SERVICE"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- @hide Allows an application to bind with satellite gateway service.
+ Only granted if the application is a system app.-->
+ <permission android:name="android.permission.BIND_SATELLITE_GATEWAY_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing external storage -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for runtime permissions related to the shared external storage. -->
+ <permission-group android:name="android.permission-group.STORAGE"
+ android:icon="@drawable/perm_group_storage"
+ android:label="@string/permgrouplab_storage"
+ android:description="@string/permgroupdesc_storage"
+ android:priority="900" />
+
+ <!-- Allows an application to read from external storage.
+ <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
+ granted this permission.</p>
+ <p>This permission is enforced starting in API level 19. Before API level 19, this
+ permission is not enforced and all apps still have access to read from external storage.
+ You can test your app with the permission enforced by enabling <em>Protect USB
+ storage</em> under Developer options in the Settings app on a device running Android 4.1 or
+ higher.</p>
+ <p>Also starting in API level 19, this permission is <em>not</em> required to
+ read/write files in your application-specific directories returned by
+ {@link android.content.Context#getExternalFilesDir} and
+ {@link android.content.Context#getExternalCacheDir}.
+ <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 4 or higher.
+
+ <p> This is a soft restricted permission which cannot be held by an app it its
+ full form until the installer on record whitelists the permission.
+ Specifically, if the permission is allowlisted the holder app can access
+ external storage and the visual and aural media collections while if the
+ permission is not allowlisted the holder app can only access to the visual
+ and aural medial collections. Also the permission is immutably restricted
+ meaning that the allowlist state can be specified only at install time and
+ cannot change until the app is installed. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_sdcardRead"
+ android:description="@string/permdesc_sdcardRead"
+ android:permissionFlags="softRestricted|immutablyRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- Required to be able to read audio files from shared storage.
+ <p>Protection level: dangerous -->
+ <permission-group android:name="android.permission-group.READ_MEDIA_AURAL"
+ android:icon="@drawable/perm_group_read_media_aural"
+ android:label="@string/permgrouplab_readMediaAural"
+ android:description="@string/permgroupdesc_readMediaAural"
+ android:priority="950" />
+
+ <!-- Allows an application to read audio files from external storage.
+ <p>This permission is enforced starting in API level
+ {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+ For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+ must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.READ_MEDIA_AUDIO"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readMediaAudio"
+ android:description="@string/permdesc_readMediaAudio"
+ android:protectionLevel="dangerous" />
+
+ <!-- Required to be able to read image and video files from shared storage.
+ <p>Protection level: dangerous -->
+ <permission-group android:name="android.permission-group.READ_MEDIA_VISUAL"
+ android:icon="@drawable/perm_group_read_media_visual"
+ android:label="@string/permgrouplab_readMediaVisual"
+ android:description="@string/permgroupdesc_readMediaVisual"
+ android:priority="1000" />
+
+ <!-- Allows an application to read audio files from external storage.
+ <p>This permission is enforced starting in API level
+ {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+ For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+ must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.READ_MEDIA_VIDEO"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readMediaVideo"
+ android:description="@string/permdesc_readMediaVideo"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to read image files from external storage.
+ <p>This permission is enforced starting in API level
+ {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+ For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+ must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.READ_MEDIA_IMAGES"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readMediaImage"
+ android:description="@string/permdesc_readMediaImage"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to read image or video files from external storage that a user has
+ selected via the permission prompt photo picker. Apps can check this permission to verify that
+ a user has decided to use the photo picker, instead of granting access to
+ {@link #READ_MEDIA_IMAGES or #READ_MEDIA_VIDEO}. It does not prevent apps from accessing the
+ standard photo picker manually.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readVisualUserSelect"
+ android:description="@string/permdesc_readVisualUserSelect"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to write to external storage.
+ <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 4 or higher.
+ <p>Starting in API level 19, this permission is <em>not</em> required to
+ read/write files in your application-specific directories returned by
+ {@link android.content.Context#getExternalFilesDir} and
+ {@link android.content.Context#getExternalCacheDir}.
+ <p>If this permission is not allowlisted for an app that targets an API level before
+ {@link android.os.Build.VERSION_CODES#Q} this permission cannot be granted to apps.</p>
+ <p>Protection level: dangerous</p>
+ -->
+ <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_sdcardWrite"
+ android:description="@string/permdesc_sdcardWrite"
+ android:permissionFlags="softRestricted|immutablyRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to access any geographic locations persisted in the
+ user's shared collection.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.ACCESS_MEDIA_LOCATION"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_mediaLocation"
+ android:description="@string/permdesc_mediaLocation"
+ android:protectionLevel="dangerous" />
+
+ <!-- @hide @SystemApi @TestApi
+ Allows an application to modify OBB files visible to other apps. -->
+ <permission android:name="android.permission.WRITE_OBB"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application a broad access to external storage in scoped storage.
+ Intended to be used by few apps that need to manage files on behalf of the users.
+ <p>Protection level: signature|appop|preinstalled -->
+ <permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:protectionLevel="signature|appop|preinstalled" />
+
+ <!-- Allows an application to modify and delete media files on this device or any connected
+ storage device without user confirmation. Applications must already be granted the
+ {@link #READ_EXTERNAL_STORAGE} or {@link #MANAGE_EXTERNAL_STORAGE}} permissions for this
+ permission to take effect.
+ <p>Even if applications are granted this permission, if applications want to modify or
+ delete media files, they also must get the access by calling
+ {@link android.provider.MediaStore#createWriteRequest(ContentResolver, Collection)},
+ {@link android.provider.MediaStore#createDeleteRequest(ContentResolver, Collection)}, or
+ {@link android.provider.MediaStore#createTrashRequest(ContentResolver, Collection, boolean)}.
+ <p>This permission doesn't give read or write access directly. It only prevents the user
+ confirmation dialog for these requests.
+ <p>If applications are not granted {@link #ACCESS_MEDIA_LOCATION}, the system also pops up
+ the user confirmation dialog for the write request.
+ <p>Protection level: signature|appop|preinstalled -->
+ <permission android:name="android.permission.MANAGE_MEDIA"
+ android:protectionLevel="signature|appop|preinstalled" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing the device location -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that allow accessing the device location. -->
+ <permission-group android:name="android.permission-group.LOCATION"
+ android:icon="@drawable/perm_group_location"
+ android:label="@string/permgrouplab_location"
+ android:description="@string/permgroupdesc_location"
+ android:priority="400" />
+
+ <!-- Allows an app to access precise location.
+ Alternatively, you might want {@link #ACCESS_COARSE_LOCATION}.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACCESS_FINE_LOCATION"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_accessFineLocation"
+ android:description="@string/permdesc_accessFineLocation"
+ android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- Allows an app to access approximate location.
+ Alternatively, you might want {@link #ACCESS_FINE_LOCATION}.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACCESS_COARSE_LOCATION"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_accessCoarseLocation"
+ android:description="@string/permdesc_accessCoarseLocation"
+ android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- Allows an app to access location in the background. If you're requesting this permission,
+ you must also request either {@link #ACCESS_COARSE_LOCATION} or
+ {@link #ACCESS_FINE_LOCATION}. Requesting this permission by itself doesn't give you
+ location access.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_accessBackgroundLocation"
+ android:permissionFlags="hardRestricted"
+ android:description="@string/permdesc_accessBackgroundLocation"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- Allows an application (emergency or advanced driver-assistance app) to bypass
+ location settings.
+ <p>Not for use by third-party applications.
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.LOCATION_BYPASS"
+ android:protectionLevel="signature|privileged"/>
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing the call log -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated telephony features. -->
+ <permission-group android:name="android.permission-group.CALL_LOG"
+ android:icon="@drawable/perm_group_call_log"
+ android:label="@string/permgrouplab_calllog"
+ android:description="@string/permgroupdesc_calllog"
+ android:priority="450" />
+
+ <!-- Allows an application to access the IMS call service: making and
+ modifying a call
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_IMS_CALL_SERVICE"
+ android:label="@string/permlab_accessImsCallService"
+ android:description="@string/permdesc_accessImsCallService"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to perform IMS Single Registration related actions.
+ Only granted if the application is a system app AND is in the Default SMS Role.
+ The permission is revoked when the app is taken out of the Default SMS Role.
+ <p>Protection level: internal|role
+ -->
+ <permission android:name="android.permission.PERFORM_IMS_SINGLE_REGISTRATION"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to read the user's call log.
+ <p class="note"><strong>Note:</strong> If your app uses the
+ {@link #READ_CONTACTS} permission and <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 15 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 16 or higher.</p>
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.READ_CALL_LOG"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readCallLog"
+ android:description="@string/permdesc_readCallLog"
+ android:permissionFlags="hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to write (but not read) the user's
+ call log data.
+ <p class="note"><strong>Note:</strong> If your app uses the
+ {@link #WRITE_CONTACTS} permission and <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 15 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 16 or higher.</p>
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.WRITE_CALL_LOG"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_writeCallLog"
+ android:description="@string/permdesc_writeCallLog"
+ android:permissionFlags="hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to see the number being dialed during an outgoing
+ call with the option to redirect the call to a different number or
+ abort the call altogether.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+
+ @deprecated Applications should use {@link android.telecom.CallRedirectionService} instead
+ of the {@link android.content.Intent#ACTION_NEW_OUTGOING_CALL} broadcast.
+ -->
+ <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_processOutgoingCalls"
+ android:description="@string/permdesc_processOutgoingCalls"
+ android:permissionFlags="hardRestricted"
+ android:protectionLevel="dangerous" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing the device telephony -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated telephony features. -->
+ <permission-group android:name="android.permission-group.PHONE"
+ android:icon="@drawable/perm_group_phone_calls"
+ android:label="@string/permgrouplab_phone"
+ android:description="@string/permgroupdesc_phone"
+ android:priority="500" />
+
+ <!-- Allows read only access to phone state, including the current cellular network information,
+ the status of any ongoing calls, and a list of any {@link android.telecom.PhoneAccount}s
+ registered on the device.
+ <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 4 or higher.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.READ_PHONE_STATE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readPhoneState"
+ android:description="@string/permdesc_readPhoneState"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
+ granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
+ <p>Protection level: dangerous-->
+ <permission android:name="android.permission.READ_PHONE_NUMBERS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readPhoneNumbers"
+ android:description="@string/permdesc_readPhoneNumbers"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- Allows an application to initiate a phone call without going through
+ the Dialer user interface for the user to confirm the call.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.CALL_PHONE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:permissionFlags="costsMoney"
+ android:label="@string/permlab_callPhone"
+ android:description="@string/permdesc_callPhone"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to add voicemails into the system.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_addVoicemail"
+ android:description="@string/permdesc_addVoicemail"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to use SIP service.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.USE_SIP"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_use_sip"
+ android:label="@string/permlab_use_sip"
+ android:protectionLevel="dangerous"/>
+
+ <!-- Allows the app to answer an incoming phone call.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ANSWER_PHONE_CALLS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_answerPhoneCalls"
+ android:description="@string/permdesc_answerPhoneCalls"
+ android:protectionLevel="dangerous|runtime" />
+
+ <!-- Allows a calling application which manages its own calls through the self-managed
+ {@link android.telecom.ConnectionService} APIs. See
+ {@link android.telecom.PhoneAccount#CAPABILITY_SELF_MANAGED} for more information on the
+ self-managed ConnectionService APIs.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.MANAGE_OWN_CALLS"
+ android:label="@string/permlab_manageOwnCalls"
+ android:description="@string/permdesc_manageOwnCalls"
+ android:protectionLevel="normal" />
+
+ <!--Allows an app which implements the
+ {@link android.telecom.InCallService InCallService} API to be eligible to be enabled as a
+ calling companion app. This means that the Telecom framework will bind to the app's
+ InCallService implementation when there are calls active. The app can use the InCallService
+ API to view information about calls on the system and control these calls.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.CALL_COMPANION_APP"
+ android:label="@string/permlab_callCompanionApp"
+ android:description="@string/permdesc_callCompanionApp"
+ android:protectionLevel="normal" />
+
+ <!-- Exempt this uid from restrictions to background audio recoding
+ <p>Protection level: signature|privileged
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS"
+ android:label="@string/permlab_exemptFromAudioRecordRestrictions"
+ android:description="@string/permdesc_exemptFromAudioRecordRestrictions"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows a calling app to continue a call which was started in another app. An example is a
+ video calling app that wants to continue a voice call on the user's mobile network.<p>
+ When the handover of a call from one app to another takes place, there are two devices
+ which are involved in the handover; the initiating and receiving devices. The initiating
+ device is where the request to handover the call was started, and the receiving device is
+ where the handover request is confirmed by the other party.<p>
+ This permission protects access to the
+ {@link android.telecom.TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)} which
+ the receiving side of the handover uses to accept a handover.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACCEPT_HANDOVER"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android.label="@string/permlab_acceptHandover"
+ android:description="@string/permdesc_acceptHandovers"
+ android:protectionLevel="dangerous" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing the device microphone -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated with accessing
+ microphone audio from the device. Note that phone calls also capture audio
+ but are in a separate (more visible) permission group. -->
+ <permission-group android:name="android.permission-group.MICROPHONE"
+ android:icon="@drawable/perm_group_microphone"
+ android:label="@string/permgrouplab_microphone"
+ android:description="@string/permgroupdesc_microphone"
+ android:priority="600" />
+
+ <!-- Allows an application to record audio.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.RECORD_AUDIO"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_recordAudio"
+ android:description="@string/permdesc_recordAudio"
+ android:backgroundPermission="android.permission.RECORD_BACKGROUND_AUDIO"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- @SystemApi @TestApi Allows an application to record audio while in the background.
+ This permission is not intended to be held by apps.
+ <p>Protection level: internal
+ @hide -->
+ <permission android:name="android.permission.RECORD_BACKGROUND_AUDIO"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_recordBackgroundAudio"
+ android:description="@string/permdesc_recordBackgroundAudio"
+ android:protectionLevel="internal|role" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for activity recognition -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated with activity recognition. -->
+ <permission-group android:name="android.permission-group.ACTIVITY_RECOGNITION"
+ android:icon="@drawable/perm_group_activity_recognition"
+ android:label="@string/permgrouplab_activityRecognition"
+ android:description="@string/permgroupdesc_activityRecognition"
+ android:priority="1000" />
+
+ <!-- Allows an application to recognize physical activity.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACTIVITY_RECOGNITION"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_activityRecognition"
+ android:description="@string/permdesc_activityRecognition"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing the vendor UCE Service -->
+ <!-- ====================================================================== -->
+
+ <!-- @hide Allows an application to Access UCE-Presence.
+ <p>Protection level: signature|privileged
+ @deprecated Framework should no longer use this permission to access the vendor UCE service
+ using AIDL, it is instead implemented by RcsCapabilityExchangeImplBase
+ -->
+ <permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="signature|privileged"/>
+
+ <!-- @hide Allows an application to Access UCE-OPTIONS.
+ <p>Protection level: signature|privileged
+ @deprecated Framework should no longer use this permission to access the vendor UCE service
+ using AIDL, it is instead implemented by RcsCapabilityExchangeImplBase
+ -->
+ <permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="signature|privileged"/>
+
+
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing the device camera -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated with accessing
+ camera or capturing images/video from the device. -->
+ <permission-group android:name="android.permission-group.CAMERA"
+ android:icon="@drawable/perm_group_camera"
+ android:label="@string/permgrouplab_camera"
+ android:description="@string/permgroupdesc_camera"
+ android:priority="700" />
+
+ <!-- Required to be able to access the camera device.
+ <p>This will automatically enforce the
+ <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">
+ uses-feature</a> manifest element for <em>all</em> camera features.
+ If you do not require all camera features or can properly operate if a camera
+ is not available, then you must modify your manifest as appropriate in order to
+ install on devices that don't support all camera features.</p>
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.CAMERA"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_camera"
+ android:description="@string/permdesc_camera"
+ android:backgroundPermission="android.permission.BACKGROUND_CAMERA"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- Required to be able to discover and connect to nearby Bluetooth devices.
+ <p>Protection level: dangerous -->
+ <permission-group android:name="android.permission-group.NEARBY_DEVICES"
+ android:icon="@drawable/perm_group_nearby_devices"
+ android:label="@string/permgrouplab_nearby_devices"
+ android:description="@string/permgroupdesc_nearby_devices"
+ android:priority="750" />
+
+ <!-- @SystemApi @TestApi Required to be able to access the camera device in the background.
+ This permission is not intended to be held by apps.
+ <p>Protection level: internal
+ @hide -->
+ <permission android:name="android.permission.BACKGROUND_CAMERA"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_backgroundCamera"
+ android:description="@string/permdesc_backgroundCamera"
+ android:protectionLevel="internal|role" />
+
+ <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
+ system only camera devices.
+ <p>Protection level: system|signature|role
+ @hide -->
+ <permission android:name="android.permission.SYSTEM_CAMERA"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_systemCamera"
+ android:description="@string/permdesc_systemCamera"
+ android:protectionLevel="system|signature|role" />
+
+ <!-- @SystemApi Allows receiving the camera service notifications when a camera is opened
+ (by a certain application package) or closed.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_cameraOpenCloseListener"
+ android:description="@string/permdesc_cameraOpenCloseListener"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows camera access by Headless System User 0 when device is running in
+ HSUM Mode.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_HEADLESS_SYSTEM_USER"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_cameraHeadlessSystemUser"
+ android:description="@string/permdesc_cameraHeadlessSystemUser"
+ android:protectionLevel="signature" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing the device sensors -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated with accessing
+ body or environmental sensors. -->
+ <permission-group android:name="android.permission-group.SENSORS"
+ android:icon="@drawable/perm_group_sensors"
+ android:label="@string/permgrouplab_sensors"
+ android:description="@string/permgroupdesc_sensors"
+ android:priority="800" />
+
+ <!-- Allows an app to access sensor data with a sampling rate greater than 200 Hz.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"
+ android:permissionGroup="android.permission-group.SENSORS"
+ android:label="@string/permlab_highSamplingRateSensors"
+ android:description="@string/permdesc_highSamplingRateSensors"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to access data from sensors that the user uses to
+ measure what is happening inside their body, such as heart rate.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.BODY_SENSORS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_bodySensors"
+ android:description="@string/permdesc_bodySensors"
+ android:backgroundPermission="android.permission.BODY_SENSORS_BACKGROUND"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to access data from sensors that the user uses to measure what is
+ happening inside their body, such as heart rate. If you're requesting this permission, you
+ must also request {@link #BODY_SENSORS}. Requesting this permission by itself doesn't give
+ you Body sensors access.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record allowlists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.BODY_SENSORS_BACKGROUND"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_bodySensors_background"
+ android:description="@string/permdesc_bodySensors_background"
+ android:protectionLevel="dangerous"
+ android:permissionFlags="hardRestricted" />
+
+ <!-- Allows an app to use fingerprint hardware.
+ <p>Protection level: normal
+ @deprecated Applications should request {@link
+ android.Manifest.permission#USE_BIOMETRIC} instead
+ -->
+ <permission android:name="android.permission.USE_FINGERPRINT"
+ android:permissionGroup="android.permission-group.SENSORS"
+ android:label="@string/permlab_useFingerprint"
+ android:description="@string/permdesc_useFingerprint"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an app to use device supported biometric modalities.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.USE_BIOMETRIC"
+ android:permissionGroup="android.permission-group.SENSORS"
+ android:label="@string/permlab_useBiometric"
+ android:description="@string/permdesc_useBiometric"
+ android:protectionLevel="normal" />
+
+ <!-- ======================================================================= -->
+ <!-- Permissions for posting notifications -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated with posting notifications
+ -->
+ <permission-group android:name="android.permission-group.NOTIFICATIONS"
+ android:icon="@drawable/ic_notifications_alerted"
+ android:label="@string/permgrouplab_notifications"
+ android:description="@string/permgroupdesc_notifications"
+ android:priority="850" />
+
+ <!-- Allows an app to post notifications
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.POST_NOTIFICATIONS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_postNotification"
+ android:description="@string/permdesc_postNotification"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- ====================================================================== -->
+ <!-- REMOVED PERMISSIONS -->
+ <!-- ====================================================================== -->
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.READ_PROFILE"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.WRITE_PROFILE"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.READ_SOCIAL_STREAM"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.WRITE_SOCIAL_STREAM"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.READ_USER_DICTIONARY"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.WRITE_USER_DICTIONARY"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.WRITE_SMS"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.MANAGE_ACCOUNTS"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.USE_CREDENTIALS"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.FLASHLIGHT"
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
+
+ <!-- ====================================================================== -->
+ <!-- INSTALL PERMISSIONS -->
+ <!-- ====================================================================== -->
+
+ <!-- ================================== -->
+ <!-- Permissions for accessing messages -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- Allows an application (Phone) to send a request to other applications
+ to handle the respond-via-message action during incoming calls.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to send SMS to premium shortcodes without user permission.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to filter carrier specific sms.
+ @hide -->
+ <permission android:name="android.permission.CARRIER_FILTER_SMS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to receive emergency cell broadcast messages,
+ to record or display them to the user.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
+ or perform processing on them. -->
+ <!-- @hide -->
+ <permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to execute contacts directory search.
+ This should only be used by ContactsProvider.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to modify the cell broadcasts configuration
+ (i.e. enable or disable channels).
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MODIFY_CELL_BROADCASTS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- =============================================================== -->
+ <!-- Permissions for setting the device alarm -->
+ <!-- =============================================================== -->
+ <eat-comment />
+
+ <!-- Allows an application to broadcast an Intent to set an alarm for the user.
+ <p>Protection level: normal
+ -->
+ <permission android:name="com.android.alarm.permission.SET_ALARM"
+ android:label="@string/permlab_setAlarm"
+ android:description="@string/permdesc_setAlarm"
+ android:protectionLevel="normal" />
+
+ <!-- =============================================================== -->
+ <!-- Permissions for accessing the user voicemail -->
+ <!-- =============================================================== -->
+ <eat-comment />
+
+ <!-- Allows an application to modify and remove existing voicemails in the system.
+ <p>Protection level: signature|privileged|role
+ -->
+ <permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows an application to read voicemails in the system.
+ <p>Protection level: signature|privileged|role
+ -->
+ <permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- ======================================= -->
+ <!-- Permissions for accessing location info -->
+ <!-- ======================================= -->
+ <eat-comment />
+
+ <!-- Allows an application to access extra location provider commands.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"
+ android:label="@string/permlab_accessLocationExtraCommands"
+ android:description="@string/permdesc_accessLocationExtraCommands"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to install a location provider into the Location Manager.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to provide location-based time zone suggestions to
+ the system server. This is needed because the system server discovers time zone providers
+ by exposed intent actions and metadata, without it any app could potentially register
+ itself as time zone provider. The system server checks for this permission.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to bind to a android.service.TimeZoneProviderService
+ for the purpose of detecting the device's time zone. This prevents arbitrary clients
+ connecting to the time zone provider service. The system server checks that the provider's
+ intent service explicitly sets this permission via the android:permission attribute of the
+ service.
+ This is only expected to be possessed by the system server outside of tests.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
+ This should only be used by HDMI-CEC service.
+ -->
+ <permission android:name="android.permission.HDMI_CEC"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- Allows an application to use location features in hardware,
+ such as the geofencing api.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.LOCATION_HARDWARE"
+ android:protectionLevel="signature|privileged|role" />
+ <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
+
+ <!-- @SystemApi Allows an application to use the Context Hub.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_CONTEXT_HUB"
+ android:protectionLevel="signature|privileged" />
+ <uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB"/>
+
+ <!-- @SystemApi Allows an application to create mock location providers for testing.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_MOCK_LOCATION"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows automotive applications to control location
+ suspend state for power management use cases.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.CONTROL_AUTOMOTIVE_GNSS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- ======================================= -->
+ <!-- Permissions for accessing networks -->
+ <!-- ======================================= -->
+ <eat-comment />
+
+ <!-- Allows applications to open network sockets.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.INTERNET"
+ android:description="@string/permdesc_createNetworkSockets"
+ android:label="@string/permlab_createNetworkSockets"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows applications to access information about networks.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.ACCESS_NETWORK_STATE"
+ android:description="@string/permdesc_accessNetworkState"
+ android:label="@string/permlab_accessNetworkState"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows applications to access information about Wi-Fi networks.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.ACCESS_WIFI_STATE"
+ android:description="@string/permdesc_accessWifiState"
+ android:label="@string/permlab_accessWifiState"
+ android:protectionLevel="normal" />
+
+ <!-- Allows applications to change Wi-Fi connectivity state.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.CHANGE_WIFI_STATE"
+ android:description="@string/permdesc_changeWifiState"
+ android:label="@string/permlab_changeWifiState"
+ android:protectionLevel="normal" />
+
+ <!-- This permission is used to let OEMs grant their trusted app access to a subset of
+ privileged wifi APIs to improve wifi performance. Allows applications to manage
+ Wi-Fi network selection related features such as enable or disable global auto-join,
+ modify connectivity scan intervals, and approve Wi-Fi Direct connections.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_WIFI_NETWORK_SELECTION"
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
+
+ <!-- Allows applications to get notified when a Wi-Fi interface request cannot
+ be satisfied without tearing down one or more other interfaces, and provide a decision
+ whether to approve the request or reject it.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_WIFI_INTERFACES"
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
+
+ <!-- @SystemApi @hide Allows apps to create and manage IPsec tunnels.
+ <p>Only granted to applications that are currently bound by the
+ system for creating and managing IPsec-based interfaces.
+ -->
+ <permission android:name="android.permission.MANAGE_IPSEC_TUNNELS"
+ android:protectionLevel="signature|appop" />
+
+ <!-- @SystemApi @hide Allows apps to create and manage Test Networks.
+ <p>Granted only to shell. CTS tests will use
+ UiAutomation.AdoptShellPermissionIdentity() to gain access.
+ -->
+ <permission android:name="android.permission.MANAGE_TEST_NETWORKS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows direct access to the <RemoteAuth>Service interfaces.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_REMOTE_AUTH"
+ android:protectionLevel="signature" />
+
+ <!-- Allows direct access to the <RemoteAuth>Service authentication methods.
+ @hide -->
+ <permission android:name="android.permission.USE_REMOTE_AUTH"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows applications to change tether state and run
+ tether carrier provisioning.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.TETHER_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allow system apps to receive broadcast
+ when a wifi network credential is changed.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to modify any wifi configuration, even if created
+ by another application. Once reconfigured the original creator cannot make any further
+ modifications.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
+
+ <!-- Allows applications to act as network scorers. @hide @SystemApi-->
+ <permission android:name="android.permission.SCORE_NETWORKS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows applications to request network
+ recommendations and scores from the NetworkScoreService.
+ @SystemApi
+ <p>Not for use by third-party applications. @hide -->
+ <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
+ android:protectionLevel="signature|setup" />
+
+ <!-- Allows applications to restart the Wi-Fi subsystem.
+ @SystemApi
+ <p>Not for use by third-party applications. @hide -->
+ <permission android:name="android.permission.RESTART_WIFI_SUBSYSTEM"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows applications to toggle airplane mode.
+ <p>Not for use by third-party or privileged applications.
+ -->
+ <permission android:name="android.permission.NETWORK_AIRPLANE_MODE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows network stack services (Connectivity and Wifi) to coordinate
+ <p>Not for use by third-party or privileged applications.
+ @SystemApi @TestApi
+ @hide This should only be used by Connectivity and Wifi Services.
+ -->
+ <permission android:name="android.permission.NETWORK_STACK"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows an application to observe network policy changes. -->
+ <permission android:name="android.permission.OBSERVE_NETWORK_POLICY"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows applications to register network factory or agent -->
+ <permission android:name="android.permission.NETWORK_FACTORY"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi @hide Allows applications to access network stats provider -->
+ <permission android:name="android.permission.NETWORK_STATS_PROVIDER"
+ android:protectionLevel="signature" />
+
+ <!-- Allows Settings and SystemUI to call methods in Networking services
+ <p>Not for use by third-party or privileged applications.
+ @SystemApi @TestApi
+ @hide This should only be used by Settings and SystemUI.
+ -->
+ <permission android:name="android.permission.NETWORK_SETTINGS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows holder to request bluetooth/wifi scan bypassing global "use location" setting and
+ location permissions.
+ <p>Not for use by third-party or privileged applications.
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"
+ android:protectionLevel="signature|companion" />
+
+ <!-- Allows SetupWizard to call methods in Networking services
+ <p>Not for use by any other third-party or privileged applications.
+ @SystemApi
+ @hide This should only be used by SetupWizard.
+ -->
+ <permission android:name="android.permission.NETWORK_SETUP_WIZARD"
+ android:protectionLevel="signature|setup" />
+
+ <!-- Allows Managed Provisioning to call methods in Networking services
+ <p>Not for use by any other third-party or privileged applications.
+ @SystemApi
+ @hide This should only be used by ManagedProvisioning app.
+ -->
+ <permission android:name="android.permission.NETWORK_MANAGED_PROVISIONING"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows Carrier Provisioning to call methods in Networking services
+ <p>Not for use by any other third-party or privileged applications.
+ @SystemApi
+ @hide This should only be used by CarrierProvisioning.
+ -->
+ <permission android:name="android.permission.NETWORK_CARRIER_PROVISIONING"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- #SystemApi @hide Allows applications to access information about LoWPAN interfaces.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.ACCESS_LOWPAN_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- #SystemApi @hide Allows applications to change LoWPAN connectivity state.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CHANGE_LOWPAN_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- #SystemApi @hide Allows applications to read LoWPAN credential.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- #SystemApi @hide Allows a service to register or unregister
+ new LoWPAN interfaces.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows changing Thread network state and access to Thread network
+ credentials such as Network Key and PSKc.
+ <p>Not for use by third-party applications.
+ @FlaggedApi("com.android.net.thread.flags.thread_enabled") -->
+ <permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- #SystemApi @hide Allows an app to bypass Private DNS.
+ <p>Not for use by third-party applications.
+ TODO: publish as system API in next API release. -->
+ <permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can
+ be increased when the device is stationary in order to save power.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows applications to update Wifi/Cellular coex channels to avoid.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi @hide Allows applications to access Wifi/Cellular coex channels being avoided.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi @hide Allows system APK to manage country code.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_WIFI_COUNTRY_CODE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows an application to manage an automotive device's application network
+ preference as it relates to OEM_PAID and OEM_PRIVATE capable networks.
+ <p>Not for use by third-party or privileged applications. -->
+ <permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows an application to manage ethernet networks.
+ <p>Not for use by third-party or privileged applications. -->
+ <permission android:name="android.permission.MANAGE_ETHERNET_NETWORKS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows system apps to call methods to register itself as a mDNS offload engine.
+ <p>Not for use by third-party or privileged applications.
+ @SystemApi
+ @hide This should only be used by system apps.
+ -->
+ <permission android:name="android.permission.REGISTER_NSD_OFFLOAD_ENGINE"
+ android:protectionLevel="signature" />
+
+ <!-- ======================================= -->
+ <!-- Permissions for short range, peripheral networks -->
+ <!-- ======================================= -->
+ <eat-comment />
+
+ <!-- Allows applications to connect to paired bluetooth devices.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.BLUETOOTH"
+ android:description="@string/permdesc_bluetooth"
+ android:label="@string/permlab_bluetooth"
+ android:protectionLevel="normal" />
+
+ <!-- Required to be able to discover and pair nearby Bluetooth devices.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.BLUETOOTH_SCAN"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_bluetooth_scan"
+ android:label="@string/permlab_bluetooth_scan"
+ android:protectionLevel="dangerous" />
+
+ <!-- Required to be able to connect to paired Bluetooth devices.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.BLUETOOTH_CONNECT"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_bluetooth_connect"
+ android:label="@string/permlab_bluetooth_connect"
+ android:protectionLevel="dangerous" />
+
+ <!-- Required to be able to advertise to nearby Bluetooth devices.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.BLUETOOTH_ADVERTISE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_bluetooth_advertise"
+ android:label="@string/permlab_bluetooth_advertise"
+ android:protectionLevel="dangerous" />
+
+ <!-- Required to be able to range to devices using ultra-wideband.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.UWB_RANGING"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_uwb_ranging"
+ android:label="@string/permlab_uwb_ranging"
+ android:protectionLevel="dangerous" />
+
+ <!-- Required to be able to advertise and connect to nearby devices via Wi-Fi.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.NEARBY_WIFI_DEVICES"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_nearby_wifi_devices"
+ android:label="@string/permlab_nearby_wifi_devices"
+ android:protectionLevel="dangerous" />
+
+ <!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the
+ user from using them until they are unsuspended.
+ @hide
+ -->
+ <permission android:name="android.permission.SUSPEND_APPS"
+ android:protectionLevel="signature|role|verifier" />
+
+ <!-- @SystemApi
+ @hide
+ @FlaggedApi("android.content.pm.quarantined_enabled")
+ Allows an application to quarantine other apps, which will prevent
+ them from running without explicit user action.
+ -->
+ <permission android:name="android.permission.QUARANTINE_APPS"
+ android:protectionLevel="signature|verifier" />
+
+ <!-- Allows applications to discover and pair bluetooth devices.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.BLUETOOTH_ADMIN"
+ android:description="@string/permdesc_bluetoothAdmin"
+ android:label="@string/permlab_bluetoothAdmin"
+ android:protectionLevel="normal" />
+
+ <!-- Allows applications to pair bluetooth devices without user interaction, and to
+ allow or disallow phonebook access or message access.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- SystemApi Control access to email providers exclusively for Bluetooth
+ @hide
+ -->
+ <permission android:name="android.permission.BLUETOOTH_MAP"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows bluetooth stack to access files
+ @hide This should only be used by Bluetooth apk.
+ -->
+ <permission android:name="android.permission.BLUETOOTH_STACK"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows uhid write access for creating virtual input devices
+ @hide
+ -->
+ <permission android:name="android.permission.VIRTUAL_INPUT_DEVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows applications to perform I/O operations over NFC.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.NFC"
+ android:description="@string/permdesc_nfc"
+ android:label="@string/permlab_nfc"
+ android:protectionLevel="normal" />
+
+ <!-- Allows applications to receive NFC transaction events.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.NFC_TRANSACTION_EVENT"
+ android:protectionLevel="normal" />
+
+ <!-- Allows applications to receive NFC preferred payment service information.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.NFC_PREFERRED_PAYMENT_INFO"
+ android:description="@string/permdesc_preferredPaymentInfo"
+ android:label="@string/permlab_preferredPaymentInfo"
+ android:protectionLevel="normal" />
+
+ <!-- @SystemApi Allows access to set NFC controller always on states.
+ <p>Protection level: signature|privileged
+ @hide -->
+ <permission android:name="android.permission.NFC_SET_CONTROLLER_ALWAYS_ON"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an internal user to use privileged SecureElement APIs.
+ Applications holding this permission can access OMAPI reset system API
+ and bypass OMAPI AccessControlEnforcer.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @deprecated This permission used to allow too broad access to sensitive methods and all its
+ uses have been replaced by a more appropriate permission. Most uses have been replaced with
+ a NETWORK_STACK or NETWORK_SETTINGS check. Please look up the documentation of the
+ individual functions to figure out what permission now protects the individual function.
+ @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
+ @hide -->
+ <permission android:name="android.permission.CONNECTIVITY_INTERNAL"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an internal user to use restricted Networks.
+ @hide -->
+ <permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"
+ android:protectionLevel="signature|privileged" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+
+ <!-- @SystemApi Allows an internal user to set signal strength in NetworkRequest. This kind of
+ request will wake up device when signal strength meets the given value.
+ @hide -->
+ <permission android:name="android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows a system application to access hardware packet offload capabilities.
+ @hide -->
+ <permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows access to the loop radio (Android@Home mesh network) device.
+ @hide -->
+ <permission android:name="android.permission.LOOP_RADIO"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows sending and receiving handover transfer status from Wifi and Bluetooth
+ @hide -->
+ <permission android:name="android.permission.NFC_HANDOVER_STATUS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows internal management of Bluetooth state when on wireless consent mode.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows the device to be reset, clearing all data and enables Test Harness Mode. -->
+ <permission android:name="android.permission.ENABLE_TEST_HARNESS_MODE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows access to ultra wideband device.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.UWB_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- ================================== -->
+ <!-- Permissions for accessing accounts -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- Allows access to the list of accounts in the Accounts Service.
+
+ <p class="note"><strong>Note:</strong> Beginning with Android 6.0 (API level
+ 23), if an app shares the signature of the authenticator that manages an
+ account, it does not need <code>"GET_ACCOUNTS"</code> permission to read
+ information about that account. On Android 5.1 and lower, all apps need
+ <code>"GET_ACCOUNTS"</code> permission to read information about any
+ account.</p>
+
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.GET_ACCOUNTS"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_getAccounts"
+ android:label="@string/permlab_getAccounts" />
+ <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
+
+ <!-- Allows applications to call into AccountAuthenticators.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.ACCOUNT_MANAGER"
+ android:protectionLevel="signature" />
+
+ <!-- ================================== -->
+ <!-- Permissions for accessing hardware that may effect battery life-->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- Allows applications to enter Wi-Fi Multicast mode.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
+ android:description="@string/permdesc_changeWifiMulticastState"
+ android:label="@string/permlab_changeWifiMulticastState"
+ android:protectionLevel="normal" />
+
+ <!-- Allows access to the vibrator.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.VIBRATE"
+ android:label="@string/permlab_vibrate"
+ android:description="@string/permdesc_vibrate"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows access to the vibrator always-on settings.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.VIBRATE_ALWAYS_ON"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows access to the vibrator state.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_VIBRATOR_STATE"
+ android:label="@string/permdesc_vibrator_state"
+ android:description="@string/permdesc_vibrator_state"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
+ from dimming.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.WAKE_LOCK"
+ android:label="@string/permlab_wakeLock"
+ android:description="@string/permdesc_wakeLock"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows using the device's IR transmitter, if available.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.TRANSMIT_IR"
+ android:label="@string/permlab_transmitIr"
+ android:description="@string/permdesc_transmitIr"
+ android:protectionLevel="normal" />
+
+ <!-- ==================================================== -->
+ <!-- Permissions related to changing audio settings -->
+ <!-- ==================================================== -->
+ <eat-comment />
+
+ <!-- Allows an application to modify global audio settings.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"
+ android:label="@string/permlab_modifyAudioSettings"
+ android:description="@string/permdesc_modifyAudioSettings"
+ android:protectionLevel="normal" />
+
+ <!-- ==================================================== -->
+ <!-- Permissions related to screen capture -->
+ <!-- ==================================================== -->
+ <eat-comment />
+
+ <!-- Allows an application to capture screen content to perform a screenshot using the intent
+ action {@link android.content.Intent#ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE}.
+ <p>Protection level: internal|role
+ <p>Intended for use by ROLE_NOTES only.
+ -->
+ <permission android:name="android.permission.LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to be notified whenever a screen capture is attempted.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.DETECT_SCREEN_CAPTURE"
+ android:label="@string/permlab_detectScreenCapture"
+ android:description="@string/permdesc_detectScreenCapture"
+ android:protectionLevel="normal" />
+
+ <!-- ======================================== -->
+ <!-- Permissions for factory reset protection -->
+ <!-- ======================================== -->
+ <eat-comment />
+
+ <!-- @SystemApi Allows an application to set a factory reset protection (FRP) policy.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.MANAGE_FACTORY_RESET_PROTECTION"
+ android:protectionLevel="signature|privileged"/>
+
+ <!-- ======================================== -->
+ <!-- Permissions for lost mode -->
+ <!-- ======================================== -->
+ <eat-comment />
+
+ <!-- @SystemApi Allows an application to trigger lost mode on an organization-owned device.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.TRIGGER_LOST_MODE"
+ android:protectionLevel="signature|role"/>
+
+ <!-- ================================== -->
+ <!-- Permissions for accessing hardware -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- @SystemApi Allows an application to manage preferences and permissions for USB devices
+ @hide -->
+ <permission android:name="android.permission.MANAGE_USB"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to manage Android Debug Bridge settings.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_DEBUGGING"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to access the MTP USB kernel driver.
+ For use only by the device side MTP implementation.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_MTP"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows access to hardware peripherals. Intended only for hardware testing.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.HARDWARE_TEST"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to manage DynamicSystem image -->
+ <permission android:name="android.permission.MANAGE_DYNAMIC_SYSTEM"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to install a DynamicSystem image and get status updates.
+ @hide -->
+ <permission android:name="android.permission.INSTALL_DYNAMIC_SYSTEM"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows access to Broadcast Radio
+ @hide This is not a third-party API (intended for system apps).-->
+ <permission android:name="android.permission.ACCESS_BROADCAST_RADIO"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @deprecated @SystemApi Allows access to FM
+ @hide This is not a third-party API (intended for system apps).-->
+ <permission android:name="android.permission.ACCESS_FM_RADIO"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows access to configure network interfaces, configure/use IPSec, etc.
+ @hide -->
+ <permission android:name="android.permission.NET_ADMIN"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows registration for remote audio playback. @hide -->
+ <permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK"
+ android:protectionLevel="signature" />
+
+ <!-- Allows TvInputService to access underlying TV input hardware such as
+ built-in tuners and HDMI-in's.
+ <p>This should only be used by OEM's TvInputService's.
+ @hide @SystemApi -->
+ <permission android:name="android.permission.TV_INPUT_HARDWARE"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- Allows to capture a frame of TV input hardware such as
+ built-in tuners and HDMI-in's.
+ <p>Not for use by third-party applications.
+ @hide @SystemApi -->
+ <permission android:name="android.permission.CAPTURE_TV_INPUT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows TvInputService to access DVB device.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.DVB_DEVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows reading and enabling/disabling the OEM unlock allowed by carrier state
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows reading and enabling/disabling the OEM unlock allowed by user state
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_USER_OEM_UNLOCK_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows reading the OEM unlock state
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_OEM_UNLOCK_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows enabling/disabling OEM unlock
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.OEM_UNLOCK_STATE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows querying state of PersistentDataBlock
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.ACCESS_PDB_STATE"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows testing if a passwords is forbidden by the admins.
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.TEST_BLACKLISTED_PASSWORD"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows system update service to notify device owner about pending updates.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- =========================================== -->
+ <!-- Permissions associated with camera and image capture -->
+ <!-- =========================================== -->
+ <eat-comment />
+
+ <!-- @SystemApi Allows disabling the transmit-indicator LED that is normally on when
+ a camera is in use by an application.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_DISABLE_TRANSMIT_LED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows sending the camera service notifications about system-wide events.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_SEND_SYSTEM_EVENTS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows injecting the external camera to replace the internal camera.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_INJECT_EXTERNAL_CAMERA"
+ android:protectionLevel="signature" />
+
+ <!-- =========================================== -->
+ <!-- Permissions associated with telephony state -->
+ <!-- =========================================== -->
+ <eat-comment />
+
+ <!-- @SystemApi Allows granting runtime permissions to telephony related components.
+ @hide -->
+ <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows modification of the telephony state - power on, mmi, etc.
+ Does not include placing calls.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MODIFY_PHONE_STATE"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows read only access to precise phone state.
+ Allows reading of detailed information about phone state for special-use applications
+ such as dialers, carrier applications, or ims applications. -->
+ <permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @TestApi Allows read access to privileged phone state.
+ @hide Used internally. -->
+ <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows to read device identifiers and use ICC based authentication like EAP-AKA.
+ Often required in authentication to access the carrier's server and manage services
+ of the subscriber.
+ <p>Protection level: signature|appop -->
+ <permission android:name="android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER"
+ android:protectionLevel="signature|appop" />
+
+ <!-- @SystemApi Allows read access to emergency number information for ongoing calls or SMS
+ sessions.
+ @hide Used internally. -->
+ <permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"
+ android:protectionLevel="signature" />
+
+ <!-- Allows listen permission to always reported system signal strength.
+ @hide Used internally. -->
+ <permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Protects the ability to register any PhoneAccount with
+ PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
+ corresponds to a device SIM.
+ @hide -->
+ <permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Protects the ability to register any PhoneAccount with
+ PhoneAccount#CAPABILITY_CALL_PROVIDER.
+ @hide -->
+ <permission android:name="android.permission.REGISTER_CALL_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Protects the ability to register any PhoneAccount with
+ PhoneAccount#CAPABILITY_CONNECTION_MANAGER
+ @hide -->
+ <permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a {@link android.telecom.InCallService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_INCALL_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows to query ongoing call details and manage ongoing calls
+ <p>Protection level: signature|appop -->
+ <permission android:name="android.permission.MANAGE_ONGOING_CALLS"
+ android:protectionLevel="signature|appop"
+ android:label="@string/permlab_manageOngoingCalls"
+ android:description="@string/permdesc_manageOngoingCalls" />
+
+ <!-- Allows the app to request network scans from telephony.
+ <p>Not for use by third-party applications.
+ @SystemApi @hide-->
+ <permission android:name="android.permission.NETWORK_SCAN"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a link {@link android.telephony.VisualVoicemailService} to ensure that
+ only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission
+ android:name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"
+ android:protectionLevel="signature|privileged"/>
+
+ <!-- Must be required by a {@link android.telecom.CallScreeningService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_SCREENING_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a {@link android.telecom.PhoneAccountSuggestionService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.telecom.CallDiagnosticService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_CALL_DIAGNOSTIC_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.telecom.CallRedirectionService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a {@link android.telecom.CallStreamingService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @SystemApi @hide-->
+ <permission android:name="android.permission.BIND_CALL_STREAMING_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.telecom.ConnectionService},
+ to ensure that only the system can bind to it.
+ @deprecated {@link android.telecom.ConnectionService}s should require
+ android.permission.BIND_TELECOM_CONNECTION_SERVICE instead.
+ @SystemApi
+ @hide -->
+ <permission android:name="android.permission.BIND_CONNECTION_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a
+ android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.telecom.ConnectionService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to control the in-call experience.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows an application to receive STK related commands.
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to send EMBMS download intents to apps
+ @hide -->
+ <permission android:name="android.permission.SEND_EMBMS_INTENTS"
+ android:protectionLevel="signature|privileged" />
+
+
+ <!-- Allows internal management of the sensor framework
+ @hide -->
+ <permission android:name="android.permission.MANAGE_SENSORS"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an ImsService to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature|privileged|vendorPrivileged
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_IMS_SERVICE"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- Must be required by a telephony data service to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_TELEPHONY_DATA_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a NetworkService to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_TELEPHONY_NETWORK_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to manage embedded subscriptions (those on a eUICC)
+ through EuiccManager APIs.
+ <p>Protection level: signature|privileged|development
+ @hide
+ -->
+ <permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- @SystemApi Must be required by an EuiccService to ensure that only the system can bind to
+ it.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_EUICC_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Required for reading information about carrier apps from SystemConfigManager.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.READ_CARRIER_APP_INFO"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an GbaService to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_GBA_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Required for an Application to access APIs related to RCS User Capability Exchange.
+ <p> This permission is only granted to system applications fulfilling the SMS, Dialer, and
+ Contacts app roles.
+ <p>Protection level: internal|role
+ @SystemApi
+ @hide -->
+ <permission android:name="android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE"
+ android:protectionLevel="internal|role" />
+
+ <!-- ================================== -->
+ <!-- Permissions for sdcard interaction -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- @SystemApi @TestApi Allows an application to write to internal media storage
+ @deprecated This permission is no longer honored in the system and no longer adds
+ the media_rw gid as a supplementary gid to the holder. Use the
+ android.permission.MANAGE_EXTERNAL_STORAGE instead.
+ @hide -->
+ <permission android:name="android.permission.WRITE_MEDIA_STORAGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to manage access to documents, usually as part
+ of a document picker.
+ <p>This permission should <em>only</em> be requested by the platform
+ document management app. This permission cannot be granted to
+ third-party apps.
+ -->
+ <permission android:name="android.permission.MANAGE_DOCUMENTS"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows an application to manage access to crates, usually as part
+ of a crates picker.
+ <p>This permission should <em>only</em> be requested by the platform
+ management app. This permission cannot be granted to
+ third-party apps.
+ @hide
+ @TestApi
+ -->
+ <permission android:name="android.permission.MANAGE_CRATES"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to cache content.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.CACHE_CONTENT"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi @hide
+ Allows an application to aggressively allocate disk space.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.ALLOCATE_AGGRESSIVE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide
+ Allows an application to use reserved disk space.
+ <p>Not for use by third-party applications. Should only be requested by
+ apps that provide core system functionality, to ensure system stability
+ when disk is otherwise completely full.
+ -->
+ <permission android:name="android.permission.USE_RESERVED_DISK"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- ================================== -->
+ <!-- Permissions for screenlock -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- Allows applications to disable the keyguard if it is not secure.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.DISABLE_KEYGUARD"
+ android:description="@string/permdesc_disableKeyguard"
+ android:label="@string/permlab_disableKeyguard"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to request the screen lock complexity and prompt users to update the
+ screen lock to a certain complexity level.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_PASSWORD_COMPLEXITY"
+ android:label="@string/permlab_requestPasswordComplexity"
+ android:description="@string/permdesc_requestPasswordComplexity"
+ android:protectionLevel="normal" />
+
+ <!-- ================================== -->
+ <!-- Permissions to access other installed applications -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- @deprecated No longer enforced. -->
+ <permission android:name="android.permission.GET_TASKS"
+ android:label="@string/permlab_getTasks"
+ android:description="@string/permdesc_getTasks"
+ android:protectionLevel="normal" />
+
+ <!-- New version of GET_TASKS that apps can request, since GET_TASKS doesn't really
+ give access to task information. We need this new one because there are
+ many existing apps that use add libraries and such that have validation
+ code to ensure the app has requested the GET_TASKS permission by seeing
+ if it has been granted the permission... if it hasn't, it kills the app
+ with a message about being upset. So we need to have it continue to look
+ like the app is getting that permission, even though it will never be
+ checked, and new privileged apps can now request this one for real access.
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.REAL_GET_TASKS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to start a task from a ActivityManager#RecentTaskInfo.
+ @hide -->
+ <permission android:name="android.permission.START_TASKS_FROM_RECENTS"
+ android:protectionLevel="signature|privileged|recents" />
+
+ <!-- @SystemApi @hide Allows an application to call APIs that allow it to do interactions
+ across the users on the device, using singleton services and
+ user-targeted broadcasts. This permission is not available to
+ third party applications. -->
+ <permission android:name="android.permission.INTERACT_ACROSS_USERS"
+ android:protectionLevel="signature|privileged|development|role" />
+
+ <!-- @SystemApi Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
+ that removes restrictions on where broadcasts can be sent and allows other
+ types of interactions
+ @hide -->
+ <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
+ android:protectionLevel="signature|installer|role" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+
+ <!-- Allows interaction across profiles in the same profile group. -->
+ <permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
+ android:protectionLevel="signature|appop" />
+
+ <!-- @SystemApi Allows configuring apps to have the INTERACT_ACROSS_PROFILES permission so that
+ they can interact across profiles in the same profile group.
+ @hide -->
+ <permission android:name="android.permission.CONFIGURE_INTERACT_ACROSS_PROFILES"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi @hide Allows starting activities across profiles in the same profile group. -->
+ <permission android:name="android.permission.START_CROSS_PROFILE_ACTIVITIES"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
+ users on the device. This permission is not available to
+ third party applications. -->
+ <permission android:name="android.permission.MANAGE_USERS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to create, remove users and get the list of
+ users on the device. Applications holding this permission can create users (including
+ normal, restricted, guest, managed, and demo users) and can optionally endow them with the
+ ephemeral property. For creating users with other kinds of properties,
+ {@link android.Manifest.permission#MANAGE_USERS} is needed.
+ This permission is not available to third party applications. -->
+ <permission android:name="android.permission.CREATE_USERS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows an application to set user association
+ with a certain subscription. Used by Enterprise to associate a
+ subscription with a work or personal profile. -->
+ <permission android:name="android.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows an application to call APIs that allow it to query users on the
+ device. -->
+ <permission android:name="android.permission.QUERY_USERS"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows an application to access data blobs across users. -->
+ <permission android:name="android.permission.ACCESS_BLOBS_ACROSS_USERS"
+ android:protectionLevel="signature|privileged|development|role" />
+
+ <!-- @SystemApi @hide Allows an application to set the profile owners and the device owner.
+ This permission is not available to third party applications.-->
+ <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
+ android:protectionLevel="signature|role"
+ android:label="@string/permlab_manageProfileAndDeviceOwners"
+ android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+
+ <!-- @SystemApi @hide Allows an application to query device policies set by any admin on
+ the device.-->
+ <permission android:name="android.permission.QUERY_ADMIN_POLICY"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi @hide Allows an application to exempt apps from platform restrictions.-->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage device policy relating to time.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.-->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_TIME"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set the grant state of runtime permissions on packages.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage the identity of the managing organization.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set support messages for when a user action is affected by an
+ active policy.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage backup service policy.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BACKUP_SERVICE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage lock task policy.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy regarding modifying applications.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage installing from unknown sources policy.
+ <p>MANAGE_SECURITY_CRITICAL_DEVICE_POLICY_ACROSS_USERS is required to call APIs protected
+ by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage application restrictions.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage calling policy.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CALLS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage debugging features policy.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy preventing users from modifying users.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage safe boot policy.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to restricting a user's ability to use or
+ enable and disable the microphone.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to restricting a user's ability to use or
+ enable and disable the camera.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to keyguard.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to account management.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to hiding and suspending packages.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to force set a new device unlock password or a managed profile
+ challenge on current user.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to the status bar.-->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_STATUS_BAR"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to bluetooth.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLUETOOTH"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to fun.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_FUN"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to airplane mode.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to mobile networks.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to physical media.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to sms.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SMS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to usb file transfers.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to lock credentials.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to Wifi.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIFI"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to screen capture.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to input methods.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to restricting the user from configuring
+ private DNS.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to the default sms application.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to profiles.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILES"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to interacting with profiles (e.g. Disallowing
+ cross-profile copy and paste).
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to VPNs.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_VPN"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to audio output.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to the display.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DISPLAY"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to location.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCATION"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to factory reset.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to the wallpaper.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_WALLPAPER"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to the usage of the contents of the screen.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CONTENT"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to system dialogs.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to users running in the background.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUN_IN_BACKGROUND"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to printing.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PRINTING"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to nearby communications (e.g. Beam and
+ nearby streaming).
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to windows.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_WINDOWS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to locale.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCALE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to autofill.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUTOFILL"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to users.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_USERS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to certificates.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to override APNs.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_OVERRIDE_APN"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to security logging.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to system updates.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to query system updates.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to private DNS.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PRIVATE_DNS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to settings.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SETTINGS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to network logging.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_NETWORK_LOGGING"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to usb data signalling.-->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to suspending personal apps.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SUSPEND_PERSONAL_APPS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set policy related to keeping uninstalled packages.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
+ required to call APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEEP_UNINSTALLED_PACKAGES"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to accessibility.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACCESSIBILITY"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to common criteria mode.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to metered data.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_METERED_DATA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set a network-independent global HTTP proxy.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROXY"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to request bugreports with user consent.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BUGREPORT"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to application user data.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_USER_DATA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to lock a profile or the device with the appropriate cross-user
+ permission.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to system apps.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to wiping data.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
+ APIs protected by this permission on users different to the calling user.
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to the Memory Tagging Extension (MTE).
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MTE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to device identifiers. -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set device policies outside the current user
+ that are critical for securing data within the current user.
+ <p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
+ permissions across all users on the device provided they are required for securing data
+ within the current user.-->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set device policies outside the current user
+ that are required for securing device ownership without accessing user data.
+ <p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
+ permissions across all users on the device provided they do not grant access to user
+ data. -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to set device policies outside the current user.
+ <p>Fuller form of {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS}
+ that removes the restriction on accessing user data.
+ <p>Holding this permission allows the use of any other held MANAGE_DEVICE_POLICY_*
+ permissions across all users on the device.-->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL"
+ android:protectionLevel="internal|role" />
+
+ <!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.-->
+ <permission android:name="android.permission.PROVISION_DEMO_DEVICE"
+ android:protectionLevel="signature|setup|knownSigner"
+ android:knownCerts="@array/demo_device_provisioning_known_signers" />
+
+ <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
+ periods. -->
+ <permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
+ android:protectionLevel="signature" />
+
+ <!-- @TestApi @hide Allows an application to force available DevicePolicyManager logs to
+ DPC. -->
+ <permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to write to the security log buffer in logd.
+ @hide -->
+ <permission android:name="android.permission.WRITE_SECURITY_LOG"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to get full detailed information about
+ recently running tasks, with full fidelity to the real state.
+ @hide -->
+ <permission android:name="android.permission.GET_DETAILED_TASKS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to change the Z-order of tasks.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REORDER_TASKS"
+ android:label="@string/permlab_reorderTasks"
+ android:description="@string/permdesc_reorderTasks"
+ android:protectionLevel="normal" />
+
+ <!-- @SystemApi @TestApi @hide Allows an application to change to remove/kill tasks -->
+ <permission android:name="android.permission.REMOVE_TASKS"
+ android:protectionLevel="signature|recents|role" />
+
+ <!-- @deprecated Use MANAGE_ACTIVITY_TASKS instead.
+ @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks -->
+ <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove tasks -->
+ <permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"
+ android:protectionLevel="signature|recents" />
+
+ <!-- @SystemApi @TestApi @hide Allows an application to embed other activities -->
+ <permission android:name="android.permission.ACTIVITY_EMBEDDING"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to start any activity, regardless of permission
+ protection or exported state.
+ @hide -->
+ <permission android:name="android.permission.START_ANY_ACTIVITY"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows an application to start activities from background -->
+ <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
+ android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role" />
+
+ <!-- Allows an application to start foreground services from the background at any time.
+ <em>This permission is not for use by third-party applications</em>,
+ with the only exception being if the app is the default SMS app.
+ Otherwise, it's only usable by privileged apps, app verifier app, and apps with
+ any of the EMERGENCY or SYSTEM GALLERY roles.
+ -->
+ <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
+ android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/>
+
+ <!-- Allows an application to request interactive options when sending a broadcast.
+ @hide -->
+ <permission android:name="android.permission.BROADCAST_OPTION_INTERACTIVE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Must be required by activities that handle the intent action
+ {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
+ hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS" />
+
+ <!-- Allows an application to start an activity as another app, provided that app has been
+ granted a permissionToken from the ActivityManagerService.
+ @hide -->
+ <permission android:name="android.permission.START_ACTIVITY_AS_CALLER"
+ android:protectionLevel="signature" />
+
+ <!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
+ API is no longer supported. -->
+ <permission android:name="android.permission.RESTART_PACKAGES"
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses"
+ android:protectionLevel="normal" />
+
+ <!-- @deprecated Allows an application to call
+ {@link android.app.ActivityManager#killBackgroundProcesses}.
+ <p>As of Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
+ the {@link android.app.ActivityManager#killBackgroundProcesses} is no longer available to
+ third party applications. For backwards compatibility, the background processes of the
+ caller's own package will still be killed when calling this API, meanwhile this permission
+ is not required anymore in this case.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses"
+ android:protectionLevel="normal" />
+
+ <!-- @SystemApi @hide Allows an application to call
+ {@link android.app.ActivityManager#killBackgroundProcesses}
+ to kill background processes of other apps.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.KILL_ALL_BACKGROUND_PROCESSES"
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to query process states and current
+ OOM adjustment scores.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows use of PendingIntent.getIntent(), .
+ @hide @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)
+ -->
+ <permission android:name="android.permission.GET_INTENT_SENDER_INTENT"
+ android:protectionLevel="signature" />
+
+ <!-- ================================== -->
+ <!-- Permissions affecting the display of other applications -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- Allows an app to create windows using the type
+ {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY},
+ shown on top of all other apps. Very few apps
+ should use this permission; these windows are intended for
+ system-level interaction with the user.
+
+ <p class="note"><strong>Note:</strong> If the app
+ targets API level 23 or higher, the app user must explicitly grant
+ this permission to the app through a permission management screen. The app requests
+ the user's approval by sending an intent with action
+ {@link android.provider.Settings#ACTION_MANAGE_OVERLAY_PERMISSION}.
+ The app can check whether it has this authorization by calling
+ {@link android.provider.Settings#canDrawOverlays
+ Settings.canDrawOverlays()}.
+ <p>Protection level: signature|setup|appop|installer|pre23|development -->
+ <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
+ android:label="@string/permlab_systemAlertWindow"
+ android:description="@string/permdesc_systemAlertWindow"
+ android:protectionLevel="signature|setup|appop|installer|pre23|development" />
+
+ <!-- @SystemApi @hide Allows an application to create windows using the type
+ {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY},
+ shown on top of all other apps.
+
+ Allows an application to use
+ {@link android.view.WindowManager.LayoutsParams#setSystemApplicationOverlay(boolean)}
+ to create overlays that will stay visible, even if another window is requesting overlays to
+ be hidden through {@link android.view.Window#setHideOverlayWindows(boolean)}.
+
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"
+ android:protectionLevel="signature|recents|role|installer"/>
+
+ <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
+ @hide
+ -->
+ <permission android:name="android.permission.RUN_IN_BACKGROUND"
+ android:label="@string/permlab_runInBackground"
+ android:description="@string/permdesc_runInBackground"
+ android:protectionLevel="signature" />
+
+ <!-- @deprecated Use
+ {@link android.Manifest.permission#REQUEST_COMPANION_USE_DATA_IN_BACKGROUND}
+ @hide
+ -->
+ <permission android:name="android.permission.USE_DATA_IN_BACKGROUND"
+ android:label="@string/permlab_useDataInBackground"
+ android:description="@string/permdesc_useDataInBackground"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to set display offsets for the screen.
+ This permission is not available to third party applications. -->
+ <permission android:name="android.permission.SET_DISPLAY_OFFSET"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows a companion app to run in the background. This permission implies
+ {@link android.Manifest.permission#REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND},
+ and allows to start a foreground service from the background.
+ If an app does not have to run in the background, but only needs to start a foreground
+ service from the background, consider using
+ {@link android.Manifest.permission#REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND},
+ which is less powerful.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND"
+ android:label="@string/permlab_runInBackground"
+ android:description="@string/permdesc_runInBackground"
+ android:protectionLevel="normal" />
+
+ <!-- Allows a companion app to start a foreground service from the background.
+ {@see android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND"
+ android:protectionLevel="normal"/>
+
+ <!-- Allows a companion app to use data in the background.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND"
+ android:label="@string/permlab_useDataInBackground"
+ android:description="@string/permdesc_useDataInBackground"
+ android:protectionLevel="normal" />
+
+ <!-- Allows app to request to be associated with a device via
+ {@link android.companion.CompanionDeviceManager}
+ as a "watch"
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_WATCH"
+ android:protectionLevel="normal" />
+
+ <!-- Allows app to request to be associated with a device via
+ {@link android.companion.CompanionDeviceManager}
+ as "glasses"
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_GLASSES"
+ android:protectionLevel="normal" />
+
+ <!-- Allows application to request to be associated with a virtual display capable of streaming
+ Android applications
+ ({@link android.companion.AssociationRequest#DEVICE_PROFILE_APP_STREAMING})
+ by {@link android.companion.CompanionDeviceManager}.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows application to request to be associated with a virtual device associated to a
+ nearby device capable of rendering an entire OS
+ ({@link android.companion.AssociationRequest#DEVICE_PROFILE_NEARBY_DEVICE_STREAMING})
+ by {@link android.companion.CompanionDeviceManager}.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows application to request to be associated with a vehicle head unit capable of
+ automotive projection
+ ({@link android.companion.AssociationRequest#DEVICE_PROFILE_AUTOMOTIVE_PROJECTION})
+ by {@link android.companion.CompanionDeviceManager}.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows application to request to be associated with a computer to share functionality
+ and/or data with other devices, such as notifications, photos and media
+ ({@link android.companion.AssociationRequest#DEVICE_PROFILE_COMPUTER})
+ by {@link android.companion.CompanionDeviceManager}.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_COMPUTER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to create a "self-managed" association.
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_SELF_MANAGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows a companion app to associate to Wi-Fi.
+ <p>Only for use by a single pre-approved app.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an app to read and listen to projection state.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.READ_PROJECTION_STATE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an app to set and release automotive projection.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an app to prevent non-system-overlay windows from being drawn on top of it -->
+ <permission android:name="android.permission.HIDE_OVERLAY_WINDOWS"
+ android:protectionLevel="normal" />
+
+ <!-- ================================== -->
+ <!-- Permissions affecting the system wallpaper -->
+ <!-- ================================== -->
+ <eat-comment />
+
+ <!-- Allows applications to set the wallpaper.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.SET_WALLPAPER"
+ android:label="@string/permlab_setWallpaper"
+ android:description="@string/permdesc_setWallpaper"
+ android:protectionLevel="normal" />
+
+ <!-- Allows applications to set the wallpaper hints.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.SET_WALLPAPER_HINTS"
+ android:label="@string/permlab_setWallpaperHints"
+ android:description="@string/permdesc_setWallpaperHints"
+ android:protectionLevel="normal" />
+
+ <!-- Allow the app to read the system wallpaper image without
+ holding the READ_EXTERNAL_STORAGE permission.
+ <p>Not for use by third-party applications.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.READ_WALLPAPER_INTERNAL"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allow apps to always update wallpaper by sending data.
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.ALWAYS_UPDATE_WALLPAPER"
+ android:protectionLevel="internal|role" />
+
+ <!-- ===================================================== -->
+ <!-- Permissions for changing the system clock / time zone -->
+ <!-- ===================================================== -->
+ <eat-comment />
+
+ <!-- Allows applications to set the system time directly.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SET_TIME"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows applications to set the system time zone directly.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.SET_TIME_ZONE"
+ android:label="@string/permlab_setTimeZone"
+ android:description="@string/permdesc_setTimeZone"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows telephony to suggest the time / time zone.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows applications like settings to suggest the user's manually chosen time / time zone.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows system clock time suggestions from an external clock / time source to be made.
+ The nature of "external" could be highly form-factor specific. Example, times
+ obtained via the VHAL for Android Auto OS.
+ <p>Not for use by third-party applications.
+ @SystemApi @hide
+ -->
+ <permission android:name="android.permission.SUGGEST_EXTERNAL_TIME"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows applications like settings to manage configuration associated with automatic time
+ and time zone detection.
+ <p>Not for use by third-party applications.
+ @SystemApi @hide
+ -->
+ <permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- ==================================================== -->
+ <!-- Permissions related to changing status bar -->
+ <!-- ==================================================== -->
+ <eat-comment />
+
+ <!-- Allows an application to expand or collapse the status bar.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.EXPAND_STATUS_BAR"
+ android:label="@string/permlab_expandStatusBar"
+ android:description="@string/permdesc_expandStatusBar"
+ android:protectionLevel="normal" />
+
+ <!-- ============================================================== -->
+ <!-- Permissions related to adding/removing shortcuts from Launcher -->
+ <!-- ============================================================== -->
+ <eat-comment />
+
+ <!-- Allows an application to install a shortcut in Launcher.
+ <p>In Android O (API level 26) and higher, the <code>INSTALL_SHORTCUT</code> broadcast no
+ longer has any effect on your app because it's a private, implicit
+ broadcast. Instead, you should create an app shortcut by using the
+ {@link android.content.pm.ShortcutManager#requestPinShortcut requestPinShortcut()}
+ method from the {@link android.content.pm.ShortcutManager} class.
+ <p>Protection level: normal
+ -->
+ <permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
+ android:label="@string/permlab_install_shortcut"
+ android:description="@string/permdesc_install_shortcut"
+ android:protectionLevel="normal"/>
+
+ <!-- <p class="caution"><strong>Don't use this permission in your app.</strong><br>This
+ permission is no longer supported.
+ -->
+ <permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
+ android:label="@string/permlab_uninstall_shortcut"
+ android:description="@string/permdesc_uninstall_shortcut"
+ android:protectionLevel="normal"/>
+
+ <!-- ==================================================== -->
+ <!-- Permissions related to accessing sync settings -->
+ <!-- ==================================================== -->
+ <eat-comment />
+
+ <!-- Allows applications to read the sync settings.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.READ_SYNC_SETTINGS"
+ android:description="@string/permdesc_readSyncSettings"
+ android:label="@string/permlab_readSyncSettings"
+ android:protectionLevel="normal" />
+
+ <!-- Allows applications to write the sync settings.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.WRITE_SYNC_SETTINGS"
+ android:description="@string/permdesc_writeSyncSettings"
+ android:label="@string/permlab_writeSyncSettings"
+ android:protectionLevel="normal" />
+
+ <!-- Allows applications to read the sync stats.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.READ_SYNC_STATS"
+ android:description="@string/permdesc_readSyncStats"
+ android:label="@string/permlab_readSyncStats"
+ android:protectionLevel="normal" />
+
+ <!-- ============================================ -->
+ <!-- Permissions for low-level system interaction -->
+ <!-- ============================================ -->
+ <eat-comment />
+
+ <!-- @SystemApi @hide Change the screen compatibility mode of applications -->
+ <permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to modify the current configuration, such
+ as locale.
+ <p>Protection level: signature|privileged|development -->
+ <permission android:name="android.permission.CHANGE_CONFIGURATION"
+ android:protectionLevel="signature|privileged|development|role" />
+
+ <!-- Allows an application to read or write the system settings.
+
+ <p class="note"><strong>Note:</strong> If the app targets API level 23
+ or higher, the app user
+ must explicitly grant this permission to the app through a permission management screen.
+ The app requests the user's approval by sending an intent with action
+ {@link android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}. The app
+ can check whether it has this authorization by calling {@link
+ android.provider.Settings.System#canWrite Settings.System.canWrite()}.
+
+ <p>Protection level: signature|preinstalled|appop|pre23
+ -->
+ <permission android:name="android.permission.WRITE_SETTINGS"
+ android:label="@string/permlab_writeSettings"
+ android:description="@string/permdesc_writeSettings"
+ android:protectionLevel="signature|preinstalled|appop|pre23|role" />
+
+ <!-- Allows an application to modify the Google service map.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WRITE_GSERVICES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @TestApi @hide Allows an application to modify config settings.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WRITE_DEVICE_CONFIG"
+ android:protectionLevel="signature|verifier|configurator"/>
+
+ <!-- @SystemApi @hide Allows an application to read config settings.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_DEVICE_CONFIG"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- @SystemApi @TestApi @hide Allows an application to modify only allowlisted settings.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG"
+ android:protectionLevel="signature|verifier|configurator"/>
+
+ <!-- @SystemApi @TestApi @hide Allows an application to read/write sync disabled mode config.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG"
+ android:protectionLevel="signature|verifier|configurator"/>
+
+ <!-- @SystemApi @hide Allows applications like settings to read system-owned
+ application-specific locale configs.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_APP_SPECIFIC_LOCALES"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @hide Allows applications to set an application-specific {@link LocaleConfig}.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SET_APP_SPECIFIC_LOCALECONFIG"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to monitor {@link android.provider.Settings.Config} access.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"
+ android:protectionLevel="signature"/>
+
+ <!-- @SystemApi @TestApi Allows an application to call
+ {@link android.app.ActivityManager#forceStopPackage}.
+ @hide -->
+ <permission android:name="android.permission.FORCE_STOP_PACKAGES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to retrieve the content of the active window
+ An active window is the window that has fired an accessibility event. -->
+ <permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Modify the global animation scaling factor.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SET_ANIMATION_SCALE"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- @deprecated This functionality will be removed in the future; please do
+ not use. Allow an application to make its activities persistent. -->
+ <permission android:name="android.permission.PERSISTENT_ACTIVITY"
+ android:label="@string/permlab_persistentActivity"
+ android:description="@string/permdesc_persistentActivity"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to find out the space used by any package.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.GET_PACKAGE_SIZE"
+ android:label="@string/permlab_getPackageSize"
+ android:description="@string/permdesc_getPackageSize"
+ android:protectionLevel="normal" />
+
+ <!-- @deprecated No longer useful, see
+ {@link android.content.pm.PackageManager#addPackageToPreferred}
+ for details. -->
+ <permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"
+ android:protectionLevel="signature|installer|verifier" />
+
+ <!-- Allows an application to receive the
+ {@link android.content.Intent#ACTION_BOOT_COMPLETED} that is
+ broadcast after the system finishes booting. If you don't
+ request this permission, you will not receive the broadcast at
+ that time. Though holding this permission does not have any
+ security implications, it can have a negative impact on the
+ user experience by increasing the amount of time it takes the
+ system to start and allowing applications to have themselves
+ running without the user being aware of them. As such, you must
+ explicitly declare your use of this facility to make that visible
+ to the user.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
+ android:label="@string/permlab_receiveBootCompleted"
+ android:description="@string/permdesc_receiveBootCompleted"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to broadcast sticky intents. These are
+ broadcasts whose data is held by the system after being finished,
+ so that clients can quickly retrieve that data without having
+ to wait for the next broadcast.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.BROADCAST_STICKY"
+ android:label="@string/permlab_broadcastSticky"
+ android:description="@string/permdesc_broadcastSticky"
+ android:protectionLevel="normal" />
+
+ <!-- Allows mounting and unmounting file systems for removable storage.
+ <p>Not for use by third-party applications.-->
+ <permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows formatting file systems for removable storage.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide -->
+ <permission android:name="android.permission.STORAGE_INTERNAL"
+ android:protectionLevel="signature" />
+
+ <!-- Allows access to ASEC non-destructive API calls
+ @hide -->
+ <permission android:name="android.permission.ASEC_ACCESS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows creation of ASEC volumes
+ @hide -->
+ <permission android:name="android.permission.ASEC_CREATE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows destruction of ASEC volumes
+ @hide -->
+ <permission android:name="android.permission.ASEC_DESTROY"
+ android:protectionLevel="signature" />
+
+ <!-- Allows mount / unmount of ASEC volumes
+ @hide -->
+ <permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
+ android:protectionLevel="signature" />
+
+ <!-- Allows rename of ASEC volumes
+ @hide -->
+ <permission android:name="android.permission.ASEC_RENAME"
+ android:protectionLevel="signature" />
+
+ <!-- Allows applications to write the apn settings and read sensitive fields of
+ an existing apn settings like user and password.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WRITE_APN_SETTINGS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows applications to change network connectivity state.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.CHANGE_NETWORK_STATE"
+ android:description="@string/permdesc_changeNetworkState"
+ android:label="@string/permlab_changeNetworkState"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to clear the caches of all installed
+ applications on the device.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.CLEAR_APP_CACHE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to use any media decoder when decoding for playback
+ @hide -->
+ <permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to install and/or uninstall CA certificates on
+ behalf of the user.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_CA_CERTIFICATES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to do certain operations needed for
+ interacting with the recovery (system update) system.
+ @hide -->
+ <permission android:name="android.permission.RECOVERY"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to do certain operations needed for
+ resume on reboot feature.
+ @hide -->
+ <permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to read system update info.
+ @hide -->
+ <permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows the system to bind to an application's task services
+ @hide -->
+ <permission android:name="android.permission.BIND_JOB_SERVICE"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.BIND_JOB_SERVICE"/>
+
+ <!-- Allows an application to initiate configuration updates
+ <p>An application requesting this permission is responsible for
+ verifying the source and integrity of any update before passing
+ it off to the various individual installer components
+ @hide -->
+ <permission android:name="android.permission.UPDATE_CONFIG"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to query the current time zone rules state
+ on device.
+ @SystemApi @hide -->
+ <permission android:name="android.permission.QUERY_TIME_ZONE_RULES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows a time zone rule updater application to request
+ the system installs / uninstalls timezone rules.
+ <p>An application requesting this permission is responsible for
+ verifying the source and integrity of the update before passing
+ it off to the installer components.
+ @SystemApi @hide -->
+ <permission android:name="android.permission.UPDATE_TIME_ZONE_RULES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows the system to reset throttling in shortcut manager.
+ @hide -->
+ <permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING"
+ android:protectionLevel="signature" />
+
+ <!-- Allows the system to bind to the discovered Network Recommendation Service.
+ @SystemApi @hide -->
+ <permission android:name="android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"/>
+
+ <!-- Allows an application to enable, disable and change priority of
+ runtime resource overlays.
+ @hide -->
+ <permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to set, update and remove the credential management app.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP"
+ android:protectionLevel="signature" />
+
+ <!-- Allows a font updater application to request that the system installs/uninstalls/updates
+ font files. @SystemApi @hide -->
+ <permission android:name="android.permission.UPDATE_FONTS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to use the AttestationVerificationService.
+ @hide -->
+ <permission android:name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to export a AttestationVerificationService to verify attestations on
+ behalf of AttestationVerificationManager for system-defined attestation profiles.
+ @hide -->
+ <permission android:name="android.permission.VERIFY_ATTESTATION"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by any AttestationVerificationService to ensure that only the system can
+ bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_ATTESTATION_VERIFICATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows the caller to generate keymint keys with the INCLUDE_UNIQUE_ID tag, which
+ uniquely identifies the device via the attestation certificate.
+ @hide @TestApi -->
+ <permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION"
+ android:protectionLevel="signature" />
+
+ <!-- ========================================= -->
+ <!-- Permissions for special development tools -->
+ <!-- ========================================= -->
+ <eat-comment />
+
+ <!-- Allows an application to read or write the secure system settings.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WRITE_SECURE_SETTINGS"
+ android:protectionLevel="signature|privileged|development|role|installer" />
+
+ <!-- Allows an application to retrieve state dump information from system services.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.DUMP"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows an application to start tracing for InputMethod and WindowManager.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_UI_TRACING"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows an application to read the low-level system log files.
+ <p>Not for use by third-party applications, because
+ Log entries can contain the user's private information. -->
+ <permission android:name="android.permission.READ_LOGS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows an application to access the data in Dropbox-->
+ <permission android:name="android.permission.READ_DROPBOX_DATA"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Configure an application for debugging.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SET_DEBUG_APP"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows an application to set the maximum number of (not needed)
+ application processes that can be running.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SET_PROCESS_LIMIT"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows an application to control whether activities are immediately
+ finished when put in the background.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SET_ALWAYS_FINISH"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allow an application to request that a signal be sent to all persistent processes.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- @hide @SystemApi Must be required by a
+ {@link com.android.service.tracing.TraceReportService}, to ensure that only the system
+ can bind to it.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.BIND_TRACE_REPORT_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @hide @SystemApi @TestApi
+ Allow an application to approve incident and bug reports to be
+ shared off-device. There can be only one application installed on the
+ device with this permission, and since this is a privileged permission, it
+ must be in priv-app.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.APPROVE_INCIDENT_REPORTS"
+ android:protectionLevel="signature|incidentReportApprover" />
+
+ <!-- @hide Allow an application to approve an incident or bug report approval from
+ the system. -->
+ <permission android:name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- ==================================== -->
+ <!-- Private permissions -->
+ <!-- ==================================== -->
+ <eat-comment />
+
+ <!-- Allows access to the list of accounts in the Accounts Service.
+ <p>Protection level: signature|privileged -->
+ <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows but does not guarantee access to user passwords at the conclusion of add account
+ @hide -->
+ <permission android:name="android.permission.GET_PASSWORD"
+ android:protectionLevel="signature" />
+
+ <!-- Allows applications to RW to diagnostic resources.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.DIAGNOSTIC"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to open, close, or disable the status bar
+ and its icons.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.STATUS_BAR"
+ android:protectionLevel="signature|privileged|recents" />
+
+ <!-- Allows an application to trigger bugreport via shell using the bugreport API.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.TRIGGER_SHELL_BUGREPORT"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to trigger profcollect report upload via shell.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to be the status bar. Currently used only by SystemUI.apk
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.STATUS_BAR_SERVICE"
+ android:protectionLevel="signature|recents" />
+
+ <!-- Allows an application to bind to third party quick settings tiles.
+ <p>Should only be requested by the System, should be required by
+ TileService declarations.-->
+ <permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
+ android:protectionLevel="signature|recents" />
+
+ <!-- Allows SystemUI to request third party controls.
+ <p>Should only be requested by the System and required by
+ {@link android.service.controls.ControlsProviderService} declarations.
+ -->
+ <permission android:name="android.permission.BIND_CONTROLS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to force a BACK operation on whatever is the
+ top activity.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.FORCE_BACK"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to update device statistics.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.UPDATE_DEVICE_STATS"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi @hide Allows an application to collect application operation statistics.
+ Not for use by third party apps. -->
+ <permission android:name="android.permission.GET_APP_OPS_STATS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- @SystemApi @hide Allows an application to collect historical application operation
+ statistics.
+ <p>Not for use by third party applications.
+ -->
+ <permission android:name="android.permission.GET_HISTORICAL_APP_OPS_STATS"
+ android:protectionLevel="internal|role" />
+
+ <!-- @SystemApi Allows an application to update application operation statistics. Not for
+ use by third party apps.
+ @hide -->
+ <permission android:name="android.permission.UPDATE_APP_OPS_STATS"
+ android:protectionLevel="signature|privileged|installer|role" />
+
+ <!-- @SystemApi Allows an application to update the user app op restrictions.
+ Not for use by third party apps.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS"
+ android:protectionLevel="signature|installer" />
+
+ <!-- Allows an application to update the user app op modes.
+ Not for use by third party apps.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_APP_OPS_MODES"
+ android:protectionLevel="signature|installer|verifier|role" />
+
+ <!-- @SystemApi Allows an application to open windows that are for use by parts
+ of the system user interface.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
+ android:protectionLevel="signature|module|recents" />
+
+ <!-- Allows an application to avoid all toast rate limiting restrictions.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.UNLIMITED_TOASTS"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.UNLIMITED_TOASTS" />
+
+ <!-- @SystemApi Allows an application to use
+ {@link android.view.WindowManager.LayoutsParams#SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
+ to hide non-system-overlay windows.
+ <p>Not for use by third-party applications.
+ @deprecated Use {@link android.Manifest.permission#HIDE_OVERLAY_WINDOWS} instead
+ @hide
+ -->
+ <permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- @SystemApi Allows an application to manage (create, destroy,
+ Z-order) application tokens in the window manager.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.MANAGE_APP_TOKENS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows System UI to register listeners for events from Window Manager.
+ @hide -->
+ <permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows the application to temporarily freeze the screen for a
+ full-screen transition. -->
+ <permission android:name="android.permission.FREEZE_SCREEN"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to inject user events (keys, touch, trackball)
+ into the event stream and deliver them to ANY window. Without this
+ permission, you can only deliver events to windows in your own process.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.INJECT_EVENTS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to register an input filter which filters the stream
+ of user events (keys, touch, trackball) before they are dispatched to any window. -->
+ <permission android:name="android.permission.FILTER_EVENTS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to retrieve the window token from the accessibility manager. -->
+ <permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to modify accessibility information from another app. -->
+ <permission android:name="android.permission.MODIFY_ACCESSIBILITY_DATA"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to perform accessibility operations (e.g. send events) on
+ behalf of another package. -->
+ <permission android:name="android.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to change the accessibility volume. -->
+ <permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to collect frame statistics -->
+ <permission android:name="android.permission.FRAME_STATS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to temporary enable accessibility on the device. -->
+ <permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to launch detail settings activity of a particular
+ accessibility service.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @SystemApi Allows an application to watch and control how activities are
+ started globally in the system. Only for is in debugging
+ (usually the monkey command).
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.SET_ACTIVITY_WATCHER"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to call the activity manager shutdown() API
+ to put the higher-level system there into a shutdown state.
+ @hide -->
+ <permission android:name="android.permission.SHUTDOWN"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to tell the activity manager to temporarily
+ stop application switches, putting it into a special mode that
+ prevents applications from immediately switching away from some
+ critical UI such as the home screen.
+ @hide -->
+ <permission android:name="android.permission.STOP_APP_SWITCHES"
+ android:protectionLevel="signature|privileged|recents" />
+
+ <!-- @SystemApi Allows an application to retrieve private information about
+ the current top activity, such as any assist context it can provide.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"
+ android:protectionLevel="signature|recents" />
+
+ <!-- @SystemApi Allows an application to set the system audio caption and its UI
+ enabled state.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows an application to retrieve the current state of keys and
+ switches.
+ <p>Not for use by third-party applications.
+ @deprecated The API that used this permission has been removed. -->
+ <permission android:name="android.permission.READ_INPUT_STATE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.inputmethodservice.InputMethodService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_INPUT_METHOD"
+ android:protectionLevel="signature" />
+
+ <!-- Allows access to Test APIs defined in {@link android.view.inputmethod.InputMethodManager}.
+ @hide -->
+ <permission android:name="android.permission.TEST_INPUT_METHOD"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.media.midi.MidiDeviceService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_MIDI_DEVICE_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.printservice.PrintService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_PRINT_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
+ to ensure that only the system can bind to it.
+ @hide
+ @SystemApi
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows applications to get the installed and enabled print services.
+ @hide
+ @SystemApi
+ <p>Protection level: signature|preinstalled
+ -->
+ <permission android:name="android.permission.READ_PRINT_SERVICES"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- Allows applications to get the currently recommended print services for printers.
+ @hide
+ @SystemApi
+ <p>Protection level: signature|preinstalled
+ -->
+ <permission android:name="android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
+ or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
+ the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_NFC_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.service.quickaccesswallet.QuickAccessWalletService}
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by the PrintSpooler to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by the CompanionDeviceManager to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by any
+ {@link android.companion.CompanionDeviceService}s
+ to ensure that only the system can bind to it. -->
+ <permission android:name="android.permission.BIND_COMPANION_DEVICE_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
+ that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a TextService (e.g. SpellCheckerService)
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_TEXT_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Must be required by a AttentionService
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_ATTENTION_SERVICE"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.BIND_ATTENTION_SERVICE" />
+
+ <!-- @SystemApi Must be required by a RotationResolverService
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_ROTATION_RESOLVER_SERVICE"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.BIND_ROTATION_RESOLVER_SERVICE" />
+
+ <!-- @SystemApi Allows an application to access ambient context service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"
+ android:protectionLevel="signature|privileged|role"/>
+
+ <!-- @SystemApi Required by a AmbientContextEventDetectionService
+ to ensure that only the service with this permission can bind to it.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.BIND_AMBIENT_CONTEXT_DETECTION_SERVICE"
+ android:protectionLevel="signature"/>
+
+ <!-- @SystemApi Required by a WearableSensingService to
+ ensure that only the caller with this permission can bind to it.
+ <p> Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_WEARABLE_SENSING_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an app to manage the wearable sensing service.
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.MANAGE_WEARABLE_SENSING_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a {@link android.net.VpnService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_VPN_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_WALLPAPER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a game service to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_GAME_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_VOICE_INTERACTION"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Must be required by a {@link android.service.voice.HotwordDetectionService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Must be required by a {@link android.service.voice.visualQueryDetection},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE"
+ android:protectionLevel="signature" />
+
+
+ <!-- @SystemApi Allows an application to manage hotword detection and visual query detection
+ on the device.
+ <p>Protection level: internal|preinstalled
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.MANAGE_HOTWORD_DETECTION"
+ android:protectionLevel="internal|preinstalled" />
+
+ <!-- Allows an application to subscribe to keyguard locked (i.e., showing) state.
+ <p>Protection level: signature|role
+ <p>Intended for use by ROLE_ASSISTANT and signature apps only.
+ -->
+ <permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE"
+ android:protectionLevel="signature|role"/>
+
+ <!-- Must be required by a {@link android.service.credentials.CredentialProviderService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_CREDENTIAL_PROVIDER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.service.autofill.AutofillService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_AUTOFILL_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a
+ {@link android.service.assist.classification.FieldClassificationService},
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_FIELD_CLASSIFICATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Alternative version of android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE.
+ This permission was renamed during the O previews but it was supported on the final O
+ release, so we need to carry it over.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_AUTOFILL"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.service.autofill.AutofillFieldClassificationService}
+ to ensure that only the system can bind to it.
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.service.autofill.InlineSuggestionRenderService}
+ to ensure that only the system can bind to it.
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_INLINE_SUGGESTION_RENDER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a android.service.textclassifier.TextClassifierService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_TEXTCLASSIFIER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a
+ {@link android.service.remotelockscreenvalidation.RemoteLockscreenValidationService}
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a android.service.selectiontoolbar.SelectionToolbarRenderService,
+ to ensure that only the system can bind to it.
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_SELECTION_TOOLBAR_RENDER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a android.service.contentcapture.ContentCaptureService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_CONTENT_CAPTURE_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a android.service.translation.TranslationService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_TRANSLATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows apps to use ui translation functions.
+ <p>Protection level: signature|privileged
+ @hide Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.MANAGE_UI_TRANSLATION"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Must be required by a android.service.contentsuggestions.ContentSuggestionsService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be declared by a android.service.musicrecognition.MusicRecognitionService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_MUSIC_RECOGNITION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a android.service.autofill.augmented.AugmentedAutofillService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.service.voice.VoiceInteractionService} implementation
+ to enroll its own sound models. This is a more restrictive permission than the higher-level
+ permission KEYPHRASE_ENROLLMENT_APPLICATION. For the caller to enroll sound models with
+ this permission, it must hold the permission and be the active VoiceInteractionService in
+ the system.
+ {@see Settings.Secure.VOICE_INTERACTION_SERVICE}
+ @hide -->
+ <permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a keyphrase enrollment application, to enroll sound models. This is
+ treated as a higher-level permission to MANAGE_VOICE_KEYPHRASES as a caller can enroll
+ sound models at any time. This permission should be reserved for system enrollment
+ applications detected by {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}
+ only.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.KEYPHRASE_ENROLLMENT_APPLICATION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
+ to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_REMOTE_DISPLAY"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a android.media.tv.ad.TvAdService to ensure that only the system can
+ bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_TV_AD_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a {@link android.media.tv.TvInputService}
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_TV_INPUT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a {@link android.media.tv.interactive.TvInteractiveAppService}
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_TV_INTERACTIVE_APP"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi
+ Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications. </p>
+ @hide -->
+ <permission android:name="android.permission.BIND_TV_REMOTE_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows TV input apps and TV apps to use TIS extension interfaces for
+ domain-specific features.
+ <p>Protection level: signature|privileged|vendorPrivileged
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.TIS_EXTENSION_INTERFACE"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- @SystemApi
+ Must be required for a virtual remote controller for TV.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications. </p>
+ @hide -->
+ <permission android:name="android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to change HDMI CEC active source.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to modify parental controls
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to read TvContentRatingSystemInfo
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.READ_CONTENT_RATING_SYSTEMS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to notify TV inputs by sending broadcasts.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications.
+ @hide @SystemApi -->
+ <permission android:name="android.permission.NOTIFY_TV_INPUTS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- This permission is required among systems services when accessing
+ tuner resource management related APIs or information.
+ <p>Protection level: signature|privileged|vendorPrivileged
+ <p>This should only be used by the OEM TvInputService.
+ @hide -->
+ <permission android:name="android.permission.TUNER_RESOURCE_ACCESS"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- @SystemApi This permission is required by Media Resource Manager Service when
+ system services create MediaCodecs on behalf of other processes and apps.
+ <p>Protection level: signature
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+ <uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
+
+ <!-- This permission is required by Media Resource Observer Service when
+ accessing its registerObserver Api.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by a {@link android.media.routing.MediaRouteService}
+ to ensure that only the system can interact with it.
+ @hide -->
+ <permission android:name="android.permission.BIND_ROUTE_PROVIDER"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by device administration receiver, to ensure that only the
+ system can interact with it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_DEVICE_ADMIN"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Required to add or remove another application as a device admin.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Allows an app to reset the device password.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.RESET_PASSWORD"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an app to lock the device.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.LOCK_DEVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows low-level access to setting the orientation (actually
+ rotation) of the screen.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.SET_ORIENTATION"
+ android:protectionLevel="signature|recents" />
+
+ <!-- @SystemApi Allows low-level access to setting the pointer speed.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.SET_POINTER_SPEED"
+ android:protectionLevel="signature" />
+
+ <!-- Allows low-level access to setting input device calibration.
+ <p>Not for use by normal applications.
+ @hide -->
+ <permission android:name="android.permission.SET_INPUT_CALIBRATION"
+ android:protectionLevel="signature" />
+
+ <!-- Allows low-level access to setting the keyboard layout.
+ <p>Not for use by third-party applications.
+ @hide
+ @TestApi -->
+ <permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
+ android:protectionLevel="signature" />
+
+ <!-- Allows low-level access for re-mapping modifier keys.
+ <p>Not for use by third-party applications.
+ @hide
+ @TestApi -->
+ <permission android:name="android.permission.REMAP_MODIFIER_KEYS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows low-level access for monitoring keyboard backlight changes.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT"
+ android:protectionLevel="signature" />
+
+ <!-- Allows low-level access for monitoring changes to sticky modifier state, when A11y
+ Sitcky keys feature is enabled.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MONITOR_STICKY_MODIFIER_STATE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an app to schedule a prioritized alarm that can be used to perform
+ background work even when the device is in doze.
+ <p>Not for use by third-party applications.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.SCHEDULE_PRIORITIZED_ALARM"
+ android:protectionLevel="signature|privileged"/>
+
+ <!-- Allows applications to use exact alarm APIs.
+ <p>Exact alarms should only be used for user-facing features.
+ For more details, see <a
+ href="{@docRoot}about/versions/12/behavior-changes-12#exact-alarm-permission">
+ Exact alarm permission</a>.
+ <p>Apps who hold this permission and target API level 31 or above, always stay in the
+ {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_WORKING_SET WORKING_SET} or
+ lower standby bucket.
+ Applications targeting API level 30 or below do not need this permission to use
+ exact alarm APIs.
+ -->
+ <permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
+ android:protectionLevel="signature|privileged|appop"/>
+
+ <!-- Allows apps to use exact alarms just like with SCHEDULE_EXACT_ALARM but without needing
+ to request this permission from the user.
+ <p><b>This is only for apps that rely on exact alarms for their core functionality.</b>
+ App stores may enforce policies to audit and review the use of this permission. Any app that
+ requests this but is found to not require exact alarms for its primary function may be
+ removed from the app store.
+ -->
+ <permission android:name="android.permission.USE_EXACT_ALARM"
+ android:protectionLevel="normal"/>
+
+ <!-- Allows an application to query tablet mode state and monitor changes
+ in it.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.TABLET_MODE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to request installing packages. Apps
+ targeting APIs greater than 25 must hold this permission in
+ order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
+ android:label="@string/permlab_requestInstallPackages"
+ android:description="@string/permdesc_requestInstallPackages"
+ android:protectionLevel="signature|appop" />
+
+ <!-- Allows an application to request deleting packages. Apps
+ targeting APIs {@link android.os.Build.VERSION_CODES#P} or greater must hold this
+ permission in order to use {@link android.content.Intent#ACTION_UNINSTALL_PACKAGE} or
+ {@link android.content.pm.PackageInstaller#uninstall}.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_DELETE_PACKAGES"
+ android:label="@string/permlab_requestDeletePackages"
+ android:description="@string/permdesc_requestDeletePackages"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to install packages.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.INSTALL_PACKAGES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to install self updates. This is a limited version
+ of {@link android.Manifest.permission#INSTALL_PACKAGES}.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.INSTALL_SELF_UPDATES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to install updates. This is a limited version
+ of {@link android.Manifest.permission#INSTALL_PACKAGES}.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.INSTALL_PACKAGE_UPDATES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to install existing system packages. This is a limited
+ version of {@link android.Manifest.permission#INSTALL_PACKAGES}.
+ <p>Not for use by third-party applications.
+ TODO(b/80204953): remove this permission once we have a long-term solution.
+ @hide
+ -->
+ <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows an application to use the package installer v2 APIs.
+ <p>The package installer v2 APIs are still a work in progress and we're
+ currently validating they work in all scenarios.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="com.android.permission.USE_INSTALLER_V2"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @TestApi Allows a testOnly application to get installed.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.INSTALL_TEST_ONLY_PACKAGE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to install DPCs only, an application is
+ considered a DPC if it has a {@link android.app.admin.DeviceAdminReceiver}
+ protected by {@link android.Manifest.permission#BIND_DEVICE_ADMIN).
+ This is a limited version of
+ {@link android.Manifest.permission#INSTALL_PACKAGES}.
+ @hide
+ -->
+ <permission android:name="android.permission.INSTALL_DPC_PACKAGES"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Allows an application to read resolved paths to the APKs (Base and any splits)
+ of a session based install.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.READ_INSTALLED_SESSION_PATHS"
+ android:protectionLevel="signature|installer" />
+ <uses-permission android:name="android.permission.READ_INSTALLED_SESSION_PATHS" />
+
+ <!-- Allows an application to use System Data Loaders.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="com.android.permission.USE_SYSTEM_DATA_LOADERS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @TestApi Allows an application to clear user data.
+ <p>Not for use by third-party applications
+ @hide
+ -->
+ <permission android:name="android.permission.CLEAR_APP_USER_DATA"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @hide Allows an application to get the URI permissions
+ granted to another application.
+ <p>Not for use by third-party applications
+ -->
+ <permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to clear the URI permissions
+ granted to another application.
+ <p>Not for use by third-party applications
+ -->
+ <permission
+ android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide
+ Allows an application to change the status of Scoped Access Directory requests granted or
+ rejected by the user.
+ <p>This permission should <em>only</em> be requested by the platform
+ settings app. This permission cannot be granted to third-party apps.
+ <p>Protection level: signature
+ -->
+ <permission
+ android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide
+ Allows an application to change the status of a persistable URI permission granted
+ to another application.
+ <p>This permission should <em>only</em> be requested by the platform
+ settings app. This permission cannot be granted to third-party apps.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.FORCE_PERSISTABLE_URI_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- Old permission for deleting an app's cache files, no longer used,
+ but signals for us to quietly ignore calls instead of throwing an exception.
+ <p>Protection level: signature|privileged -->
+ <permission android:name="android.permission.DELETE_CACHE_FILES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to delete cache files.
+ @hide -->
+ <permission android:name="android.permission.INTERNAL_DELETE_CACHE_FILES"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to delete packages.
+ <p>Not for use by third-party applications.
+ <p>Starting in {@link android.os.Build.VERSION_CODES#N}, user confirmation is requested
+ when the application deleting the package is not the same application that installed the
+ package. -->
+ <permission android:name="android.permission.DELETE_PACKAGES"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to move location of installed package.
+ @hide -->
+ <permission android:name="android.permission.MOVE_PACKAGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @TestApi Allows an application to keep uninstalled packages as apks.
+ @hide -->
+ <permission android:name="android.permission.KEEP_UNINSTALLED_PACKAGES"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to change whether an application component (other than its own) is
+ enabled or not.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to grant specific permissions.
+ @hide -->
+ <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature|installer|verifier" />
+
+ <!-- @SystemApi Allows an application to launch the settings page which manages various
+ permissions.
+ @hide -->
+ <permission android:name="android.permission.LAUNCH_PERMISSION_SETTINGS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an app that has this permission and the permissions to install packages
+ to request certain runtime permissions to be granted at installation.
+ @hide -->
+ <permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature|installer|verifier" />
+
+ <!-- @SystemApi Allows an application to revoke specific permissions.
+ @hide -->
+ <permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature|installer|verifier" />
+
+ <!-- @TestApi Allows an application to revoke the POST_NOTIFICATIONS permission from an app
+ without killing the app. Only granted to the shell.
+ @hide -->
+ <permission android:name="android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows the system to read runtime permission state.
+ @hide -->
+ <permission android:name="android.permission.GET_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows the system to restore runtime permission state. This might grant
+ permissions, hence this is a more scoped, less powerful variant of GRANT_RUNTIME_PERMISSIONS.
+ Among other restrictions this cannot override user choices.
+ @hide -->
+ <permission android:name="android.permission.RESTORE_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to change policy_fixed permissions.
+ @hide -->
+ <permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @SystemApi @TestApi Allows an application to upgrade runtime permissions.
+ @hide -->
+ <permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to allowlist restricted permissions
+ on any of the whitelists.
+ @hide -->
+ <permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @SystemApi Allows an application to an exempt an app from having its permission be
+ auto-revoked when unused for an extended period of time.
+ @hide -->
+ <permission android:name="android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @hide Allows an application to observe permission changes. -->
+ <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to start and stop one time permission sessions
+ @hide -->
+ <permission android:name="android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @SystemApi Allows an application to manage the holders of a role.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @SystemApi Allows an application to manage the holders of roles associated with default
+ applications.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_DEFAULT_APPLICATIONS"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Allows an application to bypass role qualification. This allows switching role
+ holders to otherwise non eligible holders. Only the shell is allowed to do this, the
+ qualification for the shell role itself cannot be bypassed, and each role needs to
+ explicitly allow bypassing qualification in its definition. The bypass state will not be
+ persisted across reboot.
+ @hide -->
+ <permission android:name="android.permission.BYPASS_ROLE_QUALIFICATION"
+ android:protectionLevel="internal|role" />
+
+ <!-- @SystemApi Allows an application to observe role holder changes.
+ @hide -->
+ <permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"
+ android:protectionLevel="signature|installer" />
+
+ <!-- Allows an application to manage the companion devices.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_COMPANION_DEVICES"
+ android:protectionLevel="signature|role|module" />
+
+ <!-- Allows an application to subscribe to notifications about the presence status change
+ of their associated companion device
+ -->
+ <permission android:name="android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to deliver companion messages to system
+ -->
+ <permission android:name="android.permission.DELIVER_COMPANION_MESSAGES"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to use companion transports
+ @hide -->
+ <permission android:name="android.permission.USE_COMPANION_TRANSPORTS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to create new companion device associations.
+ @SystemApi
+ @hide -->
+ <permission android:name="android.permission.ASSOCIATE_COMPANION_DEVICES"
+ android:protectionLevel="internal|role" />
+
+ <!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to rotate a surface by arbitrary degree.
+ This is a sub-feature of ACCESS_SURFACE_FLINGER and can be granted in a more concrete way.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.ROTATE_SURFACE_FLINGER"
+ android:protectionLevel="signature|recents" />
+
+ <!-- @SystemApi Allows an application to provide hints to SurfaceFlinger that can influence
+ its wakes up time to compose the next frame. This is a subset of the capabilities granted
+ by {@link #ACCESS_SURFACE_FLINGER}.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.WAKEUP_SURFACE_FLINGER"
+ android:protectionLevel="signature|recents" />
+
+ <!-- Allows an application to take screen shots and more generally
+ get access to the frame buffer data.
+ <p>Not for use by third-party applications.
+ @hide
+ @removed -->
+ <permission android:name="android.permission.READ_FRAME_BUFFER"
+ android:protectionLevel="signature|recents" />
+
+ <!-- Allows an application to use InputFlinger's low level features.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_INPUT_FLINGER"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to disable/enable input devices.
+ Could be used to prevent unwanted touch events
+ on a touchscreen, for example during swimming or rain.
+ @hide -->
+ <permission android:name="android.permission.DISABLE_INPUT_DEVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to configure and connect to Wifi displays
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
+ android:protectionLevel="signature|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
+
+ <!-- Allows an application to control low-level features of Wifi displays
+ such as opening an RTSP socket. This permission should only be used
+ by the display manager.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to control the color modes set for displays system-wide.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to control the lights on the device.
+ @hide
+ @SystemApi
+ @TestApi -->
+ <permission android:name="android.permission.CONTROL_DEVICE_LIGHTS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to control the color saturation of the display.
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.CONTROL_DISPLAY_SATURATION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to control display color transformations.
+ <p>Not for use by third-party applications.</p>
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to collect usage infomation about brightness slider changes.
+ <p>Not for use by third-party applications.</p>
+ @hide
+ @SystemApi
+ @TestApi -->
+ <permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows an application to collect ambient light stats.
+ <p>Not for use by third party applications.</p>
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.ACCESS_AMBIENT_LIGHT_STATS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows an application to modify the display brightness configuration
+ @hide
+ @SystemApi
+ @TestApi -->
+ <permission android:name="android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows an application to control the system's display brightness
+ @hide -->
+ <permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to override the display mode requests
+ so the app requested mode will be selected and user settings and display
+ policies will be ignored.
+ @hide
+ @TestApi -->
+ <permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to modify the refresh rate switching type. This
+ matches Setting.Secure.MATCH_CONTENT_FRAME_RATE.
+ @hide
+ @TestApi -->
+ <permission android:name="android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to modify the user preferred display mode.
+ @hide
+ @TestApi -->
+ <permission android:name="android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to modify the HDR conversion mode.
+ @hide
+ @TestApi -->
+ <permission android:name="android.permission.MODIFY_HDR_CONVERSION_MODE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to control VPN.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CONTROL_VPN"
+ android:protectionLevel="signature|privileged" />
+ <uses-permission android:name="android.permission.CONTROL_VPN" />
+
+ <!-- Allows an application to access and modify always-on VPN configuration.
+ <p>Not for use by third-party or privileged applications.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to capture the audio from tuner input devices types,
+ such as FM_TUNER.
+
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CAPTURE_TUNER_AUDIO_INPUT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to capture audio output.
+ Use the {@code CAPTURE_MEDIA_OUTPUT} permission if only the {@code USAGE_UNKNOWN}),
+ {@code USAGE_MEDIA}) or {@code USAGE_GAME}) usages are intended to be captured.
+ <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to capture the audio played by other apps
+ that have set an allow capture policy of
+ {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}.
+
+ Without this permission, only audio with an allow capture policy of
+ {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_ALL} can be used.
+
+ There are strong restriction listed at
+ {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}
+ on what an app can do with the captured audio.
+
+ See {@code CAPTURE_AUDIO_OUTPUT} for capturing audio use cases other than media playback.
+
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CAPTURE_MEDIA_OUTPUT"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to capture the audio played by other apps
+ with the {@code USAGE_VOICE_COMMUNICATION} usage.
+
+ The application may opt out of capturing by setting an allow capture policy of
+ {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+
+ There are strong restriction listed at
+ {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}
+ on what an app can do with the captured audio.
+
+ See {@code CAPTURE_AUDIO_OUTPUT} and {@code CAPTURE_MEDIA_OUTPUT} for capturing
+ audio use cases other than voice communication playback.
+
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to capture audio for hotword detection.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to access the ultrasound content.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.ACCESS_ULTRASOUND"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Puts an application in the chain of trust for sound trigger
+ operations. Being in the chain of trust allows an application to
+ delegate an identity of a separate entity to the sound trigger system
+ and vouch for the authenticity of this identity.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.SOUNDTRIGGER_DELEGATE_IDENTITY"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to modify audio routing and override policy decisions.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to access the uplink and downlink audio of an ongoing
+ call.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CALL_AUDIO_INTERCEPTION"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!--@SystemApi Allows an application to modify system audio settings that shouldn't be
+ controllable by external apps, such as volume settings or volume behaviors for audio
+ devices, regardless of their connection status.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @TestApi Allows an application to query audio related state.
+ @hide -->
+ <permission android:name="android.permission.QUERY_AUDIO_STATE"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows an application to modify what effects are applied to all audio
+ (matching certain criteria) from any application.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to disable system sound effects when the user exits one of
+ the application's activities.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.DISABLE_SYSTEM_SOUND_EFFECTS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to provide remote displays.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.REMOTE_DISPLAY_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to capture video output.
+ <p>Not for use by third-party applications.</p>
+ @hide
+ @removed -->
+ <permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to capture secure video output.
+ <p>Not for use by third-party applications.</p>
+ @hide
+ @removed -->
+ <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to know what content is playing and control its playback.
+ <p>Not for use by third-party applications due to privacy of media consumption</p> -->
+ <permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to control the routing of media apps.
+ <p>Only for use by role COMPANION_DEVICE_WATCH</p>
+ @FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")
+ -->
+ <permission android:name="android.permission.MEDIA_ROUTING_CONTROL"
+ android:protectionLevel="signature|appop" />
+
+ <!-- @SystemApi @hide Allows an application to set the volume key long-press listener.
+ <p>When it's set, the application will receive the volume key long-press event
+ instead of changing volume.</p>
+ <p>Not for use by third-party applications</p> -->
+ <permission android:name="android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- @SystemApi @hide Allows an application to set media key event listener.
+ <p>When it's set, the application will receive the media key event before
+ any other media sessions. If the event is handled by the listener, other sessions
+ cannot get the event.</p>
+ <p>Not for use by third-party applications</p> -->
+ <permission android:name="android.permission.SET_MEDIA_KEY_LISTENER"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- @SystemApi Required to be able to disable the device (very dangerous!).
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.BRICK"
+ android:protectionLevel="signature" />
+
+ <!-- Required to be able to reboot the device.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.REBOOT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows low-level access to power management.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.DEVICE_POWER"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows toggling battery saver on the system.
+ Superseded by DEVICE_POWER permission. @hide @SystemApi
+ -->
+ <permission android:name="android.permission.POWER_SAVER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows providing the system with battery predictions.
+ Superseded by DEVICE_POWER permission. @hide @SystemApi
+ -->
+ <permission android:name="android.permission.BATTERY_PREDICTION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows access to the PowerManager.userActivity function.
+ <p>Not for use by third-party applications. @hide @SystemApi -->
+ <permission android:name="android.permission.USER_ACTIVITY"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide @SystemApi Allows an application to manage Low Power Standby settings.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_LOW_POWER_STANDBY"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide @SystemApi Allows an application to request ports to remain open during
+ Low Power Standby.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SET_LOW_POWER_STANDBY_PORTS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows low-level access to tun tap driver -->
+ <permission android:name="android.permission.NET_TUNNELING"
+ android:protectionLevel="signature|role" />
+
+ <!-- Run as a manufacturer test application, running as the root user.
+ Only available when the device is running in manufacturer test mode.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.FACTORY_TEST"
+ android:protectionLevel="signature" />
+
+ <!-- @hide @TestApi @SystemApi Allows an application to broadcast the intent {@link
+ android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS}.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"
+ android:protectionLevel="signature|privileged|recents" />
+ <uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
+
+ <!-- Allows an application to broadcast a notification that an application
+ package has been removed.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to broadcast an SMS receipt notification.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.BROADCAST_SMS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to broadcast a WAP PUSH receipt notification.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.BROADCAST_WAP_PUSH"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to broadcast privileged networking requests.
+ <p>Not for use by third-party applications.
+ @hide
+ @deprecated Use {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} instead
+ -->
+ <permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Not for use by third-party applications. -->
+ <permission android:name="android.permission.MASTER_CLEAR"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows an application to call any phone number, including emergency
+ numbers, without going through the Dialer user interface for the user
+ to confirm the call being placed.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CALL_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to perform CDMA OTA provisioning @hide -->
+ <permission android:name="android.permission.PERFORM_CDMA_PROVISIONING"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to perform SIM Activation @hide -->
+ <permission android:name="android.permission.PERFORM_SIM_ACTIVATION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows enabling/disabling location update notifications from
+ the radio.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CONTROL_LOCATION_UPDATES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows read/write access to the "properties" table in the checkin
+ database, to change values that get uploaded.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to collect component usage
+ statistics
+ <p>Declaring the permission implies intention to use the API and the user of the
+ device can grant permission through the Settings application.
+ <p>Protection level: signature|privileged|development|appop|retailDemo -->
+ <permission android:name="android.permission.PACKAGE_USAGE_STATS"
+ android:protectionLevel="signature|privileged|development|appop|retailDemo" />
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+
+ <!-- @SystemApi @hide
+ @FlaggedApi("android.app.usage.report_usage_stats_permission")
+ Allows trusted system components to report events to UsageStatsManager -->
+ <permission android:name="android.permission.REPORT_USAGE_STATS"
+ android:protectionLevel="signature|module" />
+
+ <!-- Allows an application to query broadcast response stats (see
+ {@link android.app.usage.BroadcastResponseStats}).
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_BROADCAST_RESPONSE_STATS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Allows a data loader to read a package's access logs. The access logs contain the
+ set of pages referenced over time.
+ <p>Declaring the permission implies intention to use the API and the user of the
+ device can grant permission through the Settings application.
+ <p>Protection level: signature|privileged|appop
+ <p>A data loader has to be the one which provides data to install an app.
+ <p>A data loader has to have both permission:LOADER_USAGE_STATS AND
+ appop:LOADER_USAGE_STATS allowed to be able to access the read logs. -->
+ <permission android:name="android.permission.LOADER_USAGE_STATS"
+ android:protectionLevel="signature|privileged|appop" />
+ <uses-permission android:name="android.permission.LOADER_USAGE_STATS" />
+
+ <!-- @hide @SystemApi Allows an application to observe usage time of apps. The app can register
+ for callbacks when apps reach a certain usage time limit, etc. -->
+ <permission android:name="android.permission.OBSERVE_APP_USAGE"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @hide @TestApi @SystemApi Allows an application to change the app idle state of an app.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide @TestApi @SystemApi Allows an application to change the estimated launch time
+ of an app.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide @SystemApi Allows an application to temporarily allowlist an inactive app to
+ access the network and acquire wakelocks.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Permission an application must hold in order to use
+ {@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}.
+ <p>Protection level: normal -->
+ <permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
+ android:label="@string/permlab_requestIgnoreBatteryOptimizations"
+ android:description="@string/permdesc_requestIgnoreBatteryOptimizations"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to collect battery statistics
+ <p>Protection level: signature|privileged|development -->
+ <permission android:name="android.permission.BATTERY_STATS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!--Allows an application to manage statscompanion.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.STATSCOMPANION"
+ android:protectionLevel="signature" />
+
+ <!--@SystemApi @hide Allows an application to register stats pull atom callbacks.
+ <p>Not for use by third-party applications.-->
+ <permission android:name="android.permission.REGISTER_STATS_PULL_ATOM"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to read restricted stats from statsd.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_RESTRICTED_STATS"
+ android:protectionLevel="internal|privileged" />
+
+ <!-- @SystemApi Allows an application to control the backup and restore process.
+ <p>Not for use by third-party applications.
+ @hide pending API council -->
+ <permission android:name="android.permission.BACKUP"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to make modifications to device settings such that these
+ modifications will be overridden by settings restore..
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE"
+ android:protectionLevel="signature|setup" />
+
+ <!-- @SystemApi Allows application to manage
+ {@link android.security.keystore.recovery.RecoveryController}.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.RECOVER_KEYSTORE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows application to verify lockscreen credentials provided by a remote device.
+ @hide -->
+ <permission android:name="android.permission.CHECK_REMOTE_LOCKSCREEN"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows a package to launch the secure full-backup confirmation UI.
+ ONLY the system process may hold this permission.
+ @hide -->
+ <permission android:name="android.permission.CONFIRM_FULL_BACKUP"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link android.widget.RemoteViewsService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged -->
+ <permission android:name="android.permission.BIND_REMOTEVIEWS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to tell the AppWidget service which application
+ can access AppWidget's data. The normal user flow is that a user
+ picks an AppWidget to go into a particular host, thereby giving that
+ host application access to the private data from the AppWidget app.
+ An application that has this permission should honor that contract.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.BIND_APPWIDGET"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows sysui to manage user grants of slice permissions. -->
+ <permission android:name="android.permission.MANAGE_SLICE_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Private permission, to restrict who can bring up a dialog to add a new
+ keyguard widget
+ @hide -->
+ <permission android:name="android.permission.BIND_KEYGUARD_APPWIDGET"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Internal permission allowing an application to query/set which
+ applications can bind AppWidgets.
+ @hide -->
+ <permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows applications to change the background data setting.
+ <p>Not for use by third-party applications.
+ @hide pending API council -->
+ <permission android:name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"
+ android:protectionLevel="signature" />
+
+ <!-- This permission can be used on content providers to allow the global
+ search system to access their data. Typically it used when the
+ provider has some permissions protecting it (which global search
+ would not be expected to hold), and added as a read-only permission
+ to the path in the provider where global search queries are
+ performed. This permission can not be held by regular applications;
+ it is used by applications to protect themselves from everyone else
+ besides global search.
+ <p>Protection level: signature|privileged -->
+ <permission android:name="android.permission.GLOBAL_SEARCH"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Internal permission protecting access to the global search
+ system: ensures that only the system can access the provider
+ to perform queries (since this otherwise provides unrestricted
+ access to a variety of content providers), and to write the
+ search statistics (to keep applications from gaming the source
+ ranking).
+ @hide -->
+ <permission android:name="android.permission.GLOBAL_SEARCH_CONTROL"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Internal permission to allows an application to read indexable data.
+ @hide -->
+ <permission android:name="android.permission.READ_SEARCH_INDEXABLES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Internal permission to allows an application to bind to suggestion service.
+ @hide -->
+ <permission android:name="android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Internal permission to allows an application to access card content provider. -->
+ <permission android:name="android.permission.WRITE_SETTINGS_HOMEPAGE_DATA"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- An application needs this permission for
+ {@link android.provider.Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY} to show its
+ {@link android.app.Activity} embedded in Settings app. -->
+ <permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- @SystemApi {@link android.app.Activity} should require this permission to ensure that only
+ the settings app can embed it in a multi pane window.
+ @hide -->
+ <permission android:name="android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows applications to set a live wallpaper.
+ @hide XXX Change to signature once the picker is moved to its
+ own apk as Ghod Intended. -->
+ <permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows applications to set wallpaper dim amount.
+ @hide -->
+ <permission android:name="android.permission.SET_WALLPAPER_DIM_AMOUNT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows applications to read dream settings and dream state.
+ @hide -->
+ <permission android:name="android.permission.READ_DREAM_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows applications to write dream settings, and start or stop dreaming.
+ @hide -->
+ <permission android:name="android.permission.WRITE_DREAM_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows applications to read whether ambient display is suppressed. -->
+ <permission android:name="android.permission.READ_DREAM_SUPPRESSION"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allow an application to read and write the cache partition.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by default container service so that only
+ the system can bind to it and use it to copy
+ protected data to secure containers or files
+ accessible to the system.
+ @hide -->
+ <permission android:name="android.permission.COPY_PROTECTED_DATA"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Internal permission protecting access to the encryption methods
+ @hide
+ -->
+ <permission android:name="android.permission.CRYPT_KEEPER"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to read historical network usage for
+ specific networks and applications. @hide -->
+ <permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to manage network policies (such as warning and disable
+ limits) and to define application-specific rules. @hide -->
+ <permission android:name="android.permission.MANAGE_NETWORK_POLICY"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide @deprecated use UPDATE_DEVICE_STATS instead -->
+ <permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi @hide Allows an application to manage carrier subscription plans. -->
+ <permission android:name="android.permission.MANAGE_SUBSCRIPTION_PLANS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- C2DM permission.
+ @hide Used internally.
+ -->
+ <permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"/>
+
+ <!-- @SystemApi @hide Package verifier needs to have this permission before the PackageManager will
+ trust it to verify packages.
+ -->
+ <permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by package verifier receiver, to ensure that only the
+ system can interact with it.
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_PACKAGE_VERIFIER"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Rollback manager needs to have this permission before the PackageManager will
+ trust it to enable rollback.
+ -->
+ <permission android:name="android.permission.PACKAGE_ROLLBACK_AGENT"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @TestApi @hide Allows managing apk level rollbacks. -->
+ <permission android:name="android.permission.MANAGE_ROLLBACKS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @TestApi @hide Allows testing apk level rollbacks. -->
+ <permission android:name="android.permission.TEST_MANAGE_ROLLBACKS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
+ <permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
+ android:protectionLevel="signature|verifier" />
+
+ <!-- @SystemApi @hide Intent filter verifier needs to have this permission before the
+ PackageManager will trust it to verify intent filters.
+ -->
+ <permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by intent filter verifier rintent-filtereceiver, to ensure that only the
+ system can interact with it.
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_INTENT_FILTER_VERIFIER"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Domain verification agent package needs to have this permission before the
+ system will trust it to verify domains.
+
+ TODO(159952358): STOPSHIP: This must be updated to the new "internal" protectionLevel
+ -->
+ <permission android:name="android.permission.DOMAIN_VERIFICATION_AGENT"
+ android:protectionLevel="internal|privileged" />
+
+ <!-- @SystemApi @hide Must be required by the domain verification agent's intent
+ BroadcastReceiver, to ensure that only the system can interact with it.
+ -->
+ <permission android:name="android.permission.BIND_DOMAIN_VERIFICATION_AGENT"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows an app like Settings to update the user's grants to what domains
+ an app is allowed to automatically open.
+ -->
+ <permission android:name="android.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows applications to access serial ports via the SerialManager.
+ @hide -->
+ <permission android:name="android.permission.SERIAL_PORT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows the holder to access content providers from outside an ApplicationThread.
+ This permission is enforced by the ActivityManagerService on the corresponding APIs,
+ in particular ActivityManagerService#getContentProviderExternal(String) and
+ ActivityManagerService#removeContentProviderExternal(String).
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to hold an UpdateLock, recommending that a headless
+ OTA reboot *not* occur while the lock is held.
+ @hide -->
+ <permission android:name="android.permission.UPDATE_LOCK"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application the opportunity to become a
+ {@link android.service.notification.NotificationAssistantService}.
+ User permission is still required before access is granted.
+ @hide -->
+ <permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi @TestApi Allows an application to read the current set of notifications, including
+ any metadata and intents attached.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_NOTIFICATIONS"
+ android:protectionLevel="signature|privileged|appop" />
+
+ <!-- Marker permission for applications that wish to access notification policy. This permission
+ is not supported on managed profiles.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"
+ android:description="@string/permdesc_access_notification_policy"
+ android:label="@string/permlab_access_notification_policy"
+ android:protectionLevel="normal" />
+
+ <!-- Allows modification of do not disturb rules and policies. Only allowed for system
+ processes.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_NOTIFICATIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @TestApi Allows adding/removing enabled notification listener components.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS"
+ android:protectionLevel="signature|installer" />
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" />
+
+ <!-- @SystemApi Allows notifications to be colorized
+ <p>Not for use by third-party applications. @hide -->
+ <permission android:name="android.permission.USE_COLORIZED_NOTIFICATIONS"
+ android:protectionLevel="signature|setup|role" />
+
+ <!-- Allows access to keyguard secure storage. Only allowed for system processes.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
+ android:protectionLevel="signature|setup" />
+
+ <!-- Allows applications to set the initial lockscreen state.
+ <p>Not for use by third-party applications. @hide -->
+ <permission android:name="android.permission.SET_INITIAL_LOCK"
+ android:protectionLevel="signature|setup"/>
+
+ <!-- @TestApi Allows applications to set and verify lockscreen credentials.
+ @hide -->
+ <permission android:name="android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS"
+ android:protectionLevel="signature"/>
+
+ <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
+ <permission android:name="android.permission.MANAGE_FINGERPRINT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows managing (adding, removing) face templates. Reserved for the system. @hide -->
+ <permission android:name="android.permission.MANAGE_FACE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
+ <permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
+ android:protectionLevel="signature" />
+
+ <!-- Allows access to TestApis for various components in the biometric stack, including
+ FingerprintService, FaceService, BiometricService. Used by com.android.server.biometrics
+ CTS tests. @hide @TestApi -->
+ <permission android:name="android.permission.TEST_BIOMETRIC"
+ android:protectionLevel="signature" />
+
+ <!-- Allows direct access to the <Biometric>Service interfaces. Reserved for the system. @hide -->
+ <permission android:name="android.permission.MANAGE_BIOMETRIC"
+ android:protectionLevel="signature" />
+
+ <!-- Allows direct access to the <Biometric>Service authentication methods. Reserved for the system. @hide -->
+ <permission android:name="android.permission.USE_BIOMETRIC_INTERNAL"
+ android:protectionLevel="signature" />
+
+ <!-- Allows the system to control the BiometricDialog (SystemUI). Reserved for the system. @hide -->
+ <permission android:name="android.permission.MANAGE_BIOMETRIC_DIALOG"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to control keyguard. Only allowed for system processes.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_KEYGUARD"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to control keyguard features like secure notifications.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to manage weak escrow token on the device. This permission
+ is not available to third party applications.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_WEAK_ESCROW_TOKEN"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to listen to trust changes. Only allowed for system processes.
+ @hide -->
+ <permission android:name="android.permission.TRUST_LISTENER"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to provide a trust agent.
+ @hide For security reasons, this is a platform-only permission. -->
+ <permission android:name="android.permission.PROVIDE_TRUST_AGENT"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to show a message
+ on the keyguard when asking to dismiss it.
+ @hide For security reasons, this is a platform-only permission. -->
+ <permission android:name="android.permission.SHOW_KEYGUARD_MESSAGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to launch the trust agent settings activity.
+ @hide -->
+ <permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Must be required by an {@link
+ android.service.trust.TrustAgentService},
+ to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_TRUST_AGENT"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link
+ android.service.notification.NotificationListenerService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Must be required by an {@link
+ android.service.notification.NotificationAssistantService} to ensure that only the system
+ can bind to it.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link
+ android.service.chooser.ChooserTargetService}, to ensure that
+ only the system can bind to it.
+ <p>Protection level: signature
+
+ @deprecated For publishing direct share targets, please follow the instructions in
+ https://developer.android.com/training/sharing/receive.html#providing-direct-share-targets
+ instead.
+ -->
+ <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Must be held by services that extend
+ {@link android.service.resolver.ResolverRankerService}.
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Must be required by services that extend
+ {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can
+ bind to them.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a {@link
+ android.service.notification.ConditionProviderService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_CONDITION_PROVIDER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.service.dreams.DreamService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_DREAM_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.app.usage.CacheQuotaService} to ensure that only the
+ system can bind to it.
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_CACHE_QUOTA_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to call into a carrier setup flow. It is up to the
+ carrier setup application to enforce that this permission is required
+ @hide This is not a third-party API (intended for OEMs and system apps). -->
+ <permission android:name="android.permission.INVOKE_CARRIER_SETUP"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to listen for network condition observations.
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission android:name="android.permission.ACCESS_NETWORK_CONDITIONS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to provision and access DRM certificates
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Api Allows an application to manage media projection sessions.
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to read install sessions
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission android:name="android.permission.READ_INSTALL_SESSIONS"
+ android:label="@string/permlab_readInstallSessions"
+ android:description="@string/permdesc_readInstallSessions"
+ android:protectionLevel="normal"/>
+
+ <!-- @SystemApi Allows an application to remove DRM certificates
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission android:name="android.permission.REMOVE_DRM_CERTIFICATES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @deprecated Use {@link android.Manifest.permission#BIND_CARRIER_SERVICES} instead -->
+ <permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to interact with the currently active
+ {@link android.service.voice.VoiceInteractionService}.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- The system process that is allowed to bind to services in carrier apps will
+ have this permission. Carrier apps should use this permission to protect
+ their services that only the system is allowed to bind to.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_CARRIER_SERVICES"
+ android:label="@string/permlab_bindCarrierServices"
+ android:description="@string/permdesc_bindCarrierServices"
+ android:protectionLevel="signature|privileged" />
+
+ <!--
+ Allows the holder to start the permission usage screen for an app.
+ <p>Protection level: signature|installer
+ -->
+ <permission android:name="android.permission.START_VIEW_PERMISSION_USAGE"
+ android:label="@string/permlab_startViewPermissionUsage"
+ android:description="@string/permdesc_startViewPermissionUsage"
+ android:protectionLevel="signature|installer|module" />
+
+ <!--
+ @SystemApi
+ Allows the holder to start the screen to review permission decisions.
+ <p>Protection level: signature|installer
+ @hide -->
+ <permission android:name="android.permission.START_REVIEW_PERMISSION_DECISIONS"
+ android:label="@string/permlab_startReviewPermissionDecisions"
+ android:description="@string/permdesc_startReviewPermissionDecisions"
+ android:protectionLevel="signature|installer" />
+
+ <!--
+ Allows the holder to start the screen with a list of app features.
+ <p>Protection level: signature|installer
+ -->
+ <permission android:name="android.permission.START_VIEW_APP_FEATURES"
+ android:label="@string/permlab_startViewAppFeatures"
+ android:description="@string/permdesc_startViewAppFeatures"
+ android:protectionLevel="signature|installer" />
+
+ <!-- Allows an application to query whether DO_NOT_ASK_CREDENTIALS_ON_BOOT
+ flag is set.
+ @hide -->
+ <permission android:name="android.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows applications to kill UIDs.
+ <p>This permission can be granted to the SYSTEM_SUPERVISOR role used for parental
+ controls.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.KILL_UID"
+ android:protectionLevel="signature|installer|role" />
+
+ <!-- @SystemApi Allows applications to read the local WiFi and Bluetooth MAC address.
+ @hide -->
+ <permission android:name="android.permission.LOCAL_MAC_ADDRESS"
+ android:protectionLevel="signature|privileged" />
+ <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS"/>
+
+ <!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
+ @hide -->
+ <permission android:name="android.permission.PEERS_MAC_ADDRESS"
+ android:protectionLevel="signature|setup|role" />
+
+ <!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
+ can use this permission to ensure incoming Nfc messages are from the Nfc stack
+ and not simulated by another application.
+ @hide -->
+ <permission android:name="android.permission.DISPATCH_NFC_MESSAGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows changing day / night mode when system is configured with
+ config_lockDayNightMode set to true. If requesting app does not have permission,
+ it will be ignored.
+ @hide -->
+ <permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows entering or exiting car mode using a specified priority.
+ This permission is required to use UiModeManager while specifying a priority for the calling
+ app. A device manufacturer uses this permission to prioritize the apps which can
+ potentially request to enter car-mode on a device to help establish the correct behavior
+ where multiple such apps are active at the same time.
+ @hide -->
+ <permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Required to receive ACTION_ENTER_CAR_MODE_PRIVILEGED or
+ ACTION_EXIT_CAR_MODE_PRIVILEGED.
+ @hide -->
+ <permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows the holder to send category_car notifications.
+ @hide -->
+ <permission
+ android:name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- The system process is explicitly the only one allowed to launch the
+ confirmation UI for full backup/restore -->
+ <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
+
+ <!-- @SystemApi Allows the holder to access and manage instant applications on the device.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_INSTANT_APPS"
+ android:protectionLevel="signature|installer|verifier|role" />
+ <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS"/>
+
+ <!-- Allows the holder to view the instant applications on the device.
+ @hide -->
+ <permission android:name="android.permission.VIEW_INSTANT_APPS"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- Allows the holder to manage whether the system can bind to services
+ provided by instant apps. This permission is intended to protect
+ test/development fucntionality and should be used only in such cases.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows receiving the usage of media resource e.g. video/audio codec and
+ graphic memory.
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by system/priv apps when accessing the sound trigger
+ APIs given by {@link SoundTriggerManager}.
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.MANAGE_SOUND_TRIGGER"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Must be required by system/priv apps to run sound trigger recognition sessions while in
+ battery saver mode.
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Must be required by system/priv apps implementing sound trigger detection services
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows trusted applications to dispatch managed provisioning message to Managed
+ Provisioning app. If requesting app does not have permission, it will be ignored.
+ @hide -->
+ <permission android:name="android.permission.DISPATCH_PROVISIONING_MESSAGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows the holder to read blocked numbers. See
+ {@link android.provider.BlockedNumberContract}.
+ @hide -->
+ <permission android:name="android.permission.READ_BLOCKED_NUMBERS"
+ android:protectionLevel="signature" />
+
+ <!-- Allows the holder to write blocked numbers. See
+ {@link android.provider.BlockedNumberContract}.
+ @hide -->
+ <permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.service.vr.VrListenerService}, to ensure that only
+ the system can bind to it.
+ <p>Protection level: signature -->
+ <permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by system apps when accessing restricted VR APIs.
+ @hide
+ @SystemApi
+ <p>Protection level: signature -->
+ <permission android:name="android.permission.RESTRICTED_VR_ACCESS"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- Required to make calls to {@link android.service.vr.IVrManager}.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_VR_MANAGER"
+ android:protectionLevel="signature" />
+
+ <!-- Required to access VR-Mode state and state change events via {android.app.VrStateCallback}
+ @hide -->
+ <permission android:name="android.permission.ACCESS_VR_STATE"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- Allows an application to allowlist tasks during lock task mode
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
+ android:protectionLevel="signature|setup" />
+
+ <!-- @SystemApi Allows an application to replace the app name displayed alongside notifications
+ in the N-release and later.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to show notifications before the device is provisioned.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.NOTIFICATION_DURING_SETUP"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to manage auto-fill sessions.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_AUTO_FILL"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to manage the content capture service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_CONTENT_CAPTURE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to manager the rotation resolver service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_ROTATION_RESOLVER"
+ android:protectionLevel="signature"/>
+
+ <!-- @SystemApi Allows an application to manage the music recognition service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_MUSIC_RECOGNITION"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- @SystemApi Allows an application to manage speech recognition service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_SPEECH_RECOGNITION"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to manage the content suggestions service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to manage the app predictions service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_APP_PREDICTIONS"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Allows an application to manage the search ui service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_SEARCH_UI"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Allows an application to manage the smartspace service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_SMARTSPACE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to access the smartspace service as a client.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.ACCESS_SMARTSPACE"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- @SystemApi Allows an application to manage the wallpaper effects
+ generation service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to manage the cloudsearch service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_CLOUDSEARCH"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows an app to set the theme overlay in /vendor/overlay
+ being used.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MODIFY_THEME_OVERLAY"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an instant app to create foreground services.
+ <p>Protection level: signature|development|instant|appop -->
+ <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
+ android:protectionLevel="signature|development|instant|appop" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground}.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE"
+ android:description="@string/permdesc_foregroundService"
+ android:label="@string/permlab_foregroundService"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "camera".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "connectedDevice".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "dataSync".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "location".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "mediaPlayback".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "mediaProjection".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "microphone".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "phoneCall".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "health".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "remoteMessaging".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "systemExempted".
+ Apps are allowed to use this type only in the use cases listed in
+ {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED}.
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "fileManagement".
+ <p>Protection level: normal|instant
+ @hide
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT"
+ android:description="@string/permdesc_foregroundServiceFileManagement"
+ android:label="@string/permlab_foregroundServiceFileManagement"
+ android:protectionLevel="normal|instant" />
+
+ <!-- @FlaggedApi("android.content.pm.introduce_media_processing_type")
+ Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "mediaProcessing".
+ <p>Protection level: normal|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROCESSING"
+ android:description="@string/permdesc_foregroundServiceMediaProcessing"
+ android:label="@string/permlab_foregroundServiceMediaProcessing"
+ android:protectionLevel="normal|instant" />
+
+ <!-- Allows a regular application to use {@link android.app.Service#startForeground
+ Service.startForeground} with the type "specialUse".
+ <p>Protection level: normal|appop|instant
+ -->
+ <permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"
+ android:protectionLevel="normal|appop|instant" />
+
+ <!-- @SystemApi Allows to access all app shortcuts.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_SHORTCUTS"
+ android:protectionLevel="signature|role|recents" />
+
+ <!-- @SystemApi Allows unlimited calls to shortcut mutation APIs.
+ @hide -->
+ <permission android:name="android.permission.UNLIMITED_SHORTCUTS_API_CALLS"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Allows an application to read the runtime profiles of other apps.
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_RUNTIME_PROFILES"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows audio policy management. -->
+ <permission android:name="android.permission.MANAGE_AUDIO_POLICY"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to turn on / off quiet mode.
+ @hide -->
+ <permission android:name="android.permission.MODIFY_QUIET_MODE"
+ android:protectionLevel="signature|privileged|development|role" />
+
+ <!-- Allows internal management of the camera framework
+ @hide -->
+ <permission android:name="android.permission.MANAGE_CAMERA"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to control remote animations. See
+ {@link ActivityOptions#makeRemoteAnimation}
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"
+ android:protectionLevel="signature|privileged|recents" />
+
+ <!-- Allows an application to watch changes and/or active state of app ops.
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WATCH_APPOPS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows hidden API checks to be disabled when starting a process.
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Permission that protects the
+ {@link android.provider.Telephony.Intents#ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL}
+ broadcast -->
+ <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission.
+ <p>Protection level: signature -->
+ <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.service.watchdog.ExplicitHealthCheckService} to
+ ensure that only the system can bind to it.
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Must be required by an {@link android.service.storage.ExternalStorageService} to
+ ensure that only the system can bind to it.
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_EXTERNAL_STORAGE_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Permission that allows configuring appops.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_APPOPS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Permission that allows background clipboard access.
+ @hide Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Permission that allows apps to disable the clipboard access notifications.
+ @hide
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_CLIPBOARD_ACCESS_NOTIFICATION"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @hide Permission that suppresses the notification when the clipboard is accessed.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows modifying accessibility state.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_ACCESSIBILITY"
+ android:protectionLevel="signature|setup|recents|role" />
+
+ <!-- @FlaggedApi("com.android.server.accessibility.motion_event_observing")
+ @hide
+ @TestApi
+ Allows an accessibility service to observe motion events without consuming them. -->
+ <permission android:name="android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an app to grant a profile owner access to device identifiers.
+ <p>Not for use by third-party applications.
+ @deprecated
+ @hide -->
+ <permission android:name="android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an app to mark a profile owner as managing an organization-owned device.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MARK_DEVICE_ORGANIZATION_OWNED"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows financial apps to read filtered sms messages.
+ Protection level: signature|appop
+ @deprecated The API that used this permission is no longer functional. -->
+ <permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS"
+ android:protectionLevel="signature|appop" />
+
+ <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#Q} that want to use
+ {@link android.app.Notification.Builder#setFullScreenIntent notification full screen
+ intents}.
+ <p>Protection level: normal -->
+ <permission android:name="android.permission.USE_FULL_SCREEN_INTENT"
+ android:label="@string/permlab_fullScreenIntent"
+ android:description="@string/permdesc_fullScreenIntent"
+ android:protectionLevel="normal|appop" />
+
+ <!-- @SystemApi Required for the privileged assistant apps targeting
+ {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
+ that receive voice trigger from a sandboxed {@link HotwordDetectionService}.
+ <p>Protection level: signature|privileged|appop
+ @FlaggedApi("android.permission.flags.voice_activation_permission_apis")
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO"
+ android:protectionLevel="signature|privileged|appop" />
+
+ <!-- @SystemApi Required for the privileged assistant apps targeting
+ {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
+ that receive training data from a sandboxed {@link HotwordDetectionService} or
+ {@link VisualQueryDetectionService}.
+ <p>Protection level: internal|appop
+ @FlaggedApi("android.permission.flags.voice_activation_permission_apis")
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA"
+ android:protectionLevel="internal|appop" />
+
+ <!-- @SystemApi Allows requesting the framework broadcast the
+ {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY} intent.
+ @hide -->
+ <permission android:name="android.permission.SEND_DEVICE_CUSTOMIZATION_READY"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Permission that protects the {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY}
+ intent.
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- @SystemApi Allows wallpaper to be rendered in ambient mode.
+ @hide -->
+ <permission android:name="android.permission.AMBIENT_WALLPAPER"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- @SystemApi Allows sensor privacy to be modified.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_SENSOR_PRIVACY"
+ android:protectionLevel="internal|role|installer" />
+
+ <!-- @SystemApi Allows sensor privacy changes to be observed.
+ @hide -->
+ <permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY"
+ android:protectionLevel="internal|role|installer" />
+
+ <!-- @SystemApi Permission that protects the {@link Intent#ACTION_REVIEW_ACCESSIBILITY_SERVICES}
+ intent.
+ @hide -->
+ <permission android:name="android.permission.REVIEW_ACCESSIBILITY_SERVICES"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an activity to replace the app name and icon displayed in share targets
+ in the sharesheet for the Q-release and later.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to access shared libraries.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
+ android:protectionLevel="signature|installer" />
+
+ <!-- Allows an app to log compat change usage.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.LOG_COMPAT_CHANGE"
+ android:protectionLevel="signature|privileged" />
+ <!-- Allows an app to read compat change config.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
+ android:protectionLevel="signature|privileged" />
+ <!-- Allows an app to override compat change config.
+ This permission only allows to override config on debuggable builds or test-apks and is
+ therefore a less powerful version of OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
+ android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an app to override compat change config on release builds.
+ Only ChangeIds that are annotated as @Overridable can be overridden on release builds.
+ @hide -->
+ <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows input events to be monitored. Very dangerous! @hide -->
+ <permission android:name="android.permission.MONITOR_INPUT"
+ android:protectionLevel="signature|recents" />
+ <!-- Allows the use of FLAG_SLIPPERY, which permits touch events to slip from the current
+ window to the window where the touch currently is on top of. @hide -->
+ <permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"
+ android:protectionLevel="signature|privileged|recents|role" />
+ <!-- Allows the caller to change the associations between input devices and displays.
+ Very dangerous! @hide -->
+ <permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY"
+ android:protectionLevel="signature" />
+
+ <!-- Allows query of any normal app on the device, regardless of manifest declarations.
+ <p>Protection level: normal -->
+ <permission android:name="android.permission.QUERY_ALL_PACKAGES"
+ android:label="@string/permlab_queryAllPackages"
+ android:description="@string/permdesc_queryAllPackages"
+ android:protectionLevel="normal" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
+ <!-- @hide Allow the caller to collect debugging data from processes that otherwise
+ would require USAGE_STATS. Before sharing this data with other apps, holders
+ of this permission are REQUIRED to themselves check that the caller has
+ PACKAGE_USAGE_STATS and OP_GET_USAGE_STATS. -->
+ <permission android:name="android.permission.PEEK_DROPBOX_DATA"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an application to access TV tuner HAL
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_TV_TUNER"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- @SystemApi Allows an application to access descrambler of TV tuner HAL
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_TV_DESCRAMBLER"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- @SystemApi Allows an application to access shared filter of TV tuner HAL
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_TV_SHARED_FILTER"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- Allows an application to create trusted displays. @hide @SystemApi -->
+ <permission android:name="android.permission.ADD_TRUSTED_DISPLAY"
+ android:protectionLevel="signature|role" />
+
+ <!-- Allows an application to create always-unlocked displays. @hide @SystemApi -->
+ <permission android:name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY"
+ android:protectionLevel="signature|role"/>
+
+ <!-- @hide @SystemApi Allows an application to access locusId events in the usage stats. -->
+ <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
+ android:protectionLevel="signature|role" />
+
+ <!-- @hide @SystemApi Allows an application to manage app hibernation state. -->
+ <permission android:name="android.permission.MANAGE_APP_HIBERNATION"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @hide @TestApi Allows apps to reset the state of {@link com.android.server.am.AppErrors}.
+ <p>CTS tests will use UiAutomation.adoptShellPermissionIdentity() to gain access. -->
+ <permission android:name="android.permission.RESET_APP_ERRORS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to create/destroy input consumer. -->
+ <permission android:name="android.permission.INPUT_CONSUMER"
+ android:protectionLevel="signature" />
+
+ <!-- @hide @TestApi Allows an application to control the system's device state managed by the
+ {@link android.service.devicestate.DeviceStateManagerService}. For example, on foldable
+ devices this would grant access to toggle between the folded and unfolded states. -->
+ <permission android:name="android.permission.CONTROL_DEVICE_STATE"
+ android:protectionLevel="signature" />
+
+ <!-- @hide @SystemApi Must be required by a
+ {@link android.service.displayhash.DisplayHashingService}
+ to ensure that only the system can bind to it.
+ This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_DISPLAY_HASHING_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @hide @TestApi Allows an application to enable/disable toast rate limiting.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.MANAGE_TOAST_RATE_LIMITING"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows managing the Game Mode
+ @hide -->
+ <permission android:name="android.permission.MANAGE_GAME_MODE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows accessing the frame rate per second of a given application
+ @hide -->
+ <permission android:name="android.permission.ACCESS_FPS_COUNTER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows managing the GameService APIs
+ @hide -->
+ <permission android:name="android.permission.MANAGE_GAME_ACTIVITY"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows managing the Game service
+ @hide @TestApi Used only for testing. -->
+ <permission android:name="android.permission.SET_GAME_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows the holder to register callbacks to inform the RebootReadinessManager
+ when they are performing reboot-blocking work.
+ @hide -->
+ <permission android:name="android.permission.SIGNAL_REBOOT_READINESS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows an application to change the touch mode state.
+ @hide -->
+ <permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows the holder to launch an Intent Resolver flow with custom presentation
+ and/or targets.
+ @FlaggedApi("android.service.chooser.support_nfc_resolver")
+ @hide -->
+ <permission android:name="android.permission.SHOW_CUSTOMIZED_RESOLVER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows an application to get a People Tile preview for a given shortcut. -->
+ <permission android:name="android.permission.GET_PEOPLE_TILE_PREVIEW"
+ android:protectionLevel="signature|recents" />
+
+ <!-- @hide @SystemApi Allows an application to retrieve whether shortcut is backed by a
+ Conversation.
+ TODO(b/180412052): STOPSHIP: Define a role so it can be granted to Shell and AiAi. -->
+ <permission android:name="android.permission.READ_PEOPLE_DATA"
+ android:protectionLevel="signature|recents|role"/>
+
+ <!-- @hide @SystemApi Allows a logical component within an application to
+ temporarily renounce a set of otherwise granted permissions. -->
+ <permission android:name="android.permission.RENOUNCE_PERMISSIONS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to read nearby streaming policy. The policy controls
+ whether to allow the device to stream its notifications and apps to nearby devices. -->
+ <permission android:name="android.permission.READ_NEARBY_STREAMING_POLICY"
+ android:protectionLevel="normal" />
+
+ <!-- @SystemApi Allows the holder to set the source of the data when setting a clip on the
+ clipboard.
+ @hide -->
+ <permission android:name="android.permission.SET_CLIP_SOURCE"
+ android:protectionLevel="signature|recents" />
+
+ <!-- @SystemApi Allows an application to access TV tuned info
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_TUNED_INFO"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+ <!-- Allows an application to indicate via
+ {@link android.content.pm.PackageInstaller.SessionParams#setRequireUserAction(int)}
+ that user action should not be required for an app update.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"
+ android:label="@string/permlab_updatePackagesWithoutUserAction"
+ android:description="@string/permdesc_updatePackagesWithoutUserAction"
+ android:protectionLevel="normal" />
+ <uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"/>
+
+ <!-- Allows an application to indicate via {@link
+ android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership}
+ that it has the intention of becoming the update owner.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP"
+ android:protectionLevel="normal" />
+ <uses-permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP" />
+
+ <!-- Allows an application to take screenshots of layers that normally would be blacked out when
+ a screenshot is taken. Specifically, layers that have the flag
+ {@link android.view.SurfaceControl#SECURE} will be screenshot if the caller requests to
+ capture secure layers. Normally those layers will be rendered black.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"
+ android:protectionLevel="signature" />
+
+ <!-- Allows read only access to phone state with a non dangerous permission,
+ including the information like cellular network type, software version. -->
+ <permission android:name="android.permission.READ_BASIC_PHONE_STATE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readBasicPhoneState"
+ android:description="@string/permdesc_readBasicPhoneState"
+ android:protectionLevel="normal" />
+
+ <!-- @SystemApi Allows an application to query over global data in AppSearch.
+ @hide -->
+ <permission android:name="android.permission.READ_GLOBAL_APP_SEARCH_DATA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to query over global data in AppSearch that's visible to the
+ ASSISTANT role. -->
+ <permission android:name="android.permission.READ_ASSISTANT_APP_SEARCH_DATA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to query over global data in AppSearch that's visible to the
+ HOME role. -->
+ <permission android:name="android.permission.READ_HOME_APP_SEARCH_DATA"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an assistive application to perform actions on behalf of users inside of
+ applications.
+ <p>For now, this permission is only granted to the Assistant application selected by
+ the user.
+ <p>Protection level: internal|role
+ -->
+ <permission android:name="android.permission.EXECUTE_APP_ACTION"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to display its suggestions using the autofill framework.
+ <p>For now, this permission is only granted to the Browser application.
+ <p>Protection level: internal|role
+ -->
+ <permission android:name="android.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS"
+ android:protectionLevel="internal|role" />
+
+ <!-- @SystemApi Allows an application to create virtual devices in VirtualDeviceManager.
+ @hide -->
+ <permission android:name="android.permission.CREATE_VIRTUAL_DEVICE"
+ android:protectionLevel="internal|role" />
+
+ <!-- @SystemApi Must be required by a safety source to send an update using the
+ {@link android.safetycenter.SafetyCenterManager}.
+ <p>Protection level: internal|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE"
+ android:protectionLevel="internal|privileged" />
+
+ <!-- @SystemApi Allows an application to launch device manager setup screens.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.LAUNCH_DEVICE_MANAGER_SETUP"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Allows an application to update certain device management related system
+ resources.
+ @hide -->
+ <permission android:name="android.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi Allows an app to read whether SafetyCenter is enabled/disabled.
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.READ_SAFETY_CENTER_STATUS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Required to access the safety center internal APIs using the
+ {@link android.safetycenter.SafetyCenterManager}.
+ <p>Protection level: internal|installer|role
+ @hide
+ -->
+ <permission android:name="android.permission.MANAGE_SAFETY_CENTER"
+ android:protectionLevel="internal|installer|role" />
+
+ <!-- @SystemApi Allows an app to set keep-clear areas without restrictions on the size or
+ number of keep-clear areas (see {@link android.view.View#setPreferKeepClearRects}).
+ When the system arranges floating windows onscreen, it might decide to ignore keep-clear
+ areas from windows, whose owner does not have this permission.
+ @hide
+ -->
+ <permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an app to set gesture exclusion without restrictions on the vertical extent of the
+ exclusions (see {@link android.view.View#setSystemGestureExclusionRects}).
+ @hide
+ -->
+ <permission android:name="android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION"
+ android:protectionLevel="signature|privileged|recents" />
+
+ <!-- Allows an UID to be visible to the application based on an interaction between the
+ two apps. This permission is not intended to be held by apps.
+ @hide @TestApi -->
+ <permission android:name="android.permission.MAKE_UID_VISIBLE"
+ android:protectionLevel="signature" />
+
+ <!-- Limits the system as the only handler of the QUERY_PACKAGE_RESTART broadcast
+ @hide -->
+ <permission android:name="android.permission.HANDLE_QUERY_PACKAGE_RESTART"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.HANDLE_QUERY_PACKAGE_RESTART" />
+
+ <!-- Allows financed device kiosk apps to perform actions on the Device Lock service
+ @hide @TestApi @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES) -->
+ <permission android:name="android.permission.MANAGE_DEVICE_LOCK_STATE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an app to turn on the screen on, e.g. with
+ {@link android.os.PowerManager#ACQUIRE_CAUSES_WAKEUP}.
+ <p>Intended to only be used by home automation apps.
+ -->
+ <permission android:name="android.permission.TURN_SCREEN_ON"
+ android:label="@string/permlab_turnScreenOn"
+ android:description="@string/permdesc_turnScreenOn"
+ android:protectionLevel="signature|privileged|appop" />
+
+ <!-- Allows applications to use the user-initiated jobs API. For more details
+ see {@link android.app.job.JobInfo.Builder#setUserInitiated}.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.RUN_USER_INITIATED_JOBS"
+ android:protectionLevel="normal"/>
+
+ <!-- Allows a browser to invoke the set of credential candidate query apis.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS"
+ android:protectionLevel="normal" />
+
+ <!-- Allows browsers to call on behalf of another app by passing in a custom origin.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.CREDENTIAL_MANAGER_SET_ORIGIN"
+ android:protectionLevel="normal"/>
+
+ <!-- Allows specifying candidate credential providers to be queried in Credential Manager
+ get flows, or to be preferred as a default in the Credential Manager create flows.
+ <p>Protection level: normal -->
+ <permission android:name="android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS"
+ android:protectionLevel="normal"/>
+
+ <!-- Allows permission to use Credential Manager UI for providing and saving credentials
+ @hide -->
+ <permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an app to list Credential Manager providers.
+ @hide
+ -->
+ <permission android:name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS"
+ android:protectionLevel="signature|privileged"/>
+
+ <!-- Allows a system application to be registered with credential manager without
+ having to be enabled by the user.
+ @SystemApi
+ @hide -->
+ <permission android:name="android.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to be able to store and retrieve credentials from a remote
+ device. -->
+ <permission android:name="android.permission.PROVIDE_REMOTE_CREDENTIALS"
+ android:protectionLevel="signature|privileged|role" />
+
+ <!-- Allows an app access to the installer provided app metadata.
+ @SystemApi
+ @hide -->
+ <permission android:name="android.permission.GET_APP_METADATA"
+ android:protectionLevel="signature|installer" />
+
+ <!-- @hide @SystemApi Allows an application to stage HealthConnect's remote data so that
+ HealthConnect can later integrate it. -->
+ <permission android:name="android.permission.STAGE_HEALTH_CONNECT_REMOTE_DATA"
+ android:protectionLevel="signature|knownSigner"
+ android:knownCerts="@array/config_healthConnectRestoreKnownSigners"/>
+
+ <!-- @hide @TestApi Allows an application to clear HealthConnect's staged remote data for
+ testing only. For security reasons, this is a platform-only permission. -->
+ <permission android:name="android.permission.DELETE_STAGED_HEALTH_CONNECT_REMOTE_DATA"
+ android:protectionLevel="signature" />
+
+ <!-- @hide @TestApi Allows CTS tests running in Sandbox mode to launch activities -->
+ <permission android:name="android.permission.START_ACTIVITIES_FROM_SDK_SANDBOX"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows the holder to call health connect migration APIs.
+ @hide -->
+ <permission android:name="android.permission.MIGRATE_HEALTH_CONNECT_DATA"
+ android:protectionLevel="signature|knownSigner"
+ android:knownCerts="@array/config_healthConnectMigrationKnownSigners" />
+
+ <!-- @SystemApi Allows an app to query apps in clone profile. The permission is
+ bidirectional in nature, i.e. cloned apps would be able to query apps in root user.
+ The permission is not meant for 3P apps as of now.
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.QUERY_CLONED_APPS"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide @SystemApi
+ Allows applications to capture bugreport directly without consent dialog when using the
+ bugreporting API on userdebug/eng build.
+ <p>The application still needs to hold {@link android.permission.DUMP} permission and be
+ bugreport-whitelisted to be able to capture a bugreport using the bugreporting API in the
+ first place. Then, when the corresponding app op of this permission is ALLOWED, the
+ bugreport can be captured directly without going through the consent dialog.
+ <p>Protection level: internal|appop
+ <p>Intended to only be used on userdebug/eng build.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD"
+ android:protectionLevel="internal|appop" />
+
+ <!-- @SystemApi Allows to call APIs that log process lifecycle events
+ @hide -->
+ <permission android:name="android.permission.LOG_FOREGROUND_RESOURCE_USE"
+ android:protectionLevel="signature|module" />
+
+ <!-- @hide Allows the settings app to access GPU service APIs".
+ <p>Not for use by third-party applications.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.ACCESS_GPU_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows an application to get type of any provider uri.
+ <p>Not for use by third-party applications.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.GET_ANY_PROVIDER_TYPE"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows internal applications to read and synchronize non-core flags.
+ Apps without this permission can only read a subset of flags specifically intended
+ for use in "core", (i.e. third party apps). Apps with this permission can define their
+ own flags, and federate those values with other system-level apps.
+ <p>Not for use by third-party applications.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.SYNC_FLAGS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide Allows internal applications to override flags in the FeatureFlags service.
+ <p>Not for use by third-party applications.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.WRITE_FLAGS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide @SystemApi
+ @FlaggedApi("android.app.get_binding_uid_importance")
+ Allows to get the importance of an UID that has a service
+ binding to the app.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @hide Allows internal applications to manage displays.
+ <p>This means intercept internal signals about displays being (dis-)connected
+ and being able to enable or disable connected displays.
+ <p>Not for use by third-party applications.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.MANAGE_DISPLAYS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows apps to reset hotword training data egress count for testing.
+ <p>CTS tests will use UiAutomation.AdoptShellPermissionIdentity() to gain access.
+ <p>Protection level: signature
+ @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds")
+ @hide -->
+ <permission android:name="android.permission.RESET_HOTWORD_TRAINING_DATA_EGRESS_COUNT"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows an app to track all preparations for a complete factory reset.
+ <p>Protection level: signature|privileged
+ @FlaggedApi("android.permission.flags.factory_reset_prep_permission_apis")
+ @hide -->
+ <permission android:name="android.permission.PREPARE_FACTORY_RESET"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Allows focused window to override the default behavior of supported system keys.
+ The following keycodes are supported:
+ <p> KEYCODE_STEM_PRIMARY
+ <p>If an app is granted this permission and has a focused window, it will be allowed to
+ receive supported key events that are otherwise handled by the system. The app can choose
+ to consume the key events and trigger its own behavior, in which case the default key
+ behavior will be skipped.
+ <p>For example, KEYCODE_STEM_PRIMARY by default opens recent app launcher. If the foreground
+ fitness app is granted this permission, it can repurpose the KEYCODE_STEM_PRIMARY button
+ to pause/resume the current fitness session.
+ <p>Protection level: signature|privileged
+ @FlaggedApi("com.android.input.flags.override_key_behavior_permission_apis")
+ @hide -->
+ <permission android:name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @FlaggedApi("com.android.server.notification.flags.redact_otp_notifications_from_untrusted_listeners")
+ Allows apps with a NotificationListenerService to receive notifications with sensitive
+ information
+ <p>Apps with a NotificationListenerService without this permission will not be able
+ to view certain types of sensitive information contained in notifications
+ <p>Protection level: signature|role
+ -->
+ <permission android:name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS"
+ android:protectionLevel="signature|role" />
+
+ <!-- @SystemApi
+ @FlaggedApi("android.app.bic_client")
+ Allows app to call BackgroundInstallControlManager API to retrieve silently installed apps
+ for all users on device.
+ <p>Apps with a BackgroundInstallControlManager client will not be able to call any API without
+ this permission.
+ <p>Protection level: signature|role
+ @hide
+ -->
+ <permission android:name="android.permission.GET_BACKGROUND_INSTALLED_PACKAGES"
+ android:protectionLevel="signature|role" />
+
+ <!-- Attribution for Geofencing service. -->
+ <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
+ <!-- Attribution for Country Detector. -->
+ <attribution android:tag="CountryDetector" android:label="@string/country_detector"/>
+ <!-- Attribution for Location service. -->
+ <attribution android:tag="LocationService" android:label="@string/location_service"/>
+ <!-- Attribution for Gnss service. -->
+ <attribution android:tag="GnssService" android:label="@string/gnss_service"/>
+ <!-- Attribution for Sensor Notification service. -->
+ <attribution android:tag="SensorNotificationService"
+ android:label="@string/sensor_notification_service"/>
+ <!-- Attribution for Twilight service. -->
+ <attribution android:tag="TwilightService" android:label="@string/twilight_service"/>
+ <!-- Attribution for Gnss Time Update service. -->
+ <attribution android:tag="GnssTimeUpdateService"
+ android:label="@string/gnss_time_update_service"/>
+ <!-- Attribution for MusicRecognitionManagerService.
+ <p>Not for use by third-party applications.</p> -->
+ <attribution android:tag="MusicRecognitionManagerService"
+ android:label="@string/music_recognition_manager_service"/>
+
+ <application android:process="system"
+ android:persistent="true"
+ android:hasCode="false"
+ android:label="@string/android_system_label"
+ android:allowClearUserData="false"
+ android:backupAgent="com.android.server.backup.SystemBackupAgent"
+ android:killAfterRestore="false"
+ android:icon="@drawable/ic_launcher_android"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
+ android:defaultToDeviceProtectedStorage="true"
+ android:forceQueryable="true"
+ android:directBootAware="true">
+ <activity android:name="com.android.internal.app.ChooserActivity"
+ android:theme="@style/Theme.DeviceDefault.Chooser"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:documentLaunchMode="never"
+ android:relinquishTaskIdentity="true"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:process=":ui"
+ android:exported="true"
+ android:visibleToInstantApps="true">
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.CHOOSER" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+ <activity android:name="com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity"
+ android:exported="false"
+ android:theme="@style/Theme.DeviceDefault.Dialog.Alert.DayNight"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:documentLaunchMode="never"
+ android:relinquishTaskIdentity="true"
+ android:process=":ui"
+ android:visibleToInstantApps="true">
+ <intent-filter>
+ <action android:name="com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <activity android:name="com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity"
+ android:exported="false"
+ android:theme="@style/Theme.DeviceDefault.Resolver"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:documentLaunchMode="never"
+ android:relinquishTaskIdentity="true"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:process=":ui"
+ android:visibleToInstantApps="true">
+ <intent-filter>
+ <action android:name="com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <activity android:name="com.android.internal.app.IntentForwarderActivity"
+ android:finishOnCloseSystemDialogs="true"
+ android:theme="@style/Theme.Translucent.NoTitleBar"
+ android:excludeFromRecents="true"
+ android:label="@string/user_owner_label"
+ android:exported="true"
+ android:visibleToInstantApps="true"
+ >
+ </activity>
+ <activity-alias android:name="com.android.internal.app.ForwardIntentToParent"
+ android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+ android:exported="true"
+ android:label="@string/user_owner_label">
+ </activity-alias>
+ <activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
+ android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+ android:icon="@drawable/ic_corp_badge"
+ android:exported="true"
+ android:label="@string/managed_profile_label">
+ </activity-alias>
+ <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
+ android:theme="@style/Theme.DeviceDefault.System.Dialog.Alert"
+ android:label="@string/heavy_weight_switcher_title"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:process=":ui">
+ </activity>
+ <activity android:name="com.android.internal.app.PlatLogoActivity"
+ android:theme="@style/Theme.DeviceDefault.Wallpaper.NoTitleBar"
+ android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
+ android:icon="@drawable/platlogo"
+ android:process=":ui">
+ </activity>
+ <activity android:name="com.android.internal.app.DisableCarModeActivity"
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:process=":ui">
+ </activity>
+
+ <activity android:name="android.accounts.ChooseAccountActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.DeviceDefault.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui"
+ android:visibleToInstantApps="true">
+ </activity>
+
+ <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.DeviceDefault.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui"
+ android:visibleToInstantApps="true">
+ </activity>
+
+ <activity android:name="android.accounts.ChooseAccountTypeActivity"
+ android:excludeFromRecents="true"
+ android:theme="@style/Theme.DeviceDefault.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui"
+ android:visibleToInstantApps="true">
+ </activity>
+
+ <activity android:name="android.accounts.CantAddAccountActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar"
+ android:process=":ui">
+ </activity>
+
+ <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
+ android:process=":ui"
+ android:visibleToInstantApps="true">
+ </activity>
+
+ <activity android:name="android.content.SyncActivityTooManyDeletes"
+ android:theme="@style/Theme.DeviceDefault.Light.Dialog"
+ android:label="@string/sync_too_many_deletes"
+ android:process=":ui">
+ </activity>
+
+ <activity android:name="com.android.internal.app.ShutdownActivity"
+ android:permission="android.permission.SHUTDOWN"
+ android:theme="@style/Theme.NoDisplay"
+ android:exported="true"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="com.android.internal.intent.action.REQUEST_SHUTDOWN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.REBOOT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="com.android.internal.app.NetInitiatedActivity"
+ android:theme="@style/Theme.Dialog.Confirmation"
+ android:excludeFromRecents="true"
+ android:process=":ui">
+ </activity>
+
+ <activity android:name="com.android.internal.app.SystemUserHomeActivity"
+ android:enabled="false"
+ android:process=":ui"
+ android:systemUserOnly="true"
+ android:exported="true"
+ android:theme="@style/Theme.Translucent.NoTitleBar">
+ <intent-filter android:priority="-100">
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.HOME" />
+ </intent-filter>
+ </activity>
+
+ <!-- Activity to prompt user if it's ok to create a new user sandbox for a
+ specified account. -->
+ <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
+ android:excludeFromRecents="true"
+ android:process=":ui"
+ android:exported="true"
+ android:theme="@style/Theme.Dialog.Confirmation">
+ <intent-filter android:priority="1000">
+ <action android:name="android.os.action.CREATE_USER" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="com.android.internal.app.SuspendedAppActivity"
+ android:theme="@style/Theme.Dialog.Confirmation"
+ android:excludeFromRecents="true"
+ android:process=":ui">
+ </activity>
+
+ <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
+ android:theme="@style/Theme.Dialog.Confirmation"
+ android:excludeFromRecents="true"
+ android:process=":ui">
+ </activity>
+
+ <activity android:name="com.android.internal.app.BlockedAppActivity"
+ android:theme="@style/Theme.Dialog.Confirmation"
+ android:excludeFromRecents="true"
+ android:lockTaskMode="always"
+ android:process=":ui">
+ </activity>
+
+ <activity android:name="com.android.internal.app.LaunchAfterAuthenticationActivity"
+ android:theme="@style/Theme.Translucent.NoTitleBar"
+ android:excludeFromRecents="true"
+ android:process=":ui">
+ </activity>
+
+ <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
+ android:theme="@style/Theme.Dialog.Confirmation"
+ android:excludeFromRecents="true">
+ </activity>
+
+ <activity android:name="com.android.internal.app.HarmfulAppWarningActivity"
+ android:theme="@style/Theme.Dialog.Confirmation"
+ android:excludeFromRecents="true"
+ android:process=":ui"
+ android:label="@string/harmful_app_warning_title"
+ android:exported="false">
+ </activity>
+
+ <activity android:name="com.android.server.notification.NASLearnMoreActivity"
+ android:theme="@style/Theme.Dialog.Confirmation"
+ android:excludeFromRecents="true"
+ android:exported="false">
+ </activity>
+
+ <receiver android:name="com.android.server.BootReceiver"
+ android:exported="true"
+ android:systemUserOnly="true">
+ <intent-filter android:priority="1000">
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.CertPinInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_PINS" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_INTENT_FIREWALL" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.SmsShortCodesInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_SMS_SHORT_CODES" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.NetworkWatchlistInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_NETWORK_WATCHLIST" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.ApnDbInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="com.android.internal.intent.action.UPDATE_APN_DB" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.CarrierProvisioningUrlsInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.CertificateTransparencyLogInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_CT_LOGS" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.LangIdInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_LANG_ID" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.SmartSelectionInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_SMART_SELECTION" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.ConversationActionsInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_CONVERSATION_ACTIONS" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.CarrierIdInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.os.action.UPDATE_CARRIER_ID_DB" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.EmergencyNumberDbInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.os.action.UPDATE_EMERGENCY_NUMBER_DB" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.MasterClearReceiver"
+ android:exported="true"
+ android:permission="android.permission.MASTER_CLEAR">
+ <intent-filter
+ android:priority="100" >
+ <!-- For Checkin, Settings, etc.: action=FACTORY_RESET -->
+ <action android:name="android.intent.action.FACTORY_RESET" />
+ <!-- As above until all the references to the deprecated MASTER_CLEAR get updated to
+ FACTORY_RESET. -->
+ <action android:name="android.intent.action.MASTER_CLEAR" />
+
+ <!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->
+ <action android:name="com.google.android.c2dm.intent.RECEIVE" />
+ <category android:name="android.intent.category.MASTER_CLEAR" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.WallpaperUpdateReceiver"
+ android:exported="true"
+ android:permission="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY">
+ <intent-filter>
+ <action android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY"/>
+ </intent-filter>
+ </receiver>
+
+ <service android:name="android.hardware.location.GeofenceHardwareService"
+ android:permission="android.permission.LOCATION_HARDWARE"
+ android:exported="false" />
+
+ <service android:name="com.android.server.MountServiceIdler"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.ZramWriteback"
+ android:exported="false"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.backup.FullBackupJob"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.backup.KeyValueBackupJob"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.content.SyncJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.pm.BackgroundDexOptJobService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
+ <service android:name="com.android.server.pm.DynamicCodeLoggingService"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
+ <service android:name="com.android.server.PruneInstantAppsJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.storage.DiskStatsLoggingService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.PreloadsFileCacheExpirationJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.camera.CameraStatsJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.usage.UsageStatsIdleService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.net.watchlist.ReportWatchlistJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.display.BrightnessIdleJob"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.people.data.DataMaintenanceService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service android:name="com.android.server.profcollect.ProfcollectForwardingService$ProfcollectBGJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service
+ android:name="com.android.server.autofill.AutofillCompatAccessibilityService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:visibleToInstantApps="true"
+ android:exported="true">
+ <meta-data
+ android:name="android.accessibilityservice"
+ android:resource="@xml/autofill_compat_accessibility_service" />
+ </service>
+
+ <service android:name="com.android.server.blob.BlobStoreIdleJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
+ <service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.LOAD_DATA"/>
+ </intent-filter>
+ </service>
+
+ <provider
+ android:name="com.android.server.textclassifier.IconsContentProvider"
+ android:authorities="com.android.textclassifier.icons"
+ android:singleUser="true"
+ android:enabled="true"
+ android:exported="true">
+ </provider>
+
+ </application>
+
+</manifest>
diff --git a/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml b/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml
new file mode 100644
index 000000000..be90e7d8a
--- /dev/null
+++ b/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml
@@ -0,0 +1,613 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" >
+
+ <!--
+ This file contains the permissions defined by CarService-Builtin(com.android.car)
+ and CarService-updatable(com.[google.]?android.car.updatable). As this is only a
+ resource file, permissions from both packages can be added here.
+ -->
+ <permission-group android:name="android.car.permission-group.CAR_MONITORING"
+ android:icon="@drawable/perm_group_car"
+ android:description="@string/car_permission_desc"
+ android:label="@string/car_permission_label"/>
+ <permission android:name="android.car.permission.CAR_ENERGY"
+ android:permissionGroup="android.car.permission-group.CAR_MONITORING"
+ android:protectionLevel="dangerous"
+ android:label="@string/car_permission_label_energy"
+ android:description="@string/car_permission_desc_energy"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_ENERGY"
+ android:permissionGroup="android.car.permission-group.CAR_MONITORING"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_energy"
+ android:description="@string/car_permission_desc_control_car_energy"/>
+ <permission android:name="android.car.permission.READ_DRIVER_MONITORING_SETTINGS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_driver_monitoring_settings"
+ android:description="@string/car_permission_desc_read_driver_monitoring_settings"/>
+ <permission android:name="android.car.permission.CONTROL_DRIVER_MONITORING_SETTINGS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_driver_monitoring_settings"
+ android:description="@string/car_permission_desc_control_driver_monitoring_settings"/>
+ <permission android:name="android.car.permission.READ_DRIVER_MONITORING_STATES"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_driver_monitoring_states"
+ android:description="@string/car_permission_desc_read_driver_monitoring_states"/>
+ <permission android:name="android.car.permission.ADJUST_RANGE_REMAINING"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_adjust_range_remaining"
+ android:description="@string/car_permission_desc_adjust_range_remaining"/>
+ <permission android:name="android.car.permission.CAR_IDENTIFICATION"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_identification"
+ android:description="@string/car_permission_desc_car_identification"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_CLIMATE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_hvac"
+ android:description="@string/car_permission_desc_hvac"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_DOORS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_doors"
+ android:description="@string/car_permission_desc_control_car_doors"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_WINDOWS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_windows"
+ android:description="@string/car_permission_desc_control_car_windows"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_MIRRORS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_mirrors"
+ android:description="@string/car_permission_desc_control_car_mirrors"/>
+ <permission android:name="android.car.permission.CONTROL_GLOVE_BOX"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_glove_box"
+ android:description="@string/car_permission_desc_control_glove_box"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_SEATS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_seats"
+ android:description="@string/car_permission_desc_control_car_seats"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_AIRBAGS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_airbags"
+ android:description="@string/car_permission_desc_control_car_airbags"/>
+ <permission android:name="android.car.permission.CAR_MILEAGE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_mileage"
+ android:description="@string/car_permission_desc_mileage"/>
+ <permission android:name="android.car.permission.CAR_TIRES"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_tires"
+ android:description="@string/car_permission_desc_car_tires"/>
+ <permission android:name="android.car.permission.READ_CAR_STEERING"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_steering"
+ android:description="@string/car_permission_desc_car_steering"/>
+ <permission android:name="android.car.permission.READ_CAR_DISPLAY_UNITS"
+ android:protectionLevel="normal"
+ android:label="@string/car_permission_label_read_car_display_units"
+ android:description="@string/car_permission_desc_read_car_display_units"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_DISPLAY_UNITS"
+ android:protectionLevel="normal"
+ android:label="@string/car_permission_label_control_car_display_units"
+ android:description="@string/car_permission_desc_control_car_display_units"/>
+ <permission android:name="android.car.permission.CAR_SPEED"
+ android:permissionGroup="android.permission-group.LOCATION"
+ android:protectionLevel="dangerous"
+ android:label="@string/car_permission_label_speed"
+ android:description="@string/car_permission_desc_speed"/>
+ <permission android:name="android.car.permission.CAR_ENERGY_PORTS"
+ android:protectionLevel="normal"
+ android:label="@string/car_permission_label_car_energy_ports"
+ android:description="@string/car_permission_desc_car_energy_ports"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_ENERGY_PORTS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_energy_ports"
+ android:description="@string/car_permission_desc_control_car_energy_ports"/>
+ <permission android:name="android.car.permission.CAR_ENGINE_DETAILED"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_engine_detailed"
+ android:description="@string/car_permission_desc_car_engine_detailed"/>
+ <permission android:name="android.car.permission.CAR_DYNAMICS_STATE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_vehicle_dynamics_state"
+ android:description="@string/car_permission_desc_vehicle_dynamics_state"/>
+ <permission android:name="android.car.permission.CAR_VENDOR_EXTENSION"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_vendor_extension"
+ android:description="@string/car_permission_desc_vendor_extension"/>
+ <permission android:name="android.car.permission.CAR_PROJECTION"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_projection"
+ android:description="@string/car_permission_desc_projection"/>
+ <permission android:name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_access_projection_status"
+ android:description="@string/car_permission_desc_access_projection_status"/>
+ <permission android:name="android.car.permission.BIND_PROJECTION_SERVICE"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_bind_projection_service"
+ android:description="@string/car_permission_desc_bind_projection_service"/>
+ <permission android:name="android.car.permission.CAR_MOCK_VEHICLE_HAL"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_mock_vehicle_hal"
+ android:description="@string/car_permission_desc_mock_vehicle_hal"/>
+ <permission android:name="android.car.permission.CAR_INFO"
+ android:protectionLevel="normal"
+ android:label="@string/car_permission_label_car_info"
+ android:description="@string/car_permission_desc_car_info"/>
+ <permission android:name="android.car.permission.PRIVILEGED_CAR_INFO"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_privileged_car_info"
+ android:description="@string/car_permission_desc_privileged_car_info"/>
+ <permission android:name="android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_vendor_permission_info"
+ android:description="@string/car_permission_desc_vendor_permission_info"/>
+ <permission android:name="android.car.permission.MANAGE_REMOTE_DEVICE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_manage_remote_device"
+ android:description="@string/car_permission_desc_manage_remote_device"/>
+ <permission android:name="android.car.permission.MANAGE_OCCUPANT_CONNECTION"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_manage_occupant_connection"
+ android:description="@string/car_permission_desc_manage_occupant_connection"/>
+
+ <!-- Allows an application to read the vehicle exterior environment information. For example,
+ it allows an application to read the vehicle exterior temperature and night mode status.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT"
+ android:protectionLevel="normal"
+ android:label="@string/car_permission_label_car_exterior_environment"
+ android:description="@string/car_permission_desc_car_exterior_environment"/>
+ <permission android:name="android.car.permission.CAR_EPOCH_TIME"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_epoch_time"
+ android:description="@string/car_permission_desc_car_epoch_time"/>
+ <permission android:name="android.car.permission.CAR_EXTERIOR_LIGHTS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_exterior_lights"
+ android:description="@string/car_permission_desc_car_exterior_lights"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_exterior_lights"
+ android:description="@string/car_permission_desc_control_car_exterior_lights"/>
+ <permission android:name="android.car.permission.READ_CAR_INTERIOR_LIGHTS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_interior_lights"
+ android:description="@string/car_permission_desc_car_interior_lights"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_INTERIOR_LIGHTS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_interior_lights"
+ android:description="@string/car_permission_desc_control_car_interior_lights"/>
+ <permission android:name="android.car.permission.CAR_POWER"
+ android:protectionLevel="signature|privileged|vendorPrivileged"
+ android:label="@string/car_permission_label_car_power"
+ android:description="@string/car_permission_desc_car_power"/>
+ <permission android:name="android.car.permission.CAR_POWERTRAIN"
+ android:protectionLevel="normal"
+ android:label="@string/car_permission_label_car_powertrain"
+ android:description="@string/car_permission_desc_car_powertrain"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_POWERTRAIN"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_powertrain"
+ android:description="@string/car_permission_desc_control_car_powertrain"/>
+ <permission android:name="android.car.permission.READ_CAR_SEAT_BELTS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_car_seat_belts"
+ android:description="@string/car_permission_desc_read_car_seat_belts"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_DYNAMICS_STATE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_dynamics_state"
+ android:description="@string/car_permission_desc_control_car_dynamics_state"/>
+ <permission android:name="android.car.permission.READ_IMPACT_SENSORS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_impact_sensors"
+ android:description="@string/car_permission_desc_read_impact_sensors"/>
+ <permission android:name="android.car.permission.READ_HEAD_UP_DISPLAY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_head_up_display"
+ android:description="@string/car_permission_desc_read_head_up_display"/>
+ <permission android:name="android.car.permission.CONTROL_HEAD_UP_DISPLAY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_head_up_display"
+ android:description="@string/car_permission_desc_control_head_up_display"/>
+ <permission android:name="android.car.permission.READ_VALET_MODE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_valet_mode"
+ android:description="@string/car_permission_desc_read_valet_mode"/>
+ <permission android:name="android.car.permission.CONTROL_VALET_MODE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_valet_mode"
+ android:description="@string/car_permission_desc_control_valet_mode"/>
+ <permission android:name="android.car.permission.READ_CAR_AIRBAGS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_car_airbags"
+ android:description="@string/car_permission_desc_read_car_airbags"/>
+ <permission android:name="android.car.permission.READ_ULTRASONICS_SENSOR_DATA"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_ultrasonics_sensor_data"
+ android:description="@string/car_permission_desc_read_ultrasonics_sensor_data"/>
+ <permission android:name="android.car.permission.CAR_NAVIGATION_MANAGER"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_car_navigation_manager"
+ android:description="@string/car_permission_desc_car_navigation_manager"/>
+ <permission android:name="android.car.permission.CAR_DIAGNOSTICS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_diag_read"
+ android:description="@string/car_permission_desc_diag_read"/>
+ <permission android:name="android.car.permission.CLEAR_CAR_DIAGNOSTICS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_diag_clear"
+ android:description="@string/car_permission_desc_diag_clear"/>
+ <permission android:name="android.car.permission.BIND_VMS_CLIENT"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_bind_vms_client"
+ android:description="@string/car_permission_desc_bind_vms_client"/>
+ <permission android:name="android.car.permission.VMS_PUBLISHER"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_vms_publisher"
+ android:description="@string/car_permission_desc_vms_publisher"/>
+ <permission android:name="android.car.permission.VMS_SUBSCRIBER"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_vms_subscriber"
+ android:description="@string/car_permission_desc_vms_subscriber"/>
+ <permission android:name="android.car.permission.CAR_DRIVING_STATE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_driving_state"
+ android:description="@string/car_permission_desc_driving_state"/>
+ <permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_use_telemetry_service"
+ android:description="@string/car_permission_desc_use_telemetry_service"/>
+ <permission android:name="android.car.permission.REQUEST_CAR_EVS_ACTIVITY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_request_evs_activity"
+ android:description="@string/car_permission_desc_request_evs_activity"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_evs_activity"
+ android:description="@string/car_permission_desc_control_evs_activity"/>
+ <permission android:name="android.car.permission.USE_CAR_EVS_CAMERA"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_use_evs_camera"
+ android:description="@string/car_permission_desc_use_evs_camera"/>
+ <permission android:name="android.car.permission.MONITOR_CAR_EVS_STATUS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_monitor_evs_status"
+ android:description="@string/car_permission_desc_monitor_evs_status"/>
+ <permission android:name="android.car.permission.CONTROL_APP_BLOCKING"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_app_blocking"
+ android:description="@string/car_permission_desc_control_app_blocking"/>
+ <permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_audio_volume"
+ android:description="@string/car_permission_desc_audio_volume"/>
+ <permission android:name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_audio_settings"
+ android:description="@string/car_permission_desc_audio_settings"/>
+ <permission android:name="android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_receive_ducking"
+ android:description="@string/car_permission_desc_receive_ducking"/>
+ <permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_bind_instrument_cluster_rendering"
+ android:description="@string/car_permission_desc_bind_instrument_cluster_rendering"/>
+ <permission android:name="android.car.permission.BIND_CAR_INPUT_SERVICE"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_bind_input_service"
+ android:description="@string/car_permission_desc_bind_input_service"/>
+ <permission android:name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_car_display_in_cluster"
+ android:description="@string/car_permission_desc_car_display_in_cluster"/>
+ <permission android:name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_car_cluster_control"
+ android:description="@string/car_permission_desc_car_cluster_control"/>
+ <permission android:name="android.car.permission.CAR_MONITOR_CLUSTER_NAVIGATION_STATE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_car_monitor_cluster_navigation_state"
+ android:description="@string/car_permission_desc_car_monitor_cluster_navigation_state"/>
+ <permission android:name="android.car.permission.CAR_HANDLE_USB_AOAP_DEVICE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_handle_usb_aoap_device"
+ android:description="@string/car_permission_desc_car_handle_usb_aoap_device"/>
+ <permission android:name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_ux_restrictions_configuration"
+ android:description="@string/car_permission_desc_car_ux_restrictions_configuration"/>
+ <permission android:name="android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_car_occupant_awareness_state"
+ android:description="@string/car_permission_desc_read_car_occupant_awareness_state"/>
+ <permission android:name="android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_access_private_display_id"
+ android:description="@string/car_permission_desc_access_private_display_id"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_occupant_awareness_system"
+ android:description="@string/car_permission_desc_control_car_occupant_awareness_system"/>
+ <permission android:name="android.car.permission.STORAGE_MONITORING"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_storage_monitoring"
+ android:description="@string/car_permission_desc_storage_monitoring"/>
+ <permission android:name="android.car.permission.CAR_ENROLL_TRUST"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_enroll_trust"
+ android:description="@string/car_permission_desc_enroll_trust"/>
+ <permission android:name="android.car.permission.CAR_TEST_SERVICE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_car_test_service"
+ android:description="@string/car_permission_desc_car_test_service"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_FEATURES"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_features"
+ android:description="@string/car_permission_desc_control_car_features"/>
+ <permission android:name="android.car.permission.USE_CAR_WATCHDOG"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_use_car_watchdog"
+ android:description="@string/car_permission_desc_use_car_watchdog"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_WATCHDOG_CONFIG"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_watchdog_config"
+ android:description="@string/car_permission_desc_control_car_watchdog_config"/>
+ <permission android:name="android.car.permission.COLLECT_CAR_WATCHDOG_METRICS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_collect_car_watchdog_metrics"
+ android:description="@string/car_permission_desc_collect_car_watchdog_metrics"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_WINDOW"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_window"
+ android:description="@string/car_permission_desc_get_car_vendor_category_window"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_WINDOW"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_window"
+ android:description="@string/car_permission_desc_set_car_vendor_category_window"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_DOOR"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_door"
+ android:description="@string/car_permission_desc_get_car_vendor_category_door"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_DOOR"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_door"
+ android:description="@string/car_permission_desc_set_car_vendor_category_door"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_seat"
+ android:description="@string/car_permission_desc_get_car_vendor_category_seat"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_SEAT"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_seat"
+ android:description="@string/car_permission_desc_set_car_vendor_category_seat"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_MIRROR"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_mirror"
+ android:description="@string/car_permission_desc_get_car_vendor_category_mirror"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_MIRROR"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_mirror"
+ android:description="@string/car_permission_desc_set_car_vendor_category_mirror"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_info"
+ android:description="@string/car_permission_desc_get_car_vendor_category_info"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_info"
+ android:description="@string/car_permission_desc_set_car_vendor_category_info"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_ENGINE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_engine"
+ android:description="@string/car_permission_desc_get_car_vendor_category_engine"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_ENGINE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_engine"
+ android:description="@string/car_permission_desc_set_car_vendor_category_engine"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_HVAC"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_hvac"
+ android:description="@string/car_permission_desc_get_car_vendor_category_hvac"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_HVAC"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_hvac"
+ android:description="@string/car_permission_desc_set_car_vendor_category_hvac"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_LIGHT"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_light"
+ android:description="@string/car_permission_desc_get_car_vendor_category_light"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_LIGHT"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_light"
+ android:description="@string/car_permission_desc_set_car_vendor_category_light"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_1"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_1"
+ android:description="@string/car_permission_desc_get_car_vendor_category_1"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_1"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_1"
+ android:description="@string/car_permission_desc_set_car_vendor_category_1"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_2"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_2"
+ android:description="@string/car_permission_desc_get_car_vendor_category_2"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_2"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_2"
+ android:description="@string/car_permission_desc_set_car_vendor_category_2"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_3"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_3"
+ android:description="@string/car_permission_desc_get_car_vendor_category_3"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_3"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_3"
+ android:description="@string/car_permission_desc_set_car_vendor_category_3"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_4"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_4"
+ android:description="@string/car_permission_desc_get_car_vendor_category_4"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_4"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_4"
+ android:description="@string/car_permission_desc_set_car_vendor_category_4"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_5"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_5"
+ android:description="@string/car_permission_desc_get_car_vendor_category_5"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_5"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_5"
+ android:description="@string/car_permission_desc_set_car_vendor_category_5"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_6"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_6"
+ android:description="@string/car_permission_desc_get_car_vendor_category_6"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_6"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_6"
+ android:description="@string/car_permission_desc_set_car_vendor_category_6"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_7"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_7"
+ android:description="@string/car_permission_desc_get_car_vendor_category_7"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_7"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_7"
+ android:description="@string/car_permission_desc_set_car_vendor_category_7"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_8"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_8"
+ android:description="@string/car_permission_desc_get_car_vendor_category_8"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_8"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_8"
+ android:description="@string/car_permission_desc_set_car_vendor_category_8"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_9"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_9"
+ android:description="@string/car_permission_desc_get_car_vendor_category_9"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_9"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_9"
+ android:description="@string/car_permission_desc_set_car_vendor_category_9"/>
+ <permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_10"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_get_car_vendor_category_10"
+ android:description="@string/car_permission_desc_get_car_vendor_category_10"/>
+ <permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_10"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_set_car_vendor_category_10"
+ android:description="@string/car_permission_desc_set_car_vendor_category_10"/>
+ <permission android:name="android.car.permission.CAR_MONITOR_INPUT"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_monitor_input"
+ android:description="@string/car_permission_desc_monitor_input"/>
+ <permission android:name="android.car.permission.READ_CAR_POWER_POLICY"
+ android:protectionLevel="normal"
+ android:label="@string/car_permission_label_read_car_power_policy"
+ android:description="@string/car_permission_desc_read_car_power_policy"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_POWER_POLICY"
+ android:protectionLevel="signature|privileged|vendorPrivileged"
+ android:label="@string/car_permission_label_control_car_power_policy"
+ android:description="@string/car_permission_desc_control_car_power_policy"/>
+ <permission android:name="android.car.permission.CONTROL_SHUTDOWN_PROCESS"
+ android:protectionLevel="signature|privileged|vendorPrivileged"
+ android:label="@string/car_permission_label_adjust_shutdown_process"
+ android:description="@string/car_permission_desc_adjust_shutdown_process"/>
+ <permission android:name="android.car.permission.TEMPLATE_RENDERER"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_template_renderer"
+ android:description="@string/car_permission_desc_template_renderer"/>
+ <permission android:name="android.car.permission.CONTROL_CAR_APP_LAUNCH"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_car_app_launch"
+ android:description="@string/car_permission_desc_control_car_app_launch"/>
+ <permission android:name="android.car.permission.MANAGE_THREAD_PRIORITY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_manage_thread_priority"
+ android:description="@string/car_permission_desc_manage_thread_priority"/>
+ <permission android:name="android.car.permission.BIND_OEM_CAR_SERVICE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_bind_oem_car_service"
+ android:description="@string/car_permission_desc_bind_oem_car_service"/>
+ <permission android:name="android.car.permission.MANAGE_OCCUPANT_ZONE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_manage_occupant_zone"
+ android:description="@string/car_permission_desc_manage_occupant_zone"/>
+ <permission android:name="android.car.permission.CONTROL_STEERING_WHEEL"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_steering_wheel"
+ android:description="@string/car_permission_desc_control_steering_wheel"/>
+ <permission android:name="android.car.permission.USE_REMOTE_ACCESS"
+ android:protectionLevel="normal"
+ android:label="@string/car_permission_label_use_remote_access"
+ android:description="@string/car_permission_desc_use_remote_access"/>
+ <permission android:name="android.car.permission.CONTROL_REMOTE_ACCESS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_remote_access"
+ android:description="@string/car_permission_desc_control_remote_access"/>
+ <permission android:name="android.car.permission.READ_ADAS_SETTINGS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_adas_settings"
+ android:description="@string/car_permission_desc_read_adas_settings"/>
+ <permission android:name="android.car.permission.CONTROL_ADAS_SETTINGS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_adas_settings"
+ android:description="@string/car_permission_desc_control_adas_settings"/>
+ <permission android:name="android.car.permission.READ_ADAS_STATES"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_adas_states"
+ android:description="@string/car_permission_desc_read_adas_states"/>
+ <permission android:name="android.car.permission.CONTROL_ADAS_STATES"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_adas_states"
+ android:description="@string/car_permission_desc_control_adas_states"/>
+ <permission android:name="android.car.permission.ACCESS_MIRRORED_SURFACE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_access_mirrored_surface"
+ android:description="@string/car_permission_desc_access_mirrored_surface"/>
+ <permission android:name="android.car.permission.MIRROR_DISPLAY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_mirror_display"
+ android:description="@string/car_permission_desc_mirror_display"/>
+ <permission android:name="android.car.permission.REGISTER_CAR_SYSTEM_UI_PROXY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_register_car_system_ui_proxy"
+ android:description="@string/car_permission_desc_register_car_system_ui_proxy"/>
+ <permission android:name="android.car.permission.MANAGE_CAR_SYSTEM_UI"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_manage_car_system_ui"
+ android:description="@string/car_permission_desc_manage_car_system_ui"/>
+ <permission android:name="android.car.permission.READ_WINDSHIELD_WIPERS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_read_windshield_wipers"
+ android:description="@string/car_permission_desc_read_windshield_wipers"/>
+ <permission android:name="android.car.permission.CONTROL_WINDSHIELD_WIPERS"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_control_windshield_wipers"
+ android:description="@string/car_permission_desc_control_windshield_wipers"/>
+ <permission android:name="android.car.permission.QUERY_DISPLAY_COMPATIBILITY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_query_display_compatibility"
+ android:description="@string/car_permission_desc_query_display_compatibility"/>
+</manifest>
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/CommandBroadcastReceiver.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/CommandBroadcastReceiver.java
new file mode 100644
index 000000000..02138f36f
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/CommandBroadcastReceiver.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions andf
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import javax.annotation.Nullable;
+
+public class CommandBroadcastReceiver extends BroadcastReceiver {
+
+ private static @Nullable OnCommandResultListener sOnCommandResultListener;
+
+ public interface OnCommandResultListener {
+ void onCommandResult(@Nullable Intent result);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final OnCommandResultListener listener;
+ synchronized (CommandBroadcastReceiver.class) {
+ listener = sOnCommandResultListener;
+ }
+ if (listener != null) {
+ listener.onCommandResult(intent);
+ }
+ }
+
+ public static void setOnCommandResultListener(@Nullable OnCommandResultListener listener) {
+ synchronized (CommandBroadcastReceiver.class) {
+ sOnCommandResultListener = listener;
+ }
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ContactsProviderTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ContactsProviderTest.java
new file mode 100644
index 000000000..f34170a9b
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ContactsProviderTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.permissionpolicy.cts;
+
+import android.content.ContentValues;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.ContactsContract;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify that deprecated contacts permissions are not enforced.
+ */
+@AppModeFull(reason = "Instant apps cannot get the READ_CONTACTS/WRITE_CONTACTS permissions")
+public class ContactsProviderTest extends AndroidTestCase {
+
+ /**
+ * Verifies that query(ContactsContract.Contacts.CONTENT_URI) only requires
+ * permission {@link android.Manifest.permission#READ_CONTACTS}.
+ */
+ @SmallTest
+ public void testQueryContacts() {
+ getContext().getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
+ null, null, null, null);
+ }
+
+ /**
+ * Verifies that insert(ContactsContract.Contacts.CONTENT_URI) only requires
+ * permission {@link android.Manifest.permission#WRITE_CONTACTS}.
+ */
+ @SmallTest
+ public void testInsertContacts() {
+ try {
+ getContext().getContentResolver().insert(ContactsContract.Contacts.CONTENT_URI,
+ new ContentValues());
+ } catch (SecurityException e) {
+ fail("insert(ContactsContract.Contacts.CONTENT_URI) threw SecurityException");
+ } catch (UnsupportedOperationException e) {
+ // It is okay for this fail in this manner.
+ }
+ }
+
+ /**
+ * Verifies that query(ContactsContract.Profile.CONTENT_URI) only requires
+ * permission {@link android.Manifest.permission#READ_CONTACTS}.
+ */
+ @SmallTest
+ public void testQueryProfile() {
+ getContext().getContentResolver().query(ContactsContract.Profile.CONTENT_URI,
+ null, null, null, null);
+ }
+
+ /**
+ * Verifies that insert(ContactsContract.Profile.CONTENT_URI) only requires
+ * permission {@link android.Manifest.permission#WRITE_CONTACTS}. The provider won't
+ * actually let us execute this. But at least it shouldn't throw a security exception.
+ */
+ @SmallTest
+ public void testInsertProfile() {
+ try {
+ getContext().getContentResolver().insert(ContactsContract.Profile.CONTENT_URI,
+ new ContentValues(0));
+ } catch (SecurityException e) {
+ fail("insert(ContactsContract.Profile.CONTENT_URI) threw SecurityException");
+ } catch (UnsupportedOperationException e) {
+ // It is okay for this fail in this manner.
+ }
+ }
+
+ /**
+ * Verifies that update(ContactsContract.Profile.CONTENT_URI) only requires
+ * permission {@link android.Manifest.permission#WRITE_CONTACTS}.
+ */
+ @SmallTest
+ public void testUpdateProfile() {
+ getContext().getContentResolver().update(ContactsContract.Profile.CONTENT_URI,
+ new ContentValues(0), null, null);
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/IntelligenceRolesPolicyTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/IntelligenceRolesPolicyTest.java
new file mode 100644
index 000000000..e2cfe86ca
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/IntelligenceRolesPolicyTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.R;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ApiLevelUtil;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@AppModeFull(reason = "Instant apps cannot read the system servers permission")
+@RunWith(Parameterized.class)
+public class IntelligenceRolesPolicyTest {
+ private final int mConfigKey;
+
+ private static final Context sContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Collection intelligenceRoles() {
+ return Arrays.asList(new Object[][]{
+ {"systemUiIntelligence", R.string.config_systemUiIntelligence},
+ {"systemAmbientAudioIntelligence", R.string.config_systemAmbientAudioIntelligence},
+ {"systemAudioIntelligence", R.string.config_systemAudioIntelligence},
+ {"systemNotificationIntelligence", R.string.config_systemNotificationIntelligence},
+ {"systemTextIntelligence", R.string.config_systemTextIntelligence},
+ {"systemVisualIntelligence", R.string.config_systemVisualIntelligence},
+ });
+ }
+
+ public IntelligenceRolesPolicyTest(String unusedName, int configKey) {
+ mConfigKey = configKey;
+ }
+
+ @Test
+ public void testNoInternetPermissionRequested() throws Exception {
+ assumeTrue(ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S));
+
+ String packageName = sContext.getResources().getString(mConfigKey);
+ assumeTrue(!Strings.isNullOrEmpty(packageName));
+
+ List<String> requestedPermissions;
+
+ try {
+ requestedPermissions = getRequestedPermissions(sContext, packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ // A package is not found, despite overlay config pointing to it. Strictly speaking that
+ // means that the policy for being an intelligence role is fulfilled.
+ return;
+ }
+
+ assertWithMessage("Package " + packageName + "MUST NOT request INTERNET permission. "
+ + "Instead packages MUST access the internet through well-defined APIs in an open "
+ + "source project.")
+ .that(requestedPermissions)
+ .doesNotContain(android.Manifest.permission.INTERNET);
+ }
+
+ private static List<String> getRequestedPermissions(Context context, String pkg)
+ throws PackageManager.NameNotFoundException {
+ PackageInfo packageInfo = context.getPackageManager()
+ .getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
+
+ return Arrays.asList(packageInfo.requestedPermissions);
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoCaptureAudioOutputPermissionTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoCaptureAudioOutputPermissionTest.java
new file mode 100644
index 000000000..ef38573ab
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoCaptureAudioOutputPermissionTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import android.content.pm.PackageManager;
+import android.media.AudioFormat;
+import android.media.AudioRecord;
+import android.media.MediaRecorder.AudioSource;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify the capture system video output permission requirements.
+ */
+public class NoCaptureAudioOutputPermissionTest extends AndroidTestCase {
+ /**
+ * Verify that the AudioRecord constructor fails to create a recording object
+ * when the app does not have permission to capture audio output.
+ * For the purposes of this test, the app must already have the normal audio
+ * record permission, just not the capture audio output permission.
+ * <p>Requires permission:
+ * {@link android.Manifest.permission#RECORD_AUDIO} and
+ * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}.
+ */
+ @SmallTest
+ public void testCreateAudioRecord() {
+ int bufferSize = AudioRecord.getMinBufferSize(44100,
+ AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);
+
+ if (bufferSize <= 0)
+ {
+ // getMinBufferSize() returns an invalid buffer size.
+ // That could be because there is no microphone. In that case,
+ // use this buffer size to test AudioRecord creation.
+ PackageManager packageManager = mContext.getPackageManager();
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
+ bufferSize = 44100;
+ }
+ }
+
+ // The attempt to create the AudioRecord object succeeds even if the
+ // app does not have permission, but the object is not usable.
+ // The API should probably throw SecurityException but it was not originally
+ // designed to do that and it's not clear we can change it now.
+ AudioRecord record = new AudioRecord(AudioSource.REMOTE_SUBMIX, 44100,
+ AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
+ try {
+ assertTrue("AudioRecord state should not be INITIALIZED because the application"
+ + "does not have permission to access the remote submix source",
+ record.getState() != AudioRecord.STATE_INITIALIZED);
+ } finally {
+ record.release();
+ }
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoProcessOutgoingCallPermissionTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoProcessOutgoingCallPermissionTest.java
new file mode 100644
index 000000000..989c927e1
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoProcessOutgoingCallPermissionTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
+import android.telecom.TelecomManager;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Verify that processing outgoing calls requires Permission.
+ */
+@AppModeFull(reason = "Instant apps cannot hold PROCESS_OUTGOING_CALL")
+public class NoProcessOutgoingCallPermissionTest {
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+
+ // Time to wait for call to be placed.
+ private static final int CALL_START_WAIT_TIME_SEC = 30;
+ // Time to wait for a broadcast to be received after we verify that the test app which has
+ // the proper permission got the broadcast
+ private static final int POST_CALL_START_WAIT_TIME_SEC = 5;
+
+ private static final String APK_INSTALL_LOCATION =
+ "/data/local/tmp/cts-permissionpolicy/CtsProcessOutgoingCalls.apk";
+ private static final String LOG_TAG = "NoProcessOutgoingCallPermissionTest";
+
+ private static final String ACTION_TEST_APP_RECEIVED_CALL =
+ "android.permissionpolicy.cts.TEST_APP_RECEIVED_CALL";
+ private static final String TEST_PKG_NAME = "android.permissionpolicy.cts.receivecallbroadcast";
+
+ private final CountDownLatch mTestAppBroadcastLatch = new CountDownLatch(1);
+ private final CountDownLatch mSystemBroadcastLatch = new CountDownLatch(1);
+
+ private void callPhone() {
+ Uri uri = Uri.parse("tel:123456");
+ Intent intent = new Intent(Intent.ACTION_CALL, uri);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ Log.i(LOG_TAG, "Called phone: " + uri.toString());
+ }
+
+ /**
+ * Verify that to process an outgoing call requires Permission.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#PROCESS_OUTGOING_CALLS}
+ */
+ // TODO: add back to LargeTest when test can cancel initiated call
+ @Test
+ public void testProcessOutgoingCall() throws InterruptedException {
+ final PackageManager pm = mContext.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) ||
+ !pm.hasSystemFeature(PackageManager.FEATURE_SIP_VOIP)) {
+ return;
+ }
+
+ OutgoingCallBroadcastReceiver rcvr = new OutgoingCallBroadcastReceiver();
+ IntentFilter filter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
+ filter.addAction(ACTION_TEST_APP_RECEIVED_CALL);
+ mContext.registerReceiver(rcvr, filter, Context.RECEIVER_EXPORTED);
+ // start the test app, so that it can receive the broadcast
+ mContext.startActivity(new Intent().setComponent(new ComponentName(TEST_PKG_NAME,
+ TEST_PKG_NAME + ".ProcessOutgoingCallReceiver$BaseActivity"))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+
+ callPhone();
+
+ boolean testAppGotBroadcast =
+ mTestAppBroadcastLatch.await(CALL_START_WAIT_TIME_SEC, TimeUnit.SECONDS);
+ Assert.assertTrue("Expected test app to receive broadcast within "
+ + CALL_START_WAIT_TIME_SEC + " seconds", testAppGotBroadcast);
+ boolean testClassGotBroadcast =
+ mSystemBroadcastLatch.await(POST_CALL_START_WAIT_TIME_SEC, TimeUnit.SECONDS);
+ Assert.assertFalse("Outgoing call processed without proper permissions",
+ testClassGotBroadcast);
+ }
+
+ @Before
+ public void installApp() {
+ String installResult = runShellCommandOrThrow("pm install -g " + APK_INSTALL_LOCATION);
+ assertThat(installResult.trim()).isEqualTo("Success");
+ }
+
+ @After
+ public void endCall() {
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ mContext.getSystemService(TelecomManager.class).endCall();
+ });
+ runShellCommand("pm uninstall " + TEST_PKG_NAME);
+ }
+
+ public class OutgoingCallBroadcastReceiver extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_TEST_APP_RECEIVED_CALL.equals(intent.getAction())) {
+ mTestAppBroadcastLatch.countDown();
+ return;
+ }
+ Bundle xtrs = intent.getExtras();
+ Log.e(LOG_TAG, xtrs.toString());
+ mSystemBroadcastLatch.countDown();
+ }
+ }
+
+}
+
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoReceiveSmsPermissionTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoReceiveSmsPermissionTest.java
new file mode 100644
index 000000000..c3a29ccb3
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoReceiveSmsPermissionTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SystemUserOnly;
+import android.telephony.SmsManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.test.AndroidTestCase;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Verify Sms and Mms cannot be received without required permissions.
+ * Uses {@link android.telephony.SmsManager}.
+ */
+@AppModeFull(reason = "Instant apps cannot get the SEND_SMS permission")
+@SystemUserOnly(reason = "Secondary users have the DISALLOW_SMS user restriction")
+public class NoReceiveSmsPermissionTest extends AndroidTestCase {
+
+ private static final int SMS_DELIVERED_WAIT_TIME_MILLIS = 4000;
+ private static final String TELEPHONY_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
+ private static final String MESSAGE_STATUS_RECEIVED_ACTION =
+ "com.android.cts.permission.sms.MESSAGE_STATUS_RECEIVED_ACTION";
+ private static final String MESSAGE_SENT_ACTION =
+ "com.android.cts.permission.sms.MESSAGE_SENT";
+ private static final String APP_SPECIFIC_SMS_RECEIVED_ACTION =
+ "com.android.cts.permission.sms.APP_SPECIFIC_SMS_RECEIVED";
+
+
+ private static final String LOG_TAG = "NoReceiveSmsPermissionTest";
+
+ private Semaphore mSemaphore = new Semaphore(0);
+
+ /**
+ * Verify that SmsManager.sendTextMessage requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#SEND_SMS}.
+ *
+ * Note: this test requires that the device under test reports a valid phone number
+ */
+ public void testReceiveTextMessage() {
+ PackageManager packageManager = mContext.getPackageManager();
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+
+ // register our test receiver to receive SMSs. This won't throw a SecurityException,
+ // so test needs to wait to determine if it actual receives an SMS
+ // admittedly, this is a weak verification
+ // this test should be used in conjunction with a test that verifies an SMS can be
+ // received successfully using the same logic if all permissions are in place
+ IllegalSmsReceiver receiver = new IllegalSmsReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(TELEPHONY_SMS_RECEIVED);
+ filter.addAction(MESSAGE_SENT_ACTION);
+ filter.addAction(MESSAGE_STATUS_RECEIVED_ACTION);
+
+ getContext().registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
+ sendSMSToSelf("test");
+
+ waitForForEvents(mSemaphore, 1);
+ assertTrue("[RERUN] Sms not sent successfully. Check signal.",
+ receiver.isMessageSent());
+ assertFalse("Sms received without proper permissions", receiver.isSmsReceived());
+ }
+
+ /**
+ * Verify that without {@link android.Manifest.permission#RECEIVE_SMS} that an SMS sent
+ * containing a nonce from {@link SmsManager#createAppSpecificSmsToken} is delivered
+ * to the app.
+ */
+ public void testAppSpecificSmsToken() {
+ PackageManager packageManager = mContext.getPackageManager();
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+
+ AppSpecificSmsReceiver receiver = new AppSpecificSmsReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(TELEPHONY_SMS_RECEIVED);
+ filter.addAction(MESSAGE_SENT_ACTION);
+ filter.addAction(MESSAGE_STATUS_RECEIVED_ACTION);
+ filter.addAction(APP_SPECIFIC_SMS_RECEIVED_ACTION);
+ getContext().registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
+
+ PendingIntent receivedIntent = PendingIntent.getBroadcast(getContext(), 0,
+ new Intent(APP_SPECIFIC_SMS_RECEIVED_ACTION)
+ .setPackage(getContext().getPackageName()),
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
+
+ String token = SmsManager.getDefault().createAppSpecificSmsToken(receivedIntent);
+ String message = "test message, token=" + token;
+ sendSMSToSelf(message);
+
+ waitForForEvents(mSemaphore, 1);
+ assertTrue("[RERUN] Sms not sent successfully. Check signal.",
+ receiver.isMessageSent());
+ assertFalse("Sms received without proper permissions", receiver.isSmsReceived());
+ waitForForEvents(mSemaphore, 1);
+ assertTrue("App specific SMS intent not triggered", receiver.isAppSpecificSmsReceived());
+ }
+
+ private boolean waitForForEvents(Semaphore semaphore, int expectedNumberOfEvents) {
+ for (int i = 0; i < expectedNumberOfEvents; i++) {
+ try {
+ if (!semaphore.tryAcquire(SMS_DELIVERED_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS)) {
+ return false;
+ }
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void sendSMSToSelf(String message) {
+ PendingIntent sentIntent = PendingIntent.getBroadcast(getContext(), 0,
+ new Intent(MESSAGE_SENT_ACTION).setPackage(getContext().getPackageName()),
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
+ PendingIntent deliveryIntent = PendingIntent.getBroadcast(getContext(), 0,
+ new Intent(MESSAGE_STATUS_RECEIVED_ACTION)
+ .setPackage(getContext().getPackageName()),
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
+
+ SubscriptionManager subscription = (SubscriptionManager)
+ getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ int subscriptionId = subscription.getActiveDataSubscriptionId();
+
+ assertFalse("[RERUN] No active telephony subscription. Check there is one enabled.",
+ subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ // get current phone number
+ String currentNumber = subscription.getPhoneNumber(subscriptionId);
+
+ // fallback to getActiveSubscriptionInfo if number is empty
+ if (TextUtils.isEmpty(currentNumber)) {
+ SubscriptionInfo subInfo = subscription.getActiveSubscriptionInfo(subscriptionId);
+
+ assertTrue("[RERUN] No info for the active telephony subscription.",
+ subInfo != null);
+ currentNumber = subInfo.getNumber();
+ }
+ assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.",
+ TextUtils.isEmpty(currentNumber));
+
+ Log.i(LOG_TAG, String.format("Sending SMS to self: %s", currentNumber));
+ sendSms(currentNumber, message, sentIntent, deliveryIntent);
+ }
+
+ protected void sendSms(String currentNumber, String text, PendingIntent sentIntent,
+ PendingIntent deliveryIntent) {
+ SmsManager.getDefault().sendTextMessage(currentNumber, null, text, sentIntent,
+ deliveryIntent);
+ }
+
+ /**
+ * A receiver that tracks if message was sent and received
+ */
+ public class IllegalSmsReceiver extends BroadcastReceiver {
+
+ private boolean mIsSmsReceived = false;
+ private boolean mIsMessageSent = false;
+
+ public void onReceive(Context context, Intent intent) {
+ if (TELEPHONY_SMS_RECEIVED.equals(intent.getAction())) {
+ // this is bad, received sms without having SMS permission
+ setSmsReceived();
+ } else if (MESSAGE_STATUS_RECEIVED_ACTION.equals(intent.getAction())) {
+ handleResultCode(getResultCode(), "delivery");
+ } else if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
+ handleResultCode(getResultCode(), "sent");
+ } else {
+ Log.w(LOG_TAG, String.format("unknown intent received: %s", intent.getAction()));
+ }
+
+ }
+
+ public boolean isSmsReceived() {
+ return mIsSmsReceived;
+ }
+
+ private synchronized void setSmsReceived() {
+ mIsSmsReceived = true;
+ notify();
+ }
+
+ public boolean isMessageSent() {
+ return mIsMessageSent;
+ }
+
+ private void handleResultCode(int resultCode, String action) {
+ if (resultCode == Activity.RESULT_OK) {
+ Log.i(LOG_TAG, String.format("message %1$s successful", action));
+ setMessageSentSuccess();
+ } else {
+ setMessageSentFailure();
+ String reason = getErrorReason(resultCode);
+ Log.e(LOG_TAG, String.format("message %1$s failed: %2$s", action, reason));
+ }
+ }
+
+ private synchronized void setMessageSentSuccess() {
+ mIsMessageSent = true;
+ // set this to true, but don't notify receiver since we don't know if message received
+ // yet
+ }
+
+ private synchronized void setMessageSentFailure() {
+ mIsMessageSent = false;
+ // test environment failure, notify observer so it can stop listening
+ // TODO: should test retry?
+ notify();
+ }
+
+ private String getErrorReason(int resultCode) {
+ switch (resultCode) {
+ case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
+ return "generic failure";
+ case SmsManager.RESULT_ERROR_NO_SERVICE:
+ return "no service";
+ case SmsManager.RESULT_ERROR_NULL_PDU:
+ return "null pdu";
+ case SmsManager.RESULT_ERROR_RADIO_OFF:
+ return "Radio off";
+ }
+ return "unknown";
+ }
+ }
+
+ public class AppSpecificSmsReceiver extends IllegalSmsReceiver {
+ private boolean mAppSpecificSmsReceived = false;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (APP_SPECIFIC_SMS_RECEIVED_ACTION.equals(intent.getAction())) {
+ mAppSpecificSmsReceived = true;
+ } else {
+ super.onReceive(context, intent);
+ }
+ try {
+ mSemaphore.release();
+ } catch (Exception ex) {
+ Log.e(LOG_TAG, "mSemaphore: Got exception in releasing semaphore, ex=" + ex);
+ }
+ }
+
+ public boolean isAppSpecificSmsReceived() {
+ return mAppSpecificSmsReceived;
+ }
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoWriteSecureSettingsPermissionTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoWriteSecureSettingsPermissionTest.java
new file mode 100644
index 000000000..2e4a806b6
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoWriteSecureSettingsPermissionTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import android.Manifest;
+import android.content.ContentValues;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+
+/**
+ * Verify secure settings cannot be written to without required permissions.
+ */
+public class NoWriteSecureSettingsPermissionTest extends AndroidTestCase {
+
+ /**
+ * Verify that write to secure settings requires permissions.
+ * This test app must have WRITE_SETTINGS permission but not WRITE_SECURE_SETTINGS
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
+ */
+ public void testWriteSecureSettings() {
+ try {
+ ContentValues values = new ContentValues();
+ values.put(Settings.Secure.NAME, Settings.Secure.ACCESSIBILITY_ENABLED);
+ values.put(Settings.Secure.VALUE, Boolean.TRUE);
+ getContext().getContentResolver().insert(Settings.Secure.CONTENT_URI, values);
+ fail("expected SecurityException requiring "
+ + Manifest.permission.WRITE_SECURE_SETTINGS);
+ } catch (SecurityException expected) {
+ /* do nothing */
+ }
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionMaxSdkVersionTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionMaxSdkVersionTest.java
new file mode 100644
index 000000000..8bf3e83a4
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionMaxSdkVersionTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+
+/**
+ * Verify permission behaviors with android:maxSdkVersion
+ */
+public class PermissionMaxSdkVersionTest extends AndroidTestCase {
+ // These two permission names must match the corresponding <uses-permission>
+ // declarations in the test app manifest.
+ static final String UNGRANTABLE_PERMISSION = "android.permission.INTERNET";
+ static final String GRANTABLE_PERMISSION = "android.permission.ACCESS_NETWORK_STATE";
+
+ /**
+ * Verify that with android:maxSdkVersion set to a previous API level,
+ * the permission is not being granted.
+ */
+ @SmallTest
+ public void testMaxSdkInPast() {
+ int result = mContext.checkPermission(UNGRANTABLE_PERMISSION,
+ Process.myPid(), Process.myUid());
+ assertEquals("Permissions with maxSdkVersion in the past should not be granted",
+ result,
+ PackageManager.PERMISSION_DENIED);
+ }
+
+ /**
+ * Verify that with android:maxSdkVersion set to a future API level,
+ * the permission is being granted.
+ */
+ @SmallTest
+ public void testMaxSdkInFuture() {
+ int result = mContext.checkPermission(GRANTABLE_PERMISSION,
+ Process.myPid(), Process.myUid());
+ assertEquals("Permissions with maxSdkVersion in the future should be granted",
+ result,
+ PackageManager.PERMISSION_GRANTED);
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionPolicyTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionPolicyTest.java
new file mode 100644
index 000000000..94bd2be1b
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionPolicyTest.java
@@ -0,0 +1,533 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.permissionpolicy.cts;
+
+import static android.content.pm.PermissionInfo.FLAG_INSTALLED;
+import static android.content.pm.PermissionInfo.PROTECTION_MASK_BASE;
+import static android.os.Build.VERSION.SECURITY_PATCH;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.os.Process;
+import android.os.SystemProperties;
+import android.platform.test.annotations.AppModeFull;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.modules.utils.build.SdkLevel;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Tests for permission policy on the platform.
+ */
+@AppModeFull(reason = "Instant apps cannot read the system servers permission")
+@RunWith(AndroidJUnit4.class)
+public class PermissionPolicyTest {
+ private static final Date HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PATCH_DATE = parseDate("2017-11-01");
+ private static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PERMISSION
+ = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
+
+ private static final Date MANAGE_COMPANION_DEVICES_PATCH_DATE = parseDate("2020-07-01");
+ private static final String MANAGE_COMPANION_DEVICES_PERMISSION
+ = "android.permission.MANAGE_COMPANION_DEVICES";
+
+ private static final String LOG_TAG = "PermissionProtectionTest";
+
+ private static final String PLATFORM_PACKAGE_NAME = "android";
+
+ private static final String PLATFORM_ROOT_NAMESPACE = "android.";
+
+ private static final String TAG_PERMISSION = "permission";
+ private static final String TAG_PERMISSION_GROUP = "permission-group";
+
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_PERMISSION_GROUP = "permissionGroup";
+ private static final String ATTR_PERMISSION_FLAGS = "permissionFlags";
+ private static final String ATTR_PROTECTION_LEVEL = "protectionLevel";
+ private static final String ATTR_BACKGROUND_PERMISSION = "backgroundPermission";
+
+ private static final Context sContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ @Test
+ public void shellIsOnlySystemAppThatRequestsRevokePostNotificationsWithoutKill() {
+ List<PackageInfo> pkgs = sContext.getPackageManager().getInstalledPackages(
+ PackageManager.PackageInfoFlags.of(
+ PackageManager.GET_PERMISSIONS | PackageManager.MATCH_ALL));
+ int shellUid = Process.myUserHandle().getUid(Process.SHELL_UID);
+ for (PackageInfo pkg : pkgs) {
+ Assert.assertFalse(pkg.applicationInfo.uid != shellUid
+ && hasRevokeNotificationNoKillPermission(pkg));
+ }
+ }
+
+ @Test
+ public void platformPermissionPolicyIsUnaltered() throws Exception {
+ Map<String, PermissionInfo> declaredPermissionsMap =
+ getPermissionsForPackage(sContext, PLATFORM_PACKAGE_NAME);
+
+ List<String> offendingList = new ArrayList<>();
+
+ List<PermissionGroupInfo> declaredGroups = sContext.getPackageManager()
+ .getAllPermissionGroups(0);
+ Set<String> declaredGroupsSet = new ArraySet<>();
+ for (PermissionGroupInfo declaredGroup : declaredGroups) {
+ declaredGroupsSet.add(declaredGroup.name);
+ }
+
+ Set<String> expectedPermissionGroups = loadExpectedPermissionGroupNames(
+ R.raw.android_manifest);
+ List<ExpectedPermissionInfo> expectedPermissions = loadExpectedPermissions(
+ R.raw.android_manifest);
+
+ if (sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ expectedPermissions.addAll(loadExpectedPermissions(R.raw.automotive_android_manifest));
+ String carServicePackageName = SystemProperties.get("ro.android.car.carservice.package",
+ null);
+
+ assertWithMessage("Car service package not defined").that(
+ carServicePackageName).isNotNull();
+
+ declaredPermissionsMap.putAll(
+ getPermissionsForPackage(sContext, carServicePackageName));
+
+ // Load signature permission declared in CarService-builtin
+ String carServiceBuiltInPackageName = "com.android.car";
+ Map<String, PermissionInfo> carServiceBuiltInPermissionsMap = getPermissionsForPackage(
+ sContext, carServiceBuiltInPackageName);
+ // carServiceBuiltInPermissionsMap should only have signature permissions and those
+ // permissions should not be defined in car service updatable.
+ for (Map.Entry<String, PermissionInfo> permissionData : carServiceBuiltInPermissionsMap
+ .entrySet()) {
+ PermissionInfo carServiceBuiltInDeclaredPermission = permissionData.getValue();
+ String carServiceBuiltInDeclaredPermissionName = permissionData.getKey();
+
+ // Signature only permission should be defined in built-in car service
+ if ((carServiceBuiltInDeclaredPermission
+ .getProtection() != PermissionInfo.PROTECTION_SIGNATURE)
+ || (carServiceBuiltInDeclaredPermission.getProtectionFlags() != 0)) {
+ offendingList.add("Permission " + carServiceBuiltInDeclaredPermissionName
+ + " should be signature only permission to be declared in"
+ + " carServiceBuiltIn package.");
+ continue;
+ }
+
+ if (declaredPermissionsMap.get(carServiceBuiltInDeclaredPermissionName) != null) {
+ offendingList.add("Permission " + carServiceBuiltInDeclaredPermissionName
+ + " from car service builtin is already declared in other packages.");
+ continue;
+ }
+ }
+ declaredPermissionsMap.putAll(carServiceBuiltInPermissionsMap);
+ }
+
+ for (ExpectedPermissionInfo expectedPermission : expectedPermissions) {
+ String expectedPermissionName = expectedPermission.name;
+ if (shouldSkipPermission(expectedPermissionName)) {
+ // This permission doesn't need to exist yet, but will exist in
+ // a future SPL. It is acceptable to declare the permission
+ // even in an earlier SPL, so we remove it here so it doesn't
+ // trigger a failure after the loop.
+ declaredPermissionsMap.remove(expectedPermissionName);
+ continue;
+ }
+
+ // OEMs cannot remove permissions
+ PermissionInfo declaredPermission = declaredPermissionsMap.get(expectedPermissionName);
+ if (declaredPermission == null) {
+ offendingList.add("Permission " + expectedPermissionName + " must be declared");
+ continue;
+ }
+
+ // We want to end up with OEM defined permissions and groups to check their namespace
+ declaredPermissionsMap.remove(expectedPermissionName);
+
+ // OEMs cannot change permission protection
+ final int expectedProtection = expectedPermission.protectionLevel
+ & PROTECTION_MASK_BASE;
+ final int declaredProtection = declaredPermission.protectionLevel
+ & PROTECTION_MASK_BASE;
+ if (expectedProtection != declaredProtection) {
+ offendingList.add(
+ String.format(
+ "Permission %s invalid protection level %x, expected %x",
+ expectedPermissionName, declaredProtection, expectedProtection));
+ }
+
+ // OEMs cannot change permission flags
+ final int expectedFlags = expectedPermission.flags;
+ final int declaredFlags = (declaredPermission.flags & ~FLAG_INSTALLED);
+ if (expectedFlags != declaredFlags) {
+ offendingList.add(
+ String.format(
+ "Permission %s invalid flags %x, expected %x",
+ expectedPermissionName,
+ declaredFlags,
+ expectedFlags));
+ }
+
+ // OEMs cannot change permission protection flags
+ final int expectedProtectionFlags =
+ expectedPermission.protectionLevel & ~PROTECTION_MASK_BASE;
+ final int declaredProtectionFlags = declaredPermission.getProtectionFlags();
+ if (expectedProtectionFlags != declaredProtectionFlags) {
+ offendingList.add(
+ String.format(
+ "Permission %s invalid enforced protection %x, expected %x",
+ expectedPermissionName,
+ declaredProtectionFlags,
+ expectedProtectionFlags));
+ }
+
+ // OEMs cannot change permission grouping
+ if ((declaredPermission.protectionLevel & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
+ if (!Objects.equals(expectedPermission.group, declaredPermission.group)) {
+ offendingList.add(
+ "Permission " + expectedPermissionName + " not in correct group "
+ + "(expected=" + expectedPermission.group + " actual="
+ + declaredPermission.group);
+ }
+
+ if (declaredPermission.group != null
+ && !declaredGroupsSet.contains(declaredPermission.group)) {
+ offendingList.add(
+ "Permission group " + expectedPermission.group + " must be defined");
+ }
+ }
+
+ // OEMs cannot change background permission mapping
+ if (!Objects.equals(expectedPermission.backgroundPermission,
+ declaredPermission.backgroundPermission)) {
+ offendingList.add(
+ String.format(
+ "Permission %s invalid background permission %s, expected %s",
+ expectedPermissionName,
+ declaredPermission.backgroundPermission,
+ expectedPermission.backgroundPermission));
+ }
+ }
+
+ // OEMs cannot define permissions in the platform namespace
+ for (String permission : declaredPermissionsMap.keySet()) {
+ if (permission.startsWith(PLATFORM_ROOT_NAMESPACE)) {
+ final PermissionInfo permInfo = declaredPermissionsMap.get(permission);
+ offendingList.add(
+ "Cannot define permission " + permission
+ + ", package " + permInfo.packageName
+ + " in android namespace");
+ }
+ }
+
+ // OEMs cannot define groups in the platform namespace
+ for (PermissionGroupInfo declaredGroup : declaredGroups) {
+ if (!expectedPermissionGroups.contains(declaredGroup.name)) {
+ if (declaredGroup.name != null) {
+ if (declaredGroup.packageName.equals(PLATFORM_PACKAGE_NAME)
+ && declaredGroup.name.startsWith(PLATFORM_ROOT_NAMESPACE)) {
+ offendingList.add(
+ "Cannot define group " + declaredGroup.name
+ + ", package " + declaredGroup.packageName
+ + " in android namespace");
+ }
+ }
+ }
+ }
+
+ // OEMs cannot define new ephemeral permissions
+ for (String permission : declaredPermissionsMap.keySet()) {
+ PermissionInfo info = declaredPermissionsMap.get(permission);
+ if ((info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0) {
+ offendingList.add("Cannot define new instant permission " + permission);
+ }
+ }
+
+ // Fail on any offending item
+ assertWithMessage("list of offending permissions").that(offendingList).isEmpty();
+ }
+
+ private boolean hasRevokeNotificationNoKillPermission(PackageInfo info) {
+ if (info.requestedPermissions == null) {
+ return false;
+ }
+
+ for (int i = 0; i < info.requestedPermissions.length; i++) {
+ if (Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL.equals(
+ info.requestedPermissions[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private List<ExpectedPermissionInfo> loadExpectedPermissions(int resourceId) throws Exception {
+ List<ExpectedPermissionInfo> permissions = new ArrayList<>();
+ try (InputStream in = sContext.getResources().openRawResource(resourceId)) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (TAG_PERMISSION.equals(parser.getName())) {
+ ExpectedPermissionInfo permissionInfo = new ExpectedPermissionInfo(
+ parser.getAttributeValue(null, ATTR_NAME),
+ parser.getAttributeValue(null, ATTR_PERMISSION_GROUP),
+ parser.getAttributeValue(null, ATTR_BACKGROUND_PERMISSION),
+ parsePermissionFlags(
+ parser.getAttributeValue(null, ATTR_PERMISSION_FLAGS)),
+ parseProtectionLevel(
+ parser.getAttributeValue(null, ATTR_PROTECTION_LEVEL)));
+ permissions.add(permissionInfo);
+ } else {
+ Log.e(LOG_TAG, "Unknown tag " + parser.getName());
+ }
+ }
+ }
+
+ return permissions;
+ }
+
+ private Set<String> loadExpectedPermissionGroupNames(int resourceId) throws Exception {
+ ArraySet<String> permissionGroups = new ArraySet<>();
+ try (InputStream in = sContext.getResources().openRawResource(resourceId)) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (TAG_PERMISSION_GROUP.equals(parser.getName())) {
+ permissionGroups.add(parser.getAttributeValue(null, ATTR_NAME));
+ } else {
+ Log.e(LOG_TAG, "Unknown tag " + parser.getName());
+ }
+ }
+ }
+ return permissionGroups;
+ }
+
+ private static int parsePermissionFlags(@Nullable String permissionFlagsString) {
+ if (permissionFlagsString == null) {
+ return 0;
+ }
+
+ int protectionFlags = 0;
+ String[] fragments = permissionFlagsString.split("\\|");
+ for (String fragment : fragments) {
+ switch (fragment.trim()) {
+ case "removed": {
+ protectionFlags |= PermissionInfo.FLAG_REMOVED;
+ } break;
+ case "costsMoney": {
+ protectionFlags |= PermissionInfo.FLAG_COSTS_MONEY;
+ } break;
+ case "hardRestricted": {
+ protectionFlags |= PermissionInfo.FLAG_HARD_RESTRICTED;
+ } break;
+ case "immutablyRestricted": {
+ protectionFlags |= PermissionInfo.FLAG_IMMUTABLY_RESTRICTED;
+ } break;
+ case "softRestricted": {
+ protectionFlags |= PermissionInfo.FLAG_SOFT_RESTRICTED;
+ } break;
+ }
+ }
+ return protectionFlags;
+ }
+
+ private static int parseProtectionLevel(String protectionLevelString) {
+ int protectionLevel = 0;
+ String[] fragments = protectionLevelString.split("\\|");
+ for (String fragment : fragments) {
+ switch (fragment.trim()) {
+ case "normal": {
+ protectionLevel |= PermissionInfo.PROTECTION_NORMAL;
+ } break;
+ case "dangerous": {
+ protectionLevel |= PermissionInfo.PROTECTION_DANGEROUS;
+ } break;
+ case "signature": {
+ protectionLevel |= PermissionInfo.PROTECTION_SIGNATURE;
+ } break;
+ case "signatureOrSystem": {
+ protectionLevel |= PermissionInfo.PROTECTION_SIGNATURE;
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_SYSTEM;
+ } break;
+ case "internal": {
+ protectionLevel |= PermissionInfo.PROTECTION_INTERNAL;
+ } break;
+ case "system": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_SYSTEM;
+ } break;
+ case "installer": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_INSTALLER;
+ } break;
+ case "verifier": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_VERIFIER;
+ } break;
+ case "preinstalled": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_PREINSTALLED;
+ } break;
+ case "pre23": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_PRE23;
+ } break;
+ case "appop": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_APPOP;
+ } break;
+ case "development": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_DEVELOPMENT;
+ } break;
+ case "privileged": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_PRIVILEGED;
+ } break;
+ case "oem": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_OEM;
+ } break;
+ case "vendorPrivileged": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED;
+ } break;
+ case "setup": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_SETUP;
+ } break;
+ case "textClassifier": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER;
+ } break;
+ case "configurator": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_CONFIGURATOR;
+ } break;
+ case "incidentReportApprover": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_INCIDENT_REPORT_APPROVER;
+ } break;
+ case "appPredictor": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_APP_PREDICTOR;
+ } break;
+ case "instant": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_INSTANT;
+ } break;
+ case "runtime": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY;
+ } break;
+ case "companion": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_COMPANION;
+ } break;
+ case "retailDemo": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO;
+ } break;
+ case "recents": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_RECENTS;
+ } break;
+ case "role": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_ROLE;
+ } break;
+ case "knownSigner": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_KNOWN_SIGNER;
+ } break;
+ case "module" : {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_MODULE;
+ } break;
+ }
+ }
+ return protectionLevel;
+ }
+
+ private static Map<String, PermissionInfo> getPermissionsForPackage(Context context, String pkg)
+ throws NameNotFoundException {
+ PackageInfo packageInfo = context.getPackageManager()
+ .getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
+ Map<String, PermissionInfo> declaredPermissionsMap = new ArrayMap<>();
+
+ for (PermissionInfo declaredPermission : packageInfo.permissions) {
+ declaredPermissionsMap.put(declaredPermission.name, declaredPermission);
+ }
+ return declaredPermissionsMap;
+ }
+
+ private static Date parseDate(String date) {
+ Date patchDate = new Date();
+ try {
+ SimpleDateFormat template = new SimpleDateFormat("yyyy-MM-dd");
+ patchDate = template.parse(date);
+ } catch (ParseException e) {
+ }
+
+ return patchDate;
+ }
+
+ private boolean shouldSkipPermission(String permissionName) {
+ switch (permissionName) {
+ case HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PERMISSION:
+ return parseDate(SECURITY_PATCH).before(HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PATCH_DATE);
+ case MANAGE_COMPANION_DEVICES_PERMISSION:
+ return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE);
+ default:
+ return false;
+ }
+ }
+
+ private class ExpectedPermissionInfo {
+ final @NonNull String name;
+ final @Nullable String group;
+ final @Nullable String backgroundPermission;
+ final int flags;
+ final int protectionLevel;
+
+ private ExpectedPermissionInfo(@NonNull String name, @Nullable String group,
+ @Nullable String backgroundPermission, int flags, int protectionLevel) {
+ this.name = name;
+ this.group = group;
+ this.backgroundPermission = backgroundPermission;
+ this.flags = flags;
+ this.protectionLevel = protectionLevel;
+ }
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PrivappPermissionsTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PrivappPermissionsTest.java
new file mode 100644
index 000000000..f33e8a6e6
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PrivappPermissionsTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.permissionpolicy.cts;
+
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+
+import static com.google.common.collect.Maps.filterValues;
+import static com.google.common.collect.Sets.difference;
+import static com.google.common.collect.Sets.intersection;
+import static com.google.common.collect.Sets.newHashSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.platform.test.annotations.AppModeFull;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.PropertyUtil;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Tests enforcement of signature|privileged permission whitelist:
+ * <ul>
+ * <li>Report what is granted into the CTS log
+ * <li>Ensure all priv permissions are exclusively granted to applications declared in
+ * &lt;privapp-permissions&gt;
+ * </ul>
+ */
+@AppModeFull(reason = "This test test platform properties, not capabilities of an apps")
+@RunWith(AndroidJUnit4.class)
+public class PrivappPermissionsTest {
+
+ private static final boolean DEBUG = false;
+
+ private static final String TAG = "PrivappPermissionsTest";
+
+ private static final String PLATFORM_PACKAGE_NAME = "android";
+
+ @Test
+ public void privappPermissionsMustBeEnforced() {
+ assertEquals("ro.control_privapp_permissions is not set to enforce",
+ "enforce", PropertyUtil.getProperty("ro.control_privapp_permissions"));
+ }
+
+ @Test
+ public void privappPermissionsNeedToBeWhitelisted() throws Exception {
+ Set<String> platformPrivPermissions = new HashSet<>();
+ PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+ PackageInfo platformPackage = pm.getPackageInfo(PLATFORM_PACKAGE_NAME,
+ PackageManager.GET_PERMISSIONS);
+
+ for (PermissionInfo permission : platformPackage.permissions) {
+ int protectionLevel = permission.protectionLevel;
+ if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
+ platformPrivPermissions.add(permission.name);
+ }
+ }
+
+ List<PackageInfo> installedPackages = pm
+ .getInstalledPackages(MATCH_UNINSTALLED_PACKAGES | GET_PERMISSIONS);
+ installedPackages.sort(Comparator.comparing(p -> p.packageName));
+
+ Map<String, Set<String>> packagesGrantedNotInWhitelist = new HashMap<>();
+ Map<String, Set<String>> packagesNotGrantedNotRemovedNotInDenylist = new HashMap<>();
+ for (PackageInfo pkg : installedPackages) {
+ String packageName = pkg.packageName;
+ if (!pkg.applicationInfo.isPrivilegedApp()
+ || PLATFORM_PACKAGE_NAME.equals(packageName)) {
+ continue;
+ }
+
+ PackageInfo factoryPkg = pm
+ .getPackageInfo(packageName, MATCH_FACTORY_ONLY | GET_PERMISSIONS
+ | MATCH_UNINSTALLED_PACKAGES);
+
+ assertNotNull("No system image version found for " + packageName, factoryPkg);
+
+ Set<String> factoryRequestedPrivPermissions;
+ if (factoryPkg.requestedPermissions == null) {
+ factoryRequestedPrivPermissions = Collections.emptySet();
+ } else {
+ factoryRequestedPrivPermissions = intersection(
+ newHashSet(factoryPkg.requestedPermissions), platformPrivPermissions);
+ }
+
+ Map<String, Boolean> requestedPrivPermissions = new ArrayMap<>();
+ if (pkg.requestedPermissions != null) {
+ for (int i = 0; i < pkg.requestedPermissions.length; i++) {
+ String permission = pkg.requestedPermissions[i];
+ if (platformPrivPermissions.contains(permission)) {
+ requestedPrivPermissions.put(permission,
+ (pkg.requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED)
+ != 0);
+ }
+ }
+ }
+
+ // If an app is requesting any privileged permissions, log the details and verify
+ // that granted permissions are whitelisted
+ if (!factoryRequestedPrivPermissions.isEmpty() && !requestedPrivPermissions.isEmpty()) {
+ Set<String> granted = filterValues(requestedPrivPermissions,
+ isGranted -> isGranted).keySet();
+
+ Set<String> factoryNotGranted = difference(factoryRequestedPrivPermissions,
+ granted);
+
+ // priv permissions that the system package requested, but the current package not
+ // anymore
+ Set<String> removed = difference(factoryRequestedPrivPermissions,
+ requestedPrivPermissions.keySet());
+
+ Set<String> whitelist = getPrivAppPermissions(packageName);
+ Set<String> denylist = getPrivAppDenyPermissions(packageName);
+
+ if (DEBUG) {
+ String msg = "Application " + packageName + "\n"
+ + " Factory requested permissions:\n"
+ + getPrintableSet(" ", factoryRequestedPrivPermissions)
+ + " Granted:\n"
+ + getPrintableSet(" ", granted)
+ + " Removed:\n"
+ + getPrintableSet(" ", removed)
+ + " Whitelisted:\n"
+ + getPrintableSet(" ", whitelist)
+ + " Denylisted:\n"
+ + getPrintableSet(" ", denylist)
+ + " Factory not granted:\n"
+ + getPrintableSet(" ", factoryNotGranted);
+
+ for (String line : msg.split("\n")) {
+ Log.i(TAG, line);
+
+ // Prevent log from truncating output
+ Thread.sleep(10);
+ }
+ }
+
+ Set<String> grantedNotInWhitelist = difference(granted, whitelist);
+ Set<String> factoryNotGrantedNotRemovedNotInDenylist = difference(difference(
+ factoryNotGranted, removed), denylist);
+
+ if (!grantedNotInWhitelist.isEmpty()) {
+ packagesGrantedNotInWhitelist.put(packageName, grantedNotInWhitelist);
+ }
+
+ if (!factoryNotGrantedNotRemovedNotInDenylist.isEmpty()) {
+ packagesNotGrantedNotRemovedNotInDenylist.put(packageName,
+ factoryNotGrantedNotRemovedNotInDenylist);
+ }
+ }
+ }
+ StringBuilder message = new StringBuilder();
+ if (!packagesGrantedNotInWhitelist.isEmpty()) {
+ message.append("Not whitelisted permissions are granted: "
+ + packagesGrantedNotInWhitelist.toString());
+ }
+ if (!packagesNotGrantedNotRemovedNotInDenylist.isEmpty()) {
+ if (message.length() != 0) {
+ message.append(", ");
+ }
+ message.append("Requested permissions not granted: "
+ + packagesNotGrantedNotRemovedNotInDenylist.toString());
+ }
+ if (!packagesGrantedNotInWhitelist.isEmpty()
+ || !packagesNotGrantedNotRemovedNotInDenylist.isEmpty()) {
+ fail(message.toString());
+ }
+ }
+
+ private <T> String getPrintableSet(String indendation, Set<T> set) {
+ if (set.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ for (T e : new TreeSet<>(set)) {
+ if (!TextUtils.isEmpty(e.toString().trim())) {
+ sb.append(indendation);
+ sb.append(e);
+ sb.append("\n");
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private Set<String> getPrivAppPermissions(String packageName) throws IOException {
+ String output = SystemUtil.runShellCommand(
+ InstrumentationRegistry.getInstrumentation(),
+ "cmd package get-privapp-permissions " + packageName).trim();
+ if (output.startsWith("{") && output.endsWith("}")) {
+ String[] split = output.substring(1, output.length() - 1).split("\\s*,\\s*");
+ return new LinkedHashSet<>(Arrays.asList(split));
+ }
+ return Collections.emptySet();
+ }
+
+ private Set<String> getPrivAppDenyPermissions(String packageName) throws IOException {
+ String output = SystemUtil.runShellCommand(
+ InstrumentationRegistry.getInstrumentation(),
+ "cmd package get-privapp-deny-permissions " + packageName).trim();
+ if (output.startsWith("{") && output.endsWith("}")) {
+ String[] split = output.substring(1, output.length() - 1).split("\\s*,\\s*");
+ return new LinkedHashSet<>(Arrays.asList(split));
+ }
+ return Collections.emptySet();
+ }
+
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ProtectedBroadcastsTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ProtectedBroadcastsTest.java
new file mode 100644
index 000000000..71c990441
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ProtectedBroadcastsTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import android.content.Intent;
+import android.content.RestrictionsManager;
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+/**
+ * Verify that applications can not send protected broadcasts.
+ */
+public class ProtectedBroadcastsTest extends AndroidTestCase {
+ private static final String BROADCASTS[] = new String[] {
+ Intent.ACTION_SCREEN_OFF,
+ Intent.ACTION_SCREEN_ON,
+ Intent.ACTION_USER_PRESENT,
+ Intent.ACTION_TIME_TICK,
+ Intent.ACTION_TIMEZONE_CHANGED,
+ Intent.ACTION_BOOT_COMPLETED,
+ Intent.ACTION_PACKAGE_INSTALL,
+ Intent.ACTION_PACKAGE_ADDED,
+ Intent.ACTION_PACKAGE_REPLACED,
+ Intent.ACTION_PACKAGE_REMOVED,
+ Intent.ACTION_PACKAGE_CHANGED,
+ Intent.ACTION_PACKAGE_RESTARTED,
+ Intent.ACTION_PACKAGE_DATA_CLEARED,
+ Intent.ACTION_UID_REMOVED,
+ Intent.ACTION_CONFIGURATION_CHANGED,
+ Intent.ACTION_BATTERY_CHANGED,
+ Intent.ACTION_BATTERY_LOW,
+ Intent.ACTION_BATTERY_OKAY,
+ Intent.ACTION_POWER_CONNECTED,
+ Intent.ACTION_POWER_DISCONNECTED,
+ Intent.ACTION_SHUTDOWN,
+ Intent.ACTION_DEVICE_STORAGE_LOW,
+ Intent.ACTION_DEVICE_STORAGE_OK,
+ Intent.ACTION_REBOOT,
+ "com.android.server.WifiManager.action.START_SCAN",
+ "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP",
+ "android.net.wifi.WIFI_STATE_CHANGED",
+ "android.net.wifi.WIFI_AP_STATE_CHANGED",
+ "android.net.wifi.SCAN_RESULTS",
+ "android.net.wifi.RSSI_CHANGED",
+ "android.net.wifi.STATE_CHANGE",
+ "android.net.wifi.LINK_CONFIGURATION_CHANGED",
+ "android.net.wifi.CONFIGURED_NETWORKS_CHANGE",
+ "android.net.wifi.supplicant.CONNECTION_CHANGE",
+ "android.net.wifi.supplicant.STATE_CHANGE",
+ "android.net.wifi.p2p.STATE_CHANGED",
+ "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE",
+ "android.net.wifi.p2p.THIS_DEVICE_CHANGED",
+ "android.net.wifi.p2p.PEERS_CHANGED",
+ "android.net.wifi.p2p.CONNECTION_STATE_CHANGE",
+ "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED",
+ "android.net.conn.TETHER_STATE_CHANGED",
+ "android.net.conn.INET_CONDITION_ACTION",
+ "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED",
+ RestrictionsManager.ACTION_PERMISSION_RESPONSE_RECEIVED,
+ RestrictionsManager.ACTION_REQUEST_PERMISSION
+ };
+
+ private static final String BROADCASTS_TELEPHONY[] = new String[] {
+ Intent.ACTION_NEW_OUTGOING_CALL,
+ "android.intent.action.SERVICE_STATE",
+ "android.intent.action.SIG_STR",
+ "android.intent.action.RADIO_TECHNOLOGY",
+ "android.intent.action.ANY_DATA_STATE",
+ "android.intent.action.ACTION_MDN_STATE_CHANGED",
+ "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED",
+ "android.intent.action.SIM_STATE_CHANGED",
+ "android.telephony.action.SERVICE_PROVIDERS_UPDATED",
+ "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED",
+ "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED",
+ "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS",
+ };
+
+ /**
+ * Verify that protected broadcast actions can't be sent.
+ */
+ public void testSendProtectedBroadcasts() {
+ for (String action : BROADCASTS) {
+ try {
+ Intent intent = new Intent(action);
+ getContext().sendBroadcast(intent);
+ fail("expected security exception broadcasting action: " + action);
+ } catch (SecurityException expected) {
+ assertNotNull("security exception's error message.", expected.getMessage());
+ }
+ }
+ }
+
+ public void testSendProtectedTelephonyBroadcasts() {
+ if (!getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+ for (String action : BROADCASTS_TELEPHONY) {
+ try {
+ Intent intent = new Intent(action);
+ getContext().sendBroadcast(intent);
+ fail("expected security exception broadcasting telephony action: " + action);
+ } catch (SecurityException expected) {
+ assertNotNull("security exception's error message.", expected.getMessage());
+ }
+ }
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedPermissionsTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedPermissionsTest.java
new file mode 100644
index 000000000..5f396c49c
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedPermissionsTest.java
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions andf
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.READ_SMS;
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permission.cts.PermissionUtils.isPermissionGranted;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+
+import android.Manifest;
+import android.Manifest.permission;
+import android.app.AppOpsManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.Session;
+import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SystemUserOnly;
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ThrowingRunnable;
+import com.android.modules.utils.build.SdkLevel;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nullable;
+
+/**
+ * Tests for restricted permission behaviors.
+ */
+public class RestrictedPermissionsTest {
+ private static final String APK_USES_LOCATION_22 =
+ "/data/local/tmp/cts-permissionpolicy/CtsLocationPermissionsUserSdk22.apk";
+
+ private static final String APK_USES_LOCATION_29 =
+ "/data/local/tmp/cts-permissionpolicy/CtsLocationPermissionsUserSdk29.apk";
+
+ private static final String APK_USES_SMS_CALL_LOG_22 =
+ "/data/local/tmp/cts-permissionpolicy/CtsSMSCallLogPermissionsUserSdk22.apk";
+
+ private static final String APK_NAME_USES_SMS_CALL_LOG_29 =
+ "CtsSMSCallLogPermissionsUserSdk29.apk";
+
+ private static final String APK_USES_SMS_CALL_LOG_29 =
+ "/data/local/tmp/cts-permissionpolicy/CtsSMSCallLogPermissionsUserSdk29.apk";
+
+ private static final String APK_USES_STORAGE_DEFAULT_29 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserDefaultSdk29.apk";
+
+ private static final String PKG = "android.permissionpolicy.cts.restrictedpermissionuser";
+
+ private static final String APK_USES_SMS_RESTRICTED_SHARED_UID =
+ "/data/local/tmp/cts-permissionpolicy/CtsSMSRestrictedWithSharedUid.apk";
+
+ private static final String PKG_USES_SMS_RESTRICTED_SHARED_UID =
+ "android.permissionpolicy.cts.smswithshareduid.restricted";
+
+ private static final String APK_USES_SMS_NOT_RESTRICTED_SHARED_UID =
+ "/data/local/tmp/cts-permissionpolicy/CtsSMSNotRestrictedWithSharedUid.apk";
+
+ private static final String PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID =
+ "android.permissionpolicy.cts.smswithshareduid.notrestricted";
+
+ private static final long UI_TIMEOUT = 5000L;
+
+ private static @NonNull BroadcastReceiver sCommandReceiver;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ sCommandReceiver = new CommandBroadcastReceiver();
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction("installRestrictedPermissionUserApp");
+ intentFilter.addAction("uninstallApp");
+ getContext().registerReceiver(sCommandReceiver, intentFilter,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ getContext().unregisterReceiver(sCommandReceiver);
+ }
+
+ @Test
+ @AppModeFull
+ public void testDefaultAllRestrictedPermissionsWhitelistedAtInstall29() throws Exception {
+ // Install with no changes to whitelisted permissions, not attempting to grant.
+ installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
+ Collections.EMPTY_SET /*grantedPermissions*/);
+
+ // All restricted permission should be whitelisted.
+ assertAllRestrictedPermissionWhitelisted();
+
+ // No restricted permission should be granted.
+ assertNoRestrictedPermissionGranted();
+ }
+
+ @Test
+ @AppModeFull
+ public void testSomeRestrictedPermissionsWhitelistedAtInstall29() throws Exception {
+ // Whitelist only these permissions.
+ final Set<String> whitelistedPermissions = new ArraySet<>(2);
+ whitelistedPermissions.add(Manifest.permission.SEND_SMS);
+ whitelistedPermissions.add(Manifest.permission.READ_CALL_LOG);
+
+ // Install with some whitelisted permissions, not attempting to grant.
+ installRestrictedPermissionUserApp(whitelistedPermissions,
+ Collections.EMPTY_SET /*grantedPermissions*/);
+
+ // Some restricted permission should be whitelisted.
+ assertRestrictedPermissionWhitelisted(whitelistedPermissions);
+
+ // No restricted permission should be granted.
+ assertNoRestrictedPermissionGranted();
+ }
+
+ @Test
+ @AppModeFull
+ public void testNoneRestrictedPermissionWhitelistedAtInstall29() throws Exception {
+ // Install with all whitelisted permissions, not attempting to grant.
+ installRestrictedPermissionUserApp(Collections.emptySet(),
+ Collections.EMPTY_SET /*grantedPermissions*/);
+
+ // No restricted permission should be whitelisted.
+ assertNoRestrictedPermissionWhitelisted();
+
+ // No restricted permission should be granted.
+ assertNoRestrictedPermissionGranted();
+ }
+
+ @Test
+ @AppModeFull
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_SMS user restriction")
+ public void testDefaultAllRestrictedPermissionsWhitelistedAtInstall22() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_SMS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ String bypassLowTargetSdkFlag = "";
+ if (SdkLevel.isAtLeastU()) {
+ bypassLowTargetSdkFlag = " --bypass-low-target-sdk-block";
+ }
+
+ // Install with no changes to whitelisted permissions
+ runShellCommandOrThrow("pm install" + bypassLowTargetSdkFlag
+ + " -g --force-queryable " + APK_USES_SMS_CALL_LOG_22);
+
+ // All restricted permission should be whitelisted.
+ assertAllRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void testSomeRestrictedPermissionsWhitelistedAtInstall22() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ // Whitelist only these permissions.
+ final Set<String> whitelistedPermissions = new ArraySet<>(2);
+ whitelistedPermissions.add(Manifest.permission.SEND_SMS);
+ whitelistedPermissions.add(Manifest.permission.READ_CALL_LOG);
+
+ // Install with some whitelisted permissions
+ installApp(APK_USES_SMS_CALL_LOG_22, whitelistedPermissions, null /*grantedPermissions*/);
+
+ // Some restricted permission should be whitelisted.
+ assertRestrictedPermissionWhitelisted(whitelistedPermissions);
+ }
+
+ @Test
+ @AppModeFull
+ public void testNoneRestrictedPermissionWhitelistedAtInstall22() throws Exception {
+ // Install with all whitelisted permissions
+ installApp(APK_USES_SMS_CALL_LOG_22, Collections.emptySet(),
+ null /*grantedPermissions*/);
+
+ // No restricted permission should be whitelisted.
+ assertNoRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ public void testLocationBackgroundPermissionWhitelistedAtInstall29() throws Exception {
+ installApp(APK_USES_LOCATION_29, null, new ArraySet<>(Arrays.asList(ACCESS_FINE_LOCATION,
+ ACCESS_BACKGROUND_LOCATION)));
+ assertAllRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ public void testLocationBackgroundPermissionNotWhitelistedAtInstall29() throws Exception {
+ installApp(APK_USES_LOCATION_29, Collections.emptySet(),
+ Collections.singleton(ACCESS_FINE_LOCATION));
+ assertNoRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ public void testLocationBackgroundPermissionWhitelistedAtInstall22() throws Exception {
+ installApp(APK_USES_LOCATION_22, null, new ArraySet<>(Arrays.asList(ACCESS_FINE_LOCATION,
+ ACCESS_BACKGROUND_LOCATION)));
+ assertAllRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ public void testLocationBackgroundPermissionNotWhitelistedAtInstall22() throws Exception {
+ installApp(APK_USES_LOCATION_22, Collections.emptySet(),
+ Collections.singleton(ACCESS_FINE_LOCATION));
+ assertNoRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void testSomeRestrictedPermissionsGrantedAtInstall() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ // Grant only these permissions.
+ final Set<String> grantedPermissions = new ArraySet<>(1);
+ grantedPermissions.add(Manifest.permission.SEND_SMS);
+ grantedPermissions.add(Manifest.permission.READ_CALL_LOG);
+
+ // Install with no whitelisted permissions attempting to grant.
+ installRestrictedPermissionUserApp(null /*whitelistedPermissions*/, grantedPermissions);
+
+ // All restricted permission should be whitelisted.
+ assertAllRestrictedPermissionWhitelisted();
+
+ // Some restricted permission should be granted.
+ assertRestrictedPermissionGranted(grantedPermissions);
+ }
+
+ @Test
+ @AppModeFull
+ public void testCanGrantSoftRestrictedNotWhitelistedPermissions() throws Exception {
+ try {
+ final Set<String> grantedPermissions = new ArraySet<>();
+ grantedPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ grantedPermissions.add(permission.WRITE_EXTERNAL_STORAGE);
+
+ installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet(), grantedPermissions);
+
+ assertRestrictedPermissionGranted(grantedPermissions);
+ } finally {
+ uninstallApp();
+ }
+ }
+
+ @Test
+ @AppModeFull
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_SMS user restriction")
+ public void testAllRestrictedPermissionsGrantedAtInstall() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_SMS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ // Install with whitelisted permissions attempting to grant.
+ installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
+ null);
+
+ // All restricted permission should be whitelisted.
+ assertAllRestrictedPermissionWhitelisted();
+
+ // Some restricted permission should be granted.
+ assertAllRestrictedPermissionGranted();
+ }
+
+ @Test
+ @AppModeFull
+ public void testWhitelistAccessControl() throws Exception {
+ // Install with no whitelisted permissions not attempting to grant.
+ installRestrictedPermissionUserApp(Collections.emptySet(), null);
+
+ assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
+
+ assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE);
+
+ assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ }
+
+ @Test
+ @AppModeFull
+ public void onSideLoadRestrictedPermissionsWhitelistingDefault() throws Exception {
+ installRestrictedPermissionUserApp(new SessionParams(SessionParams.MODE_FULL_INSTALL));
+
+ // All restricted permissions whitelisted on side-load by default
+ assertAllRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ public void onSideLoadAllRestrictedPermissionsWhitelisted() throws Exception {
+ SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
+ params.setWhitelistedRestrictedPermissions(SessionParams.RESTRICTED_PERMISSIONS_ALL);
+
+ installRestrictedPermissionUserApp(params);
+
+ assertAllRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ @FlakyTest
+ public void onSideLoadWhitelistSomePermissions() throws Exception {
+ Set<String> whitelistedPermissions = new ArraySet<>();
+ whitelistedPermissions.add(Manifest.permission.SEND_SMS);
+ whitelistedPermissions.add(Manifest.permission.READ_CALL_LOG);
+
+ SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
+ params.setWhitelistedRestrictedPermissions(whitelistedPermissions);
+
+ installRestrictedPermissionUserApp(params);
+
+ assertRestrictedPermissionWhitelisted(whitelistedPermissions);
+ }
+
+ @Test
+ @AppModeFull
+ @FlakyTest
+ public void onSideLoadWhitelistNoPermissions() throws Exception {
+ SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
+ params.setWhitelistedRestrictedPermissions(Collections.emptySet());
+
+ installRestrictedPermissionUserApp(params);
+
+ assertNoRestrictedPermissionWhitelisted();
+ }
+
+ @Test
+ @AppModeFull
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_SMS user restriction")
+ public void shareUidBetweenRestrictedAndNotRestrictedApp() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_SMS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ runShellCommandOrThrow(
+ "pm install -g --force-queryable --restrict-permissions "
+ + APK_USES_SMS_RESTRICTED_SHARED_UID);
+ runShellCommandOrThrow("pm install -g --force-queryable "
+ + APK_USES_SMS_NOT_RESTRICTED_SHARED_UID);
+
+ eventually(
+ () -> assertThat(isGranted(PKG_USES_SMS_RESTRICTED_SHARED_UID, READ_SMS)).isTrue());
+ // The apps share a UID, hence the whitelisting is shared too
+ assertThat(isGranted(PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID, READ_SMS)).isTrue();
+ }
+
+ private static void installRestrictedPermissionUserApp(@NonNull SessionParams params)
+ throws Exception {
+ final CountDownLatch installLatch = new CountDownLatch(1);
+
+ // Create an install result receiver.
+ final BroadcastReceiver installReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE_INVALID)
+ == PackageInstaller.STATUS_SUCCESS) {
+ installLatch.countDown();
+ }
+ }
+ };
+
+ // Register the result receiver.
+ final String action = "android.permissionpolicy.cts.ACTION_INSTALL_COMMIT";
+ final IntentFilter intentFilter = new IntentFilter(action);
+ getContext().registerReceiver(installReceiver, intentFilter,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
+
+ try {
+ // Create a session.
+ final PackageInstaller packageInstaller = getContext()
+ .getPackageManager().getPackageInstaller();
+ final int sessionId = packageInstaller.createSession(params);
+ final Session session = packageInstaller.openSession(sessionId);
+
+ // Write the apk.
+ try (
+ InputStream in = new BufferedInputStream(new FileInputStream(
+ new File(APK_USES_SMS_CALL_LOG_29)));
+ OutputStream out = session.openWrite(
+ APK_NAME_USES_SMS_CALL_LOG_29, 0, -1);
+ ) {
+ final byte[] buf = new byte[8192];
+ int size;
+ while ((size = in.read(buf)) != -1) {
+ out.write(buf, 0, size);
+ }
+ }
+
+ final Intent intent = new Intent(action);
+ intent.setPackage("android.permissionpolicy.cts");
+ final IntentSender intentSender = PendingIntent.getBroadcast(getContext(),
+ 1, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE)
+ .getIntentSender();
+
+ // Commit as shell to avoid confirm UI
+ runWithShellPermissionIdentity(() -> {
+ session.commit(intentSender);
+ installLatch.await(UI_TIMEOUT, TimeUnit.MILLISECONDS);
+ });
+ } finally {
+ getContext().unregisterReceiver(installReceiver);
+ }
+ }
+
+ private void assertWeCannotReadOrWriteWhileShellCanReadAndWrite(int whitelist)
+ throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+ try {
+ packageManager.getWhitelistedRestrictedPermissions(PKG, whitelist);
+ fail();
+ } catch (SecurityException expected) {
+ /*ignore*/
+ }
+ try {
+ packageManager.addWhitelistedRestrictedPermission(PKG,
+ permission.SEND_SMS, whitelist);
+ fail();
+ } catch (SecurityException expected) {
+ /*ignore*/
+ }
+ runWithShellPermissionIdentity(() -> {
+ packageManager.addWhitelistedRestrictedPermission(PKG,
+ permission.SEND_SMS, whitelist);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ whitelist)).contains(permission.SEND_SMS);
+ packageManager.removeWhitelistedRestrictedPermission(PKG,
+ permission.SEND_SMS, whitelist);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ whitelist)).doesNotContain(permission.SEND_SMS);
+ });
+ }
+
+ private @NonNull Set<String> getPermissionsOfAppWithAnyOfFlags(int flags) throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+ final Set<String> restrictedPermissions = new ArraySet<>();
+ for (String permission : getRequestedPermissionsOfApp()) {
+ PermissionInfo permInfo = packageManager.getPermissionInfo(permission, 0);
+
+ if ((permInfo.flags & flags) != 0) {
+ restrictedPermissions.add(permission);
+ }
+ }
+ return restrictedPermissions;
+ }
+
+ private @NonNull Set<String> getRestrictedPermissionsOfApp() throws Exception {
+ return getPermissionsOfAppWithAnyOfFlags(
+ PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED);
+ }
+
+ private @NonNull String[] getRequestedPermissionsOfApp() throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+ final PackageInfo packageInfo = packageManager.getPackageInfo(PKG,
+ PackageManager.GET_PERMISSIONS);
+ return packageInfo.requestedPermissions;
+ }
+
+ private void assertAllRestrictedPermissionWhitelisted() throws Exception {
+ assertRestrictedPermissionWhitelisted(getRestrictedPermissionsOfApp());
+ }
+
+ private void assertNoRestrictedPermissionWhitelisted() throws Exception {
+ assertRestrictedPermissionWhitelisted(
+ Collections.EMPTY_SET /*expectedWhitelistedPermissions*/);
+ }
+
+ /**
+ * Assert that the passed in restrictions are whitelisted and that their app-op is set
+ * correctly.
+ *
+ * @param expectedWhitelistedPermissions The expected white listed permissions
+ */
+ private void assertRestrictedPermissionWhitelisted(
+ @NonNull Set<String> expectedWhitelistedPermissions) throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+ eventually(() -> runWithShellPermissionIdentity(() -> {
+ final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+ final PackageInfo packageInfo = packageManager.getPackageInfo(PKG,
+ PackageManager.GET_PERMISSIONS);
+
+ final Set<String> whitelistedPermissions = packageManager
+ .getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
+ | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE);
+
+ assertThat(whitelistedPermissions).isNotNull();
+ assertWithMessage("Whitelisted permissions").that(whitelistedPermissions)
+ .containsExactlyElementsIn(expectedWhitelistedPermissions);
+
+ // Also assert that apps ops are properly set
+ for (String permission : getRestrictedPermissionsOfApp()) {
+ String op = AppOpsManager.permissionToOp(permission);
+ ArraySet<Integer> possibleModes = new ArraySet<>();
+
+ if (permission.equals(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
+ op = AppOpsManager.OPSTR_FINE_LOCATION;
+
+ // If permission is denied app-op might be allowed/fg or ignored. It does
+ // not matter. If permission is granted, it has to be allowed/fg.
+ if (isPermissionGranted(PKG, Manifest.permission.ACCESS_FINE_LOCATION)) {
+ if (expectedWhitelistedPermissions.contains(permission)
+ && isPermissionGranted(PKG, permission)) {
+ possibleModes.add(AppOpsManager.MODE_ALLOWED);
+ } else {
+ possibleModes.add(AppOpsManager.MODE_FOREGROUND);
+ }
+ } else {
+ possibleModes.add(AppOpsManager.MODE_IGNORED);
+ possibleModes.add(AppOpsManager.MODE_ALLOWED);
+ possibleModes.add(AppOpsManager.MODE_FOREGROUND);
+ }
+ } else {
+ if (expectedWhitelistedPermissions.contains(permission)) {
+ // If permission is denied app-op might be allowed or ignored. It does not
+ // matter. If permission is granted, it has to be allowed.
+ possibleModes.add(AppOpsManager.MODE_ALLOWED);
+ if (!isPermissionGranted(PKG, permission)) {
+ possibleModes.add(AppOpsManager.MODE_IGNORED);
+ }
+ } else {
+ possibleModes.add(AppOpsManager.MODE_IGNORED);
+ }
+ }
+
+ assertWithMessage(op).that(appOpsManager.unsafeCheckOpRawNoThrow(op,
+ packageInfo.applicationInfo.uid, PKG)).isIn(possibleModes);
+ }
+ }));
+ }
+
+ private void assertAllRestrictedPermissionGranted() throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+ final PackageInfo packageInfo = packageManager.getPackageInfo(
+ PKG, PackageManager.GET_PERMISSIONS);
+ if (packageInfo.requestedPermissions != null) {
+ final int permissionCount = packageInfo.requestedPermissions.length;
+ for (int i = 0; i < permissionCount; i++) {
+ final String permission = packageInfo.requestedPermissions[i];
+ final PermissionInfo permissionInfo = packageManager.getPermissionInfo(
+ permission, 0);
+ if ((permissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0) {
+ assertThat((packageInfo.requestedPermissionsFlags[i]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED)).isNotEqualTo(0);
+ }
+ }
+ }
+ }
+
+ private void assertNoRestrictedPermissionGranted() throws Exception {
+ assertRestrictedPermissionGranted(Collections.EMPTY_SET);
+ }
+
+ private void assertRestrictedPermissionGranted(@NonNull Set<String> expectedGrantedPermissions)
+ throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+ final PackageInfo packageInfo = packageManager.getPackageInfo(
+ PKG, PackageManager.GET_PERMISSIONS);
+ if (packageInfo.requestedPermissions != null) {
+ final int permissionCount = packageInfo.requestedPermissions.length;
+ for (int i = 0; i < permissionCount; i++) {
+ final String permission = packageInfo.requestedPermissions[i];
+ final PermissionInfo permissionInfo = packageManager.getPermissionInfo(
+ permission, 0);
+ if ((permissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
+ || (permissionInfo.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
+ if (expectedGrantedPermissions.contains(permission)) {
+ assertThat((packageInfo.requestedPermissionsFlags[i]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED)).isNotEqualTo(0);
+ } else {
+ assertThat((packageInfo.requestedPermissionsFlags[i]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED)).isEqualTo(0);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Install {@link #APK_USES_SMS_CALL_LOG_29}.
+ *
+ * @param whitelistedPermissions The permission to be whitelisted. {@code null} == all
+ * @param grantedPermissions The permission to be granted. {@code null} == all
+ */
+ private void installRestrictedPermissionUserApp(@Nullable Set<String> whitelistedPermissions,
+ @Nullable Set<String> grantedPermissions) throws Exception {
+ installApp(APK_USES_SMS_CALL_LOG_29, whitelistedPermissions, grantedPermissions);
+ }
+
+ /**
+ * Install app and grant all permission.
+ *
+ * @param app The app to be installed
+ * @param whitelistedPermissions The permission to be whitelisted. {@code null} == all
+ */
+ private void installApp(@NonNull String app, @Nullable Set<String> whitelistedPermissions)
+ throws Exception {
+ installApp(app, whitelistedPermissions, null /*grantedPermissions*/);
+ }
+
+ /**
+ * Install an app.
+ *
+ * @param app The app to be installed
+ * @param whitelistedPermissions The permission to be whitelisted. {@code null} == all
+ * @param grantedPermissions The permission to be granted. {@code null} == all
+ */
+ private void installApp(@NonNull String app, @Nullable Set<String> whitelistedPermissions,
+ @Nullable Set<String> grantedPermissions) throws Exception {
+ String bypassLowTargetSdkFlag = "";
+ if (SdkLevel.isAtLeastU()) {
+ bypassLowTargetSdkFlag = " --bypass-low-target-sdk-block";
+ }
+
+ // Install the app and whitelist/grant all permission if requested.
+ String installResult = runShellCommandOrThrow("pm install -r --force-queryable"
+ + bypassLowTargetSdkFlag + " --restrict-permissions " + app);
+ assertThat(installResult.trim()).isEqualTo("Success");
+
+ final Set<String> adjustedWhitelistedPermissions;
+ if (whitelistedPermissions == null) {
+ adjustedWhitelistedPermissions = getRestrictedPermissionsOfApp();
+ } else {
+ adjustedWhitelistedPermissions = whitelistedPermissions;
+ }
+
+ final Set<String> adjustedGrantedPermissions;
+ if (grantedPermissions == null) {
+ adjustedGrantedPermissions = getRestrictedPermissionsOfApp();
+ } else {
+ adjustedGrantedPermissions = grantedPermissions;
+ }
+
+ // Whitelist subset of permissions if requested
+ runWithShellPermissionIdentity(() -> {
+ final PackageManager packageManager = getContext().getPackageManager();
+ for (String permission : adjustedWhitelistedPermissions) {
+ packageManager.addWhitelistedRestrictedPermission(PKG, permission,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ }
+ });
+
+ // Grant subset of permissions if requested
+ runWithShellPermissionIdentity(() -> {
+ final PackageManager packageManager = getContext().getPackageManager();
+ for (String permission : adjustedGrantedPermissions) {
+ packageManager.grantRuntimePermission(PKG, permission,
+ getContext().getUser());
+ packageManager.updatePermissionFlags(permission, PKG,
+ PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0, getContext().getUser());
+ }
+ });
+
+ // Mark all permissions as reviewed as for pre-22 apps the restriction state might not be
+ // applied until reviewed
+ runWithShellPermissionIdentity(() -> {
+ final PackageManager packageManager = getContext().getPackageManager();
+ for (String permission : getRequestedPermissionsOfApp()) {
+ packageManager.updatePermissionFlags(permission, PKG,
+ PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0,
+ getContext().getUser());
+ }
+ });
+ }
+
+ @After
+ public void uninstallApp() {
+ runShellCommand("pm uninstall " + PKG);
+ runShellCommand("pm uninstall " + PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID);
+ runShellCommand("pm uninstall " + PKG_USES_SMS_RESTRICTED_SHARED_UID);
+ }
+
+ private static @NonNull Context getContext() {
+ return InstrumentationRegistry.getInstrumentation().getContext();
+ }
+
+ private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable command)
+ throws Exception {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity();
+ try {
+ command.run();
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedStoragePermissionSharedUidTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedStoragePermissionSharedUidTest.java
new file mode 100644
index 000000000..d6ee7a66b
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedStoragePermissionSharedUidTest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE;
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permissionpolicy.cts.RestrictedStoragePermissionSharedUidTest.StorageState.DENIED;
+import static android.permissionpolicy.cts.RestrictedStoragePermissionSharedUidTest.StorageState.ISOLATED;
+import static android.permissionpolicy.cts.RestrictedStoragePermissionSharedUidTest.StorageState.NON_ISOLATED;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static java.lang.Integer.min;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.ArrayList;
+
+@AppModeFull(reason = "Instant apps cannot access other app's properties")
+@RunWith(Parameterized.class)
+public class RestrictedStoragePermissionSharedUidTest {
+ private static final String LOG_TAG =
+ RestrictedStoragePermissionSharedUidTest.class.getSimpleName();
+
+ public enum StorageState {
+ /** The app has non-isolated storage */
+ NON_ISOLATED,
+
+ /** The app has isolated storage */
+ ISOLATED,
+
+ /** The read-external-storage permission cannot be granted */
+ DENIED
+ }
+
+ /**
+ * An app that is tested
+ */
+ private static class TestApp {
+ private static @NonNull Context sContext =
+ InstrumentationRegistry.getInstrumentation().getContext();
+ private static @NonNull AppOpsManager sAppOpsManager =
+ sContext.getSystemService(AppOpsManager.class);
+ private static @NonNull PackageManager sPackageManager = sContext.getPackageManager();
+
+ private final String mApk;
+ private final String mPkg;
+
+ public final boolean isRestricted;
+ public final boolean hasRequestedLegacyExternalStorage;
+
+ TestApp(@NonNull String apk, @NonNull String pkg, boolean isRestricted,
+ @NonNull boolean hasRequestedLegacyExternalStorage) {
+ mApk = apk;
+ mPkg = pkg;
+
+ this.isRestricted = isRestricted;
+ this.hasRequestedLegacyExternalStorage = hasRequestedLegacyExternalStorage;
+ }
+
+ /**
+ * Assert that the read-external-storage permission was granted or not granted.
+ *
+ * @param expectGranted {@code true} if the permission is expected to be granted
+ */
+ void assertStoragePermGranted(boolean expectGranted) {
+ eventually(() -> assertWithMessage(this + " read storage granted").that(
+ isGranted(mPkg, READ_EXTERNAL_STORAGE)).isEqualTo(expectGranted));
+ }
+
+ /**
+ * Assert that the app has non-isolated storage
+ *
+ * @param expectGranted {@code true} if the app is expected to have non-isolated storage
+ */
+ void assertHasNotIsolatedStorage(boolean expectHasNotIsolatedStorage) {
+ eventually(() -> runWithShellPermissionIdentity(() -> {
+ int uid = sContext.getPackageManager().getPackageUid(mPkg, 0);
+ if (expectHasNotIsolatedStorage) {
+ assertWithMessage(this + " legacy storage mode").that(
+ sAppOpsManager.unsafeCheckOpRawNoThrow(OPSTR_LEGACY_STORAGE, uid,
+ mPkg)).isEqualTo(MODE_ALLOWED);
+ } else {
+ assertWithMessage(this + " legacy storage mode").that(
+ sAppOpsManager.unsafeCheckOpRawNoThrow(OPSTR_LEGACY_STORAGE, uid,
+ mPkg)).isNotEqualTo(MODE_ALLOWED);
+ }
+ }));
+ }
+
+ int getTargetSDK() throws Exception {
+ return sPackageManager.getApplicationInfo(mPkg, 0).targetSdkVersion;
+ }
+
+ void install() {
+ if (isRestricted) {
+ runShellCommandOrThrow(
+ "pm install -g --force-queryable --restrict-permissions " + mApk);
+ } else {
+ runShellCommandOrThrow("pm install -g --force-queryable " + mApk);
+ }
+ }
+
+ void uninstall() {
+ runShellCommand("pm uninstall " + mPkg);
+ }
+
+ @Override
+ public String toString() {
+ return mPkg.substring(PKG_PREFIX.length());
+ }
+ }
+
+ /**
+ * Placeholder for "no app". The properties are chosen that when combined with another app, the
+ * other app always decides the resulting property,
+ */
+ private static class NoApp extends TestApp {
+ NoApp() {
+ super("", PKG_PREFIX + "(none)", true, false);
+ }
+
+ void assertStoragePermGranted(boolean ignored) {
+ // empty
+ }
+
+ void assertHasNotIsolatedStorage(boolean ignored) {
+ // empty
+ }
+
+ @Override
+ int getTargetSDK() {
+ return 10000;
+ }
+
+ @Override
+ public void install() {
+ // empty
+ }
+
+ @Override
+ public void uninstall() {
+ // empty
+ }
+ }
+
+ private static final String APK_PATH = "/data/local/tmp/cts-permissionpolicy/";
+ private static final String PKG_PREFIX = "android.permissionpolicy.cts.legacystoragewithshareduid.";
+
+ private static final TestApp[] TEST_APPS = new TestApp[]{
+ new TestApp(APK_PATH + "CtsLegacyStorageNotIsolatedWithSharedUid.apk",
+ PKG_PREFIX + "notisolated", false, true),
+ new TestApp(APK_PATH + "CtsLegacyStorageIsolatedWithSharedUid.apk",
+ PKG_PREFIX + "isolated", false, false),
+ new TestApp(APK_PATH + "CtsLegacyStorageRestrictedWithSharedUid.apk",
+ PKG_PREFIX + "restricted", true, false),
+ new TestApp(APK_PATH + "CtsLegacyStorageRestrictedSdk28WithSharedUid.apk",
+ PKG_PREFIX + "restrictedsdk28", true, true),
+ new NoApp()};
+
+ /**
+ * First app to be tested. This is the first in an entry created by {@link
+ * #getTestAppCombinations}
+ */
+ @Parameter(0)
+ public @NonNull TestApp app1;
+
+ /**
+ * Second app to be tested. This is the second in an entry created by {@link
+ * #getTestAppCombinations}
+ */
+ @Parameter(1)
+ public @NonNull TestApp app2;
+
+ /**
+ * Run this test for all combination of two tests-apps out of {@link #TEST_APPS}. This includes
+ * the {@link NoApp}, i.e. we also test a single test-app by itself.
+ *
+ * @return All combinations of two test-apps
+ */
+ @Parameters(name = "{0} and {1}")
+ public static Iterable<Object[]> getTestAppCombinations() {
+ ArrayList<Object[]> parameters = new ArrayList<>();
+
+ for (int firstApp = 0; firstApp < TEST_APPS.length; firstApp++) {
+ for (int secondApp = firstApp + 1; secondApp < TEST_APPS.length; secondApp++) {
+ parameters.add(new Object[]{TEST_APPS[firstApp], TEST_APPS[secondApp]});
+ }
+ }
+
+ return parameters;
+ }
+
+ @Test
+ public void checkExceptedStorageStateForAppsSharingUid() throws Exception {
+ app1.install();
+ app2.install();
+
+ int targetSDK = min(app1.getTargetSDK(), app2.getTargetSDK());
+ boolean isRestricted = app1.isRestricted && app2.isRestricted;
+ boolean hasRequestedLegacyExternalStorage =
+ app1.hasRequestedLegacyExternalStorage || app2.hasRequestedLegacyExternalStorage;
+
+ StorageState expectedState;
+ if (isRestricted) {
+ if (targetSDK < Build.VERSION_CODES.Q) {
+ expectedState = DENIED;
+ } else {
+ expectedState = ISOLATED;
+ }
+ } else if (hasRequestedLegacyExternalStorage && targetSDK <= Build.VERSION_CODES.Q) {
+ expectedState = NON_ISOLATED;
+ } else {
+ expectedState = ISOLATED;
+ }
+
+ Log.i(LOG_TAG, "Expected state=" + expectedState);
+
+ app1.assertStoragePermGranted(expectedState != DENIED);
+ app2.assertStoragePermGranted(expectedState != DENIED);
+
+ if (expectedState != DENIED) {
+ app1.assertHasNotIsolatedStorage(expectedState == NON_ISOLATED);
+ app2.assertHasNotIsolatedStorage(expectedState == NON_ISOLATED);
+ }
+ }
+
+ @After
+ public void uninstallAllTestPackages() {
+ app1.uninstall();
+ app2.uninstall();
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedStoragePermissionTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedStoragePermissionTest.java
new file mode 100644
index 000000000..6a3b0711d
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RestrictedStoragePermissionTest.java
@@ -0,0 +1,755 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts;
+
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permission.cts.PermissionUtils.isPermissionGranted;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.Manifest;
+import android.Manifest.permission;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.platform.test.annotations.AppModeFull;
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ThrowingRunnable;
+import com.android.modules.utils.build.SdkLevel;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/** Tests for restricted storage-related permissions. */
+public class RestrictedStoragePermissionTest {
+ private static final String APK_USES_STORAGE_DEFAULT_22 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserDefaultSdk22.apk";
+
+ private static final String APK_USES_STORAGE_DEFAULT_28 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserDefaultSdk28.apk";
+
+ private static final String APK_USES_STORAGE_DEFAULT_29 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserDefaultSdk29.apk";
+
+ private static final String APK_USES_STORAGE_OPT_IN_22 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserOptInSdk22.apk";
+
+ private static final String APK_USES_STORAGE_OPT_IN_28 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserOptInSdk28.apk";
+
+ private static final String APK_USES_STORAGE_OPT_OUT_29 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserOptOutSdk29.apk";
+
+ private static final String APK_USES_STORAGE_OPT_OUT_30 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsUserOptOutSdk30.apk";
+
+ private static final String APK_USES_STORAGE_PRESERVED_OPT_OUT_30 =
+ "/data/local/tmp/cts-permissionpolicy/CtsStoragePermissionsPreservedUserOptOutSdk30.apk";
+
+ private static final String PKG = "android.permissionpolicy.cts.restrictedpermissionuser";
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk22DefaultWhitelistedHasFullAccess() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_22, null /*whitelistedPermissions*/);
+
+ // Check expected storage mode
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk22OptInWhitelistedHasIsolatedAccess() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_IN_22, null /*whitelistedPermissions*/);
+
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk28DefaultWhitelistedHasFullAccess() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
+
+ // Check expected storage mode
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk28OptInWhitelistedHasIsolatedAccess() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
+
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29DefaultWhitelistedHasIsolatedAccess() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet());
+
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29DefaultNotWhitelistedHasIsolatedAccess() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_29, null /*whitelistedPermissions*/);
+
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29OptOutWhitelistedHasFullAccess() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null /*whitelistedPermissions*/);
+
+ // Check expected storage mode
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29OptOutNotWhitelistedHasIsolatedAccess() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet());
+
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29CanOptOutViaUpdate() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29CanOptOutViaDowngradeTo28() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
+
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk30_cannotOptOut() throws Exception {
+ // Apps that target R and above cannot opt out of isolated storage.
+ installApp(APK_USES_STORAGE_OPT_OUT_30, null);
+
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk28CanRemoveOptInViaUpdate() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
+
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk28CanRemoveOptInByOptingOut() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk28DoesNotLoseAccessWhenOptingIn() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
+ assertHasFullStorageAccess();
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk28DoesNotLoseAccessViaUpdate() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
+ assertHasFullStorageAccess();
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29DoesNotLoseAccessViaUpdate() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ assertHasFullStorageAccess();
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29DoesNotLoseAccessWhenOptingIn() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ assertHasFullStorageAccess();
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk29LosesAccessViaUpdateToTargetSdk30() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ assertHasFullStorageAccess();
+
+ installApp(APK_USES_STORAGE_OPT_OUT_30, null); // opt-out is a no-op on 30
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testTargetingSdk28LosesAccessViaUpdateToTargetSdk30() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
+ assertHasFullStorageAccess();
+
+ installApp(APK_USES_STORAGE_OPT_OUT_30, null); // opt-out is a no-op on 30
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testCannotControlStorageWhitelistPostInstall1() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
+
+ // Check expected state of restricted permissions.
+ assertCannotUnWhitelistStorage();
+ }
+
+ @Test
+ @AppModeFull
+ public void testCannotControlStorageWhitelistPostInstall2() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
+
+ // Check expected state of restricted permissions.
+ assertCannotWhitelistStorage();
+ }
+
+ @Test
+ @AppModeFull
+ public void cannotGrantStorageTargetingSdk22NotWhitelisted() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_22, Collections.emptySet());
+
+ eventually(() -> {
+ // Could not grant permission+app-op as targetSDK<29 and not whitelisted
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
+
+ // Permissions are always granted for pre-23 apps
+ assertThat(isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE))
+ .isTrue();
+ });
+ }
+
+ @Test
+ @AppModeFull
+ public void cannotGrantStorageTargetingSdk22OptInNotWhitelisted() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_IN_22, Collections.emptySet());
+
+ eventually(() -> {
+ // Could not grant permission as targetSDK<29 and not whitelisted
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
+
+ // Permissions are always granted for pre-23 apps
+ assertThat(isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE))
+ .isTrue();
+ });
+ }
+
+ @Test
+ @AppModeFull
+ public void canGrantStorageTargetingSdk22Whitelisted() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_22, null);
+
+ // Could grant permission
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+ }
+
+ @Test
+ @AppModeFull
+ public void canGrantStorageTargetingSdk22OptInWhitelisted() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_IN_22, null);
+
+ // Could grant permission
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+ }
+
+ @Test
+ @AppModeFull
+ public void cannotGrantStorageTargetingSdk28NotWhitelisted() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
+
+ // Could not grant permission as targetSDK<29 and not whitelisted
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse());
+ }
+
+ @Test
+ @AppModeFull
+ public void cannotGrantStorageTargetingSdk28OptInNotWhitelisted() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_IN_28, Collections.emptySet());
+
+ // Could not grant permission as targetSDK<29 and not whitelisted
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse());
+ }
+
+ @Test
+ @AppModeFull
+ public void canGrantStorageTargetingSdk28Whitelisted() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
+
+ // Could grant permission
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+ }
+
+ @Test
+ @AppModeFull
+ public void canGrantStorageTargetingSdk28OptInWhitelisted() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+
+ // Could grant permission
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+ }
+
+ @Test
+ @AppModeFull
+ public void canGrantStorageTargetingSdk29NotWhitelisted() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet());
+
+ // Could grant permission as targetSDK=29 apps can always grant
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+ }
+
+ @Test
+ @AppModeFull
+ public void canGrantStorageTargetingSdk29OptOutNotWhitelisted() throws Exception {
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet());
+
+ // Could grant permission as targetSDK=29 apps can always grant
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+ }
+
+ @Test
+ @AppModeFull
+ public void canGrantStorageTargetingSdk29Whitelisted() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+
+ // Could grant permission as targetSDK=29 apps can always grant
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+ }
+
+ @Test
+ @AppModeFull
+ public void canGrantStorageTargetingSdk29OptOutWhitelisted() throws Exception {
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+
+ // Could grant permission as targetSDK=29 apps can always grant
+ eventually(() ->
+ assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+ }
+
+ @Test
+ @AppModeFull
+ public void restrictedWritePermDoesNotImplyIsolatedStorageAccess() throws Exception {
+ // Install with whitelisted read permissions.
+ installApp(
+ APK_USES_STORAGE_OPT_OUT_29,
+ Collections.singleton(Manifest.permission.READ_EXTERNAL_STORAGE));
+
+ // It does not matter that write is restricted as the storage access level is only
+ // controlled by the read perm
+ assertHasFullStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void whitelistedWritePermDoesNotImplyFullStorageAccess() throws Exception {
+ // Install with whitelisted read permissions.
+ installApp(
+ APK_USES_STORAGE_OPT_OUT_29,
+ Collections.singleton(Manifest.permission.WRITE_EXTERNAL_STORAGE));
+
+ // It does not matter that write is white listed as the storage access level is only
+ // controlled by the read perm
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk30CanPreserveLegacyOnUpdateFromLegacy() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ assertHasFullStorageAccess();
+
+ // Updating with the flag preserves legacy
+ installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+ assertHasFullStorageAccess();
+
+ // And with the flag still preserves legacy
+ installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+ assertHasFullStorageAccess();
+
+ // But without the flag loses legacy
+ installApp(APK_USES_STORAGE_OPT_OUT_30, null);
+ assertHasIsolatedStorageAccess();
+
+ // And again with the flag doesn't bring back legacy
+ installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk30CannotPreserveLegacyAfterLegacyUninstall()
+ throws Exception {
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ assertHasFullStorageAccess();
+
+ runShellCommand("pm uninstall " + PKG);
+
+ installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk30CannotPreserveLegacyOnUpdateFromNonLegacy()
+ throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+ installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+
+ assertHasIsolatedStorageAccess();
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk30CannotPreserveLegacyOnInstall() throws Exception {
+ installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+
+ assertHasIsolatedStorageAccess();
+ }
+
+ private void assertHasFullStorageAccess() throws Exception {
+ runWithShellPermissionIdentity(() -> {
+ AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+ final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
+ eventually(() -> assertThat(appOpsManager.unsafeCheckOpRawNoThrow(
+ AppOpsManager.OPSTR_LEGACY_STORAGE,
+ uid, PKG)).isEqualTo(AppOpsManager.MODE_ALLOWED));
+ });
+ }
+
+ private void assertHasIsolatedStorageAccess() throws Exception {
+ runWithShellPermissionIdentity(() -> {
+ AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+ final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
+ eventually(() -> assertThat(appOpsManager.unsafeCheckOpRawNoThrow(
+ AppOpsManager.OPSTR_LEGACY_STORAGE,
+ uid, PKG)).isNotEqualTo(AppOpsManager.MODE_ALLOWED));
+ });
+ }
+
+ private void assertCannotWhitelistStorage() throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+
+ runWithShellPermissionIdentity(() -> {
+ // Assert added only to none whitelist.
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+ .doesNotContain(permission.READ_EXTERNAL_STORAGE);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+ .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
+ });
+
+ // Assert we cannot add.
+ try {
+ packageManager.addWhitelistedRestrictedPermission(
+ PKG,
+ permission.READ_EXTERNAL_STORAGE,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ try {
+ packageManager.addWhitelistedRestrictedPermission(
+ PKG,
+ permission.WRITE_EXTERNAL_STORAGE,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ fail();
+ } catch (SecurityException expected) {
+ }
+
+ runWithShellPermissionIdentity(() -> {
+ // Assert added only to none whitelist.
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+ .doesNotContain(permission.READ_EXTERNAL_STORAGE);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+ .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
+ });
+ }
+
+ private void assertCannotUnWhitelistStorage() throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+
+ runWithShellPermissionIdentity(() -> {
+ // Assert added only to install whitelist.
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+ .contains(permission.READ_EXTERNAL_STORAGE);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+ .contains(permission.WRITE_EXTERNAL_STORAGE);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
+ .doesNotContain(permission.READ_EXTERNAL_STORAGE);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
+ .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
+ });
+
+ try {
+ // Assert we cannot remove.
+ packageManager.removeWhitelistedRestrictedPermission(
+ PKG,
+ permission.READ_EXTERNAL_STORAGE,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ try {
+ packageManager.removeWhitelistedRestrictedPermission(
+ PKG,
+ permission.WRITE_EXTERNAL_STORAGE,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ fail();
+ } catch (SecurityException expected) {
+ }
+
+ runWithShellPermissionIdentity(() -> {
+ // Assert added only to install whitelist.
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+ .contains(permission.READ_EXTERNAL_STORAGE);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+ .contains(permission.WRITE_EXTERNAL_STORAGE);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
+ .doesNotContain(permission.READ_EXTERNAL_STORAGE);
+ assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
+ .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
+ });
+ }
+
+ private @NonNull Set<String> getPermissionsOfAppWithAnyOfFlags(int flags) throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+ final Set<String> restrictedPermissions = new ArraySet<>();
+ for (String permission : getRequestedPermissionsOfApp()) {
+ PermissionInfo permInfo = packageManager.getPermissionInfo(permission, 0);
+
+ if ((permInfo.flags & flags) != 0) {
+ restrictedPermissions.add(permission);
+ }
+ }
+ return restrictedPermissions;
+ }
+
+ private @NonNull Set<String> getRestrictedPermissionsOfApp() throws Exception {
+ return getPermissionsOfAppWithAnyOfFlags(
+ PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED);
+ }
+
+ private @NonNull String[] getRequestedPermissionsOfApp() throws Exception {
+ final PackageManager packageManager = getContext().getPackageManager();
+ final PackageInfo packageInfo =
+ packageManager.getPackageInfo(PKG, PackageManager.GET_PERMISSIONS);
+ return packageInfo.requestedPermissions;
+ }
+
+ private static @NonNull Context getContext() {
+ return InstrumentationRegistry.getInstrumentation().getContext();
+ }
+
+ private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable command)
+ throws Exception {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ try {
+ command.run();
+ } finally {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Install an app.
+ *
+ * @param app The app to be installed
+ * @param whitelistedPermissions The permission to be whitelisted. {@code null} == all
+ * @param grantedPermissions The permission to be granted. {@code null} == all
+ */
+ private void installApp(
+ @NonNull String app,
+ @Nullable Set<String> whitelistedPermissions)
+ throws Exception {
+ String bypassLowTargetSdkFlag = "";
+ if (SdkLevel.isAtLeastU()) {
+ bypassLowTargetSdkFlag = " --bypass-low-target-sdk-block";
+ }
+
+ // Install the app and whitelist/grant all permission if requested.
+ String installResult = runShellCommandOrThrow("pm install"
+ + bypassLowTargetSdkFlag + " -t -r --restrict-permissions " + app);
+ assertThat(installResult.trim()).isEqualTo("Success");
+
+ final Set<String> adjustedWhitelistedPermissions;
+ if (whitelistedPermissions == null) {
+ adjustedWhitelistedPermissions = getRestrictedPermissionsOfApp();
+ } else {
+ adjustedWhitelistedPermissions = whitelistedPermissions;
+ }
+
+ final Set<String> adjustedGrantedPermissions = getRestrictedPermissionsOfApp();
+
+ // Whitelist subset of permissions if requested
+ runWithShellPermissionIdentity(() -> {
+ final PackageManager packageManager = getContext().getPackageManager();
+ for (String permission : adjustedWhitelistedPermissions) {
+ packageManager.addWhitelistedRestrictedPermission(
+ PKG,
+ permission,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ }
+ });
+
+ // Grant subset of permissions if requested
+ runWithShellPermissionIdentity(() -> {
+ final PackageManager packageManager = getContext().getPackageManager();
+ for (String permission : adjustedGrantedPermissions) {
+ packageManager.grantRuntimePermission(PKG, permission, getContext().getUser());
+ packageManager.updatePermissionFlags(
+ permission,
+ PKG,
+ PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
+ 0,
+ getContext().getUser());
+ }
+ });
+
+ // Mark all permissions as reviewed as for pre-22 apps the restriction state might not be
+ // applied until reviewed
+ runWithShellPermissionIdentity(() -> {
+ final PackageManager packageManager = getContext().getPackageManager();
+ for (String permission : getRequestedPermissionsOfApp()) {
+ packageManager.updatePermissionFlags(
+ permission,
+ PKG,
+ PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED,
+ 0,
+ getContext().getUser());
+ }
+ });
+ }
+
+ @After
+ public void uninstallApp() {
+ runShellCommand("pm uninstall " + PKG);
+ }
+}
diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt
new file mode 100644
index 000000000..6b3ae5f2e
--- /dev/null
+++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionpolicy.cts
+
+import android.Manifest.permission.ACCEPT_HANDOVER
+import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.Manifest.permission.ACTIVITY_RECOGNITION
+import android.Manifest.permission.ADD_VOICEMAIL
+import android.Manifest.permission.ANSWER_PHONE_CALLS
+import android.Manifest.permission.BLUETOOTH_ADVERTISE
+import android.Manifest.permission.BLUETOOTH_CONNECT
+import android.Manifest.permission.BLUETOOTH_SCAN
+import android.Manifest.permission.BODY_SENSORS
+import android.Manifest.permission.CALL_PHONE
+import android.Manifest.permission.CAMERA
+import android.Manifest.permission.GET_ACCOUNTS
+import android.Manifest.permission.NEARBY_WIFI_DEVICES
+import android.Manifest.permission.PACKAGE_USAGE_STATS
+import android.Manifest.permission.POST_NOTIFICATIONS
+import android.Manifest.permission.PROCESS_OUTGOING_CALLS
+import android.Manifest.permission.READ_CALENDAR
+import android.Manifest.permission.READ_CALL_LOG
+import android.Manifest.permission.READ_CELL_BROADCASTS
+import android.Manifest.permission.READ_CONTACTS
+import android.Manifest.permission.READ_EXTERNAL_STORAGE
+import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+import android.Manifest.permission.READ_PHONE_NUMBERS
+import android.Manifest.permission.READ_PHONE_STATE
+import android.Manifest.permission.READ_SMS
+import android.Manifest.permission.RECEIVE_MMS
+import android.Manifest.permission.RECEIVE_SMS
+import android.Manifest.permission.RECEIVE_WAP_PUSH
+import android.Manifest.permission.RECORD_AUDIO
+import android.Manifest.permission.SEND_SMS
+import android.Manifest.permission.USE_SIP
+import android.Manifest.permission.UWB_RANGING
+import android.Manifest.permission.WRITE_CALENDAR
+import android.Manifest.permission.WRITE_CALL_LOG
+import android.Manifest.permission.WRITE_CONTACTS
+import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+import android.Manifest.permission_group.UNDEFINED
+import android.app.AppOpsManager.permissionToOp
+import android.content.pm.PackageManager.GET_PERMISSIONS
+import android.content.pm.PermissionInfo.PROTECTION_DANGEROUS
+import android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP
+import android.os.Build
+import android.permission.PermissionManager
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RuntimePermissionProperties {
+ private val context = InstrumentationRegistry.getInstrumentation().getTargetContext()
+ private val pm = context.packageManager
+
+ private val platformPkg = pm.getPackageInfo("android", GET_PERMISSIONS)
+ private val platformRuntimePerms =
+ platformPkg.permissions!!.filter { it.protection == PROTECTION_DANGEROUS }
+ private val platformBgPermNames = platformRuntimePerms.mapNotNull { it.backgroundPermission }
+
+ @Test
+ fun allRuntimeForegroundPermissionNeedAnAppOp() {
+ val platformFgPerms = platformRuntimePerms.filter { !platformBgPermNames.contains(it.name) }
+
+ for (perm in platformFgPerms) {
+ assertWithMessage("AppOp for ${perm.name}").that(permissionToOp(perm.name)).isNotNull()
+ }
+ }
+
+ @Test
+ fun groupOfRuntimePermissionsShouldBeUnknown() {
+ for (perm in platformRuntimePerms) {
+ assertWithMessage("Group of ${perm.name}").that(perm.group).isEqualTo(UNDEFINED)
+ }
+ }
+
+ @Test
+ fun allAppOpPermissionNeedAnAppOp() {
+ val platformAppOpPerms =
+ platformPkg.permissions!!
+ .filter { (it.protectionFlags and PROTECTION_FLAG_APPOP) != 0 }
+ .filter {
+ // Grandfather incomplete definition of PACKAGE_USAGE_STATS
+ it.name != PACKAGE_USAGE_STATS
+ }
+
+ for (perm in platformAppOpPerms) {
+ assertWithMessage("AppOp for ${perm.name}").that(permissionToOp(perm.name)).isNotNull()
+ }
+ }
+
+ /** The permission of a background permission is the one of its foreground permission */
+ @Test
+ fun allRuntimeBackgroundPermissionCantHaveAnAppOp() {
+ val platformBgPerms = platformRuntimePerms.filter { platformBgPermNames.contains(it.name) }
+
+ for (perm in platformBgPerms) {
+ assertWithMessage("AppOp for ${perm.name}").that(permissionToOp(perm.name)).isNull()
+ }
+ }
+
+ /** Commonly a new runtime permission is created by splitting an old one into twice */
+ @Test
+ fun runtimePermissionsShouldHaveBeenSplitFromPreviousPermission() {
+ // Runtime permissions in Android P
+ val expectedPerms =
+ mutableSetOf(
+ READ_CONTACTS,
+ WRITE_CONTACTS,
+ GET_ACCOUNTS,
+ READ_CALENDAR,
+ WRITE_CALENDAR,
+ SEND_SMS,
+ RECEIVE_SMS,
+ READ_SMS,
+ RECEIVE_MMS,
+ RECEIVE_WAP_PUSH,
+ READ_CELL_BROADCASTS,
+ READ_EXTERNAL_STORAGE,
+ WRITE_EXTERNAL_STORAGE,
+ ACCESS_FINE_LOCATION,
+ ACCESS_COARSE_LOCATION,
+ READ_CALL_LOG,
+ WRITE_CALL_LOG,
+ PROCESS_OUTGOING_CALLS,
+ READ_PHONE_STATE,
+ READ_PHONE_NUMBERS,
+ CALL_PHONE,
+ ADD_VOICEMAIL,
+ USE_SIP,
+ ANSWER_PHONE_CALLS,
+ ACCEPT_HANDOVER,
+ RECORD_AUDIO,
+ CAMERA,
+ BODY_SENSORS
+ )
+
+ // Add permission split since P
+ for (sdkVersion in Build.VERSION_CODES.P + 1..Build.VERSION_CODES.CUR_DEVELOPMENT + 1) {
+ for (splitPerm in
+ context.getSystemService(PermissionManager::class.java)!!.splitPermissions) {
+ if (
+ splitPerm.targetSdk == sdkVersion &&
+ expectedPerms.contains(splitPerm.splitPermission)
+ ) {
+ expectedPerms.addAll(splitPerm.newPermissions)
+ }
+ }
+ }
+
+ // Add runtime permission added in Q which were _not_ split from a previously existing
+ // runtime permission
+ expectedPerms.add(ACTIVITY_RECOGNITION)
+
+ // Add runtime permissions added in S which were _not_ split from a previously existing
+ // runtime permission
+ expectedPerms.add(BLUETOOTH_ADVERTISE)
+ expectedPerms.add(BLUETOOTH_CONNECT)
+ expectedPerms.add(BLUETOOTH_SCAN)
+ expectedPerms.add(UWB_RANGING)
+
+ // Add runtime permissions added in T which were _not_ split from a previously existing
+ // runtime permission
+ expectedPerms.add(POST_NOTIFICATIONS)
+ expectedPerms.add(NEARBY_WIFI_DEVICES)
+
+ // Add runtime permissions added in U which were _not_ split from a previously existing
+ // runtime permission
+ expectedPerms.add(READ_MEDIA_VISUAL_USER_SELECTED)
+
+ assertThat(expectedPerms).containsExactlyElementsIn(platformRuntimePerms.map { it.name })
+ }
+}
diff --git a/tests/cts/permissionui/Android.bp b/tests/cts/permissionui/Android.bp
new file mode 100644
index 000000000..12fdbe533
--- /dev/null
+++ b/tests/cts/permissionui/Android.bp
@@ -0,0 +1,81 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsPermissionUiTestCases",
+ defaults: ["mts-target-sdk-version-current"],
+ sdk_version: "test_current",
+ min_sdk_version: "30",
+ srcs: [
+ "src/**/*.kt",
+ ":CtsProviderTestUtils",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "bluetooth-test-util-lib",
+ "modules-utils-build_system",
+ "androidx.test.core",
+ "permission-test-util-lib",
+ "sts-device-util",
+ "cts-wm-util",
+ "flag-junit",
+ "CtsAccessibilityCommon",
+ "platform-test-rules",
+ "platform-test-annotations",
+ ],
+ data: [
+ ":CtsPermissionPolicyApp25",
+ ":CtsUsePermissionApp22",
+ ":CtsUsePermissionApp22CalendarOnly",
+ ":CtsUsePermissionApp22None",
+ ":CtsUsePermissionApp23",
+ ":CtsUsePermissionApp25",
+ ":CtsUsePermissionApp26",
+ ":CtsUsePermissionApp28",
+ ":CtsUsePermissionApp29",
+ ":CtsUsePermissionApp30",
+ ":CtsUsePermissionApp30WithBackground",
+ ":CtsUsePermissionApp30WithBluetooth",
+ ":CtsUsePermissionApp31",
+ ":CtsUsePermissionApp32",
+ ":CtsUsePermissionAppLatest",
+ ":CtsUsePermissionAppLatestNone",
+ ":CtsUsePermissionAppWithOverlay",
+ ":CtsAccessMicrophoneAppLocationProvider",
+ ":CtsHelperAppOverlay",
+ ":CtsCreateNotificationChannelsApp31",
+ ":CtsMediaPermissionApp33WithStorage",
+ ":CtsDifferentPkgNameApp",
+ ":CtsUsePermissionAppImplicitUserSelectStorage",
+ ":CtsAppThatAccessesMicAndCameraPermission",
+ ":CtsUsePermissionAppStorage33",
+ ],
+ test_suites: [
+ "cts",
+ "sts",
+ "general-tests",
+ "mts-permission",
+ "automotive-tests",
+ "automotive-general-tests",
+ ],
+}
diff --git a/tests/cts/permissionui/AndroidManifest.xml b/tests/cts/permissionui/AndroidManifest.xml
new file mode 100644
index 000000000..3b80b8d8b
--- /dev/null
+++ b/tests/cts/permissionui/AndroidManifest.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.GET_TASKS" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+
+ <application>
+
+ <uses-library android:name="android.test.runner" />
+
+ <service android:name="android.permission.cts.CtsNotificationListenerService"
+ android:exported="true"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService"/>
+ </intent-filter>
+ </service>
+
+ <activity android:name="com.android.compatibility.common.util.FutureResultActivity" />
+ <activity
+ android:name=".StartForFutureActivity"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"/>
+
+ <activity android:name=".TestInstallerActivity"
+ android:exported="true"
+ android:enabled="false"
+ android:launchMode="singleInstance">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.SHOW_APP_INFO" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <service android:name=".AccessibilityTestService1"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:label="@string/test_accessibility_service"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/test_accessibilityservice"/>
+ </service>
+
+ <service android:name=".AccessibilityTestService2"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:label="@string/test_accessibility_service_2"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/test_accessibilityservice"/>
+ </service>
+
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.permissionui.cts"
+ android:label="CTS UI tests for permissions">
+ </instrumentation>
+</manifest>
diff --git a/tests/cts/permissionui/AndroidTest.xml b/tests/cts/permissionui/AndroidTest.xml
new file mode 100644
index 000000000..eefa0018d
--- /dev/null
+++ b/tests/cts/permissionui/AndroidTest.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Config for CTS Permission UI test cases">
+
+ <option name="test-suite-tag" value="cts" />
+
+ <option name="config-descriptor:metadata" key="component" value="permissions" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="run_on_sdk_sandbox" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" />
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+
+ <!-- Keep screen on for Bluetooth scanning -->
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ <option name="disable-device-config-sync" value="true" />
+ <option name="screen-always-on" value="on" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPermissionUiTestCases.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="CtsAccessMicrophoneAppLocationProvider.apk->/data/local/tmp/cts-permissionui/CtsAccessMicrophoneAppLocationProvider.apk" />
+ <option name="push" value="CtsPermissionPolicyApp25.apk->/data/local/tmp/cts-permissionui/CtsPermissionPolicyApp25.apk" />
+ <option name="push" value="CtsUsePermissionApp22.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp22.apk" />
+ <option name="push" value="CtsUsePermissionApp22CalendarOnly.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp22CalendarOnly.apk" />
+ <option name="push" value="CtsUsePermissionApp22None.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp22None.apk" />
+ <option name="push" value="CtsUsePermissionApp23.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp23.apk" />
+ <option name="push" value="CtsUsePermissionApp25.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp25.apk" />
+ <option name="push" value="CtsUsePermissionApp26.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp26.apk" />
+ <option name="push" value="CtsUsePermissionApp28.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp28.apk" />
+ <option name="push" value="CtsUsePermissionApp29.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp29.apk" />
+ <option name="push" value="CtsUsePermissionApp30.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp30.apk" />
+ <option name="push" value="CtsUsePermissionApp30WithBackground.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp30WithBackground.apk" />
+ <option name="push" value="CtsUsePermissionApp30WithBluetooth.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp30WithBluetooth.apk" />
+ <option name="push" value="CtsUsePermissionApp31.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp31.apk" />
+ <option name="push" value="CtsUsePermissionApp32.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionApp32.apk" />
+ <option name="push" value="CtsUsePermissionAppLatest.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionAppLatest.apk" />
+ <option name="push" value="CtsUsePermissionAppLatestNone.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionAppLatestNone.apk" />
+ <option name="push" value="CtsUsePermissionAppWithOverlay.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionAppWithOverlay.apk" />
+ <option name="push" value="CtsHelperAppOverlay.apk->/data/local/tmp/cts-permissionui/CtsHelperAppOverlay.apk" />
+ <option name="push" value="CtsCreateNotificationChannelsApp31.apk->/data/local/tmp/cts-permissionui/CtsCreateNotificationChannelsApp31.apk" />
+ <option name="push" value="CtsDifferentPkgNameApp.apk->/data/local/tmp/cts-permissionui/CtsDifferentPkgNameApp.apk" />
+ <option name="push" value="CtsMediaPermissionApp33WithStorage.apk->/data/local/tmp/cts-permissionui/CtsMediaPermissionApp33WithStorage.apk" />
+ <option name="push" value="CtsUsePermissionAppImplicitUserSelectStorage.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionAppImplicitUserSelectStorage.apk" />
+ <option name="push" value="CtsAppThatAccessesMicAndCameraPermission.apk->/data/local/tmp/cts-permissionui/CtsAppThatAccessesMicAndCameraPermission.apk" />
+ <option name="push" value="CtsUsePermissionAppStorage33.apk->/data/local/tmp/cts-permissionui/CtsUsePermissionAppStorage33.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="appops set android.permissionui.cts REQUEST_INSTALL_PACKAGES allow" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
+ <!-- ensure user setup is completed -->
+ <option name="run-command" value="settings put secure user_setup_complete 1" />
+ <!-- disable DeprecatedAbi warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_abi_dialog 1" />
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1" />
+ </target_preparer>
+
+ <!-- Create place to store apks -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/cts-permissionui" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/cts-permissionui"/>
+ </target_preparer>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/user/0/android.permissionui.cts/files" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.permissionui.cts" />
+ <option name="runtime-hint" value="5m" />
+ </test>
+</configuration>
diff --git a/tests/cts/permissionui/AppThatAccessesCameraAndMic/Android.bp b/tests/cts/permissionui/AppThatAccessesCameraAndMic/Android.bp
new file mode 100644
index 000000000..e0d9fd791
--- /dev/null
+++ b/tests/cts/permissionui/AppThatAccessesCameraAndMic/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatAccessesMicAndCameraPermission",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "31",
+
+ static_libs: [
+ "androidx.test.rules",
+ "kotlin-stdlib",
+ "kotlinx-coroutines-android",
+ ],
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+}
diff --git a/tests/cts/permissionui/AppThatAccessesCameraAndMic/AndroidManifest.xml b/tests/cts/permissionui/AppThatAccessesCameraAndMic/AndroidManifest.xml
new file mode 100644
index 000000000..e1130fbaa
--- /dev/null
+++ b/tests/cts/permissionui/AppThatAccessesCameraAndMic/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.appthataccessescameraandmic"
+ android:versionCode="1">
+
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.CAMERA"/>
+
+ <application android:label="CtsCameraMicAccess">
+ <activity android:name=".AccessCameraOrMicActivity"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="test.action.USE_CAMERA_OR_MIC" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/AppThatAccessesCameraAndMic/src/android/permissionui/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt b/tests/cts/permissionui/AppThatAccessesCameraAndMic/src/android/permissionui/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
new file mode 100644
index 000000000..ca0c458a3
--- /dev/null
+++ b/tests/cts/permissionui/AppThatAccessesCameraAndMic/src/android/permissionui/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.appthataccessescameraandmic
+
+import android.app.Activity
+import android.app.AppOpsManager
+import android.hardware.camera2.CameraAccessException
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraManager
+import android.hardware.camera2.params.OutputConfiguration
+import android.hardware.camera2.params.SessionConfiguration
+import android.media.AudioFormat.CHANNEL_IN_MONO
+import android.media.AudioFormat.ENCODING_PCM_16BIT
+import android.media.AudioRecord
+import android.media.ImageReader
+import android.media.MediaRecorder.AudioSource.MIC
+import android.os.Bundle
+import android.os.Handler
+import android.os.Process
+import android.util.Log
+import android.util.Size
+import androidx.annotation.NonNull
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+private const val USE_CAMERA = "use_camera"
+private const val USE_MICROPHONE = "use_microphone"
+private const val USE_HOTWORD = "use_hotword"
+private const val FINISH_EARLY = "finish_early"
+private const val USE_DURATION_MS = 10000L
+private const val SAMPLE_RATE_HZ = 44100
+
+/**
+ * Activity which will, depending on the extra passed in the intent, use the camera, the microphone,
+ * or both.
+ */
+class AccessCameraOrMicActivity : Activity() {
+ private lateinit var cameraManager: CameraManager
+ private lateinit var cameraId: String
+ private var cameraDevice: CameraDevice? = null
+ private var recorder: AudioRecord? = null
+ private var appOpsManager: AppOpsManager? = null
+ private var cameraFinished = false
+ private var runCamera = false
+ private var backupCameraOpRunning = true
+ private var micFinished = false
+ private var runMic = false
+ private var hotwordFinished = false
+ private var runHotword = false
+ private var finishEarly = false
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ throw RuntimeException(
+ "Activity was recreated (perhaps due to a configuration change?) " +
+ "and this activity doesn't currently know how to gracefully handle " +
+ "configuration changes."
+ )
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ runCamera = intent.getBooleanExtra(USE_CAMERA, false)
+ runMic = intent.getBooleanExtra(USE_MICROPHONE, false)
+ runHotword = intent.getBooleanExtra(USE_HOTWORD, false)
+ finishEarly = intent.getBooleanExtra(FINISH_EARLY, false)
+
+ if (runMic) {
+ useMic()
+ }
+
+ if (runCamera) {
+ useCamera()
+ }
+
+ if (runHotword) {
+ useHotword()
+ }
+ }
+
+ override fun finish() {
+ super.finish()
+ cameraDevice?.close()
+ cameraDevice = null
+ recorder?.stop()
+ recorder = null
+ if (runCamera) {
+ appOpsManager?.finishOp(AppOpsManager.OPSTR_CAMERA, Process.myUid(), packageName)
+ }
+ if (runHotword) {
+ appOpsManager?.finishOp(
+ AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
+ Process.myUid(),
+ packageName
+ )
+ }
+ appOpsManager = null
+ }
+
+ override fun onStop() {
+ super.onStop()
+ finish()
+ }
+
+ private val stateCallback =
+ object : CameraDevice.StateCallback() {
+ override fun onOpened(@NonNull camDevice: CameraDevice) {
+ cameraDevice = camDevice
+ val config =
+ cameraManager!!
+ .getCameraCharacteristics(cameraId)
+ .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
+ val outputFormat = config!!.outputFormats[0]
+ val outputSize: Size = config!!.getOutputSizes(outputFormat)[0]
+ val handler = Handler(mainLooper)
+
+ val imageReader =
+ ImageReader.newInstance(outputSize.width, outputSize.height, outputFormat, 2)
+
+ val builder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
+ builder.addTarget(imageReader.surface)
+ val captureRequest = builder.build()
+ val sessionConfiguration =
+ SessionConfiguration(
+ SessionConfiguration.SESSION_REGULAR,
+ listOf(OutputConfiguration(imageReader.surface)),
+ mainExecutor,
+ object : CameraCaptureSession.StateCallback() {
+ override fun onConfigured(session: CameraCaptureSession) {
+ session.capture(captureRequest, null, handler)
+ }
+
+ override fun onConfigureFailed(session: CameraCaptureSession) {}
+
+ override fun onReady(session: CameraCaptureSession) {}
+ }
+ )
+
+ imageReader.setOnImageAvailableListener(
+ {
+ GlobalScope.launch {
+ delay(USE_DURATION_MS)
+ if (!backupCameraOpRunning) {
+ cameraFinished = true
+ if (!runMic || micFinished) {
+ finish()
+ }
+ }
+ }
+ },
+ handler
+ )
+ cameraDevice!!.createCaptureSession(sessionConfiguration)
+ }
+
+ override fun onDisconnected(@NonNull camDevice: CameraDevice) {
+ Log.e("CameraMicIndicatorsPermissionTest", "camera disconnected")
+ startBackupCamera(camDevice)
+ }
+
+ override fun onError(@NonNull camDevice: CameraDevice, error: Int) {
+ Log.e("CameraMicIndicatorsPermissionTest", "camera error $error")
+ startBackupCamera(camDevice)
+ }
+ }
+
+ private fun startBackupCamera(camDevice: CameraDevice?) {
+ // Something went wrong with the camera. Fallback to direct app op usage
+ if (runCamera && !cameraFinished) {
+ backupCameraOpRunning = true
+ appOpsManager = getSystemService(AppOpsManager::class.java)
+ appOpsManager?.startOpNoThrow(AppOpsManager.OPSTR_CAMERA, Process.myUid(), packageName)
+
+ GlobalScope.launch {
+ delay(USE_DURATION_MS)
+ cameraFinished = true
+ backupCameraOpRunning = false
+ finishIfAllDone()
+ }
+ }
+ camDevice?.close()
+ if (camDevice == cameraDevice) {
+ cameraDevice = null
+ }
+ }
+
+ @Throws(CameraAccessException::class)
+ private fun useCamera() {
+ // TODO 192690992: determine why the camera manager code is flaky
+ startBackupCamera(null)
+ /*
+ cameraManager = getSystemService(CameraManager::class.java)!!
+ cameraId = cameraManager.cameraIdList[0]
+ cameraManager.openCamera(cameraId, mainExecutor, stateCallback)
+ */
+ }
+
+ private fun useMic() {
+ val minSize =
+ AudioRecord.getMinBufferSize(SAMPLE_RATE_HZ, CHANNEL_IN_MONO, ENCODING_PCM_16BIT)
+ recorder = AudioRecord(MIC, SAMPLE_RATE_HZ, CHANNEL_IN_MONO, ENCODING_PCM_16BIT, minSize)
+ recorder?.startRecording()
+ if (finishEarly) {
+ appOpsManager = getSystemService(AppOpsManager::class.java)
+ appOpsManager?.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO, Process.myUid(), packageName)
+ return
+ }
+ GlobalScope.launch {
+ delay(USE_DURATION_MS)
+ micFinished = true
+ finishIfAllDone()
+ }
+ }
+
+ private fun useHotword() {
+ appOpsManager = getSystemService(AppOpsManager::class.java)
+ appOpsManager?.startOpNoThrow(
+ AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
+ Process.myUid(),
+ packageName
+ )
+
+ GlobalScope.launch {
+ delay(USE_DURATION_MS)
+ hotwordFinished = true
+ finishIfAllDone()
+ }
+ }
+
+ private fun finishIfAllDone() {
+ if (
+ (!runMic || micFinished) &&
+ (!runCamera || cameraFinished) &&
+ (!runHotword || hotwordFinished)
+ ) {
+ finish()
+ }
+ }
+}
diff --git a/tests/cts/permissionui/CreateNotificationChannelsApp31/Android.bp b/tests/cts/permissionui/CreateNotificationChannelsApp31/Android.bp
new file mode 100644
index 000000000..265a01c69
--- /dev/null
+++ b/tests/cts/permissionui/CreateNotificationChannelsApp31/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsCreateNotificationChannelsApp31",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "31",
+
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+}
diff --git a/tests/cts/permissionui/CreateNotificationChannelsApp31/AndroidManifest.xml b/tests/cts/permissionui/CreateNotificationChannelsApp31/AndroidManifest.xml
new file mode 100644
index 000000000..b342319f3
--- /dev/null
+++ b/tests/cts/permissionui/CreateNotificationChannelsApp31/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission"
+ android:versionCode="1">
+
+ <uses-sdk android:minSdkVersion="31" android:targetSdkVersion="31" />
+
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+ <application android:label="CreateNotif">
+ <activity android:name=".CreateNotificationChannelsActivity"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="usepermission.createchannels.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/CreateNotificationChannelsApp31/src/android/permissionui/cts/usepermission/CreateNotificationChannelsActivity.kt b/tests/cts/permissionui/CreateNotificationChannelsApp31/src/android/permissionui/cts/usepermission/CreateNotificationChannelsActivity.kt
new file mode 100644
index 000000000..302d021ca
--- /dev/null
+++ b/tests/cts/permissionui/CreateNotificationChannelsApp31/src/android/permissionui/cts/usepermission/CreateNotificationChannelsActivity.kt
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermission
+
+import android.Manifest
+import android.app.Activity
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+
+const val EXTRA_CREATE_CHANNELS = "extra_create"
+const val EXTRA_REQUEST_NOTIF_PERMISSION = "extra_request_notif_permission"
+const val EXTRA_REQUEST_OTHER_PERMISSIONS = "extra_request_permissions"
+const val EXTRA_START_SECOND_ACTIVITY = "extra_start_second_activity"
+const val EXTRA_START_SECOND_APP = "extra_start_second_app"
+const val SECONDARY_APP_INTENT = "emptyactivity.main"
+const val SECONDARY_APP_PKG = "android.permissionui.cts.usepermissionother"
+const val TEST_PKG = "android.permissionui.cts"
+const val CHANNEL_ID_31 = "test_channel_id"
+const val BROADCAST_ACTION = "usepermission.createchannels.BROADCAST"
+const val DELAY_MS = 1000L
+const val LONG_DELAY_MS = 2000L
+
+class CreateNotificationChannelsActivity : Activity() {
+ private lateinit var notificationManager: NotificationManager
+ private var launchActivityOnSecondResume = false
+ private var isFirstResume = true
+ private var windowHasFocus = false
+ private var pendingCreateChannel = false
+ private val handler = Handler(Looper.getMainLooper())
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ throw RuntimeException(
+ "Activity was recreated (perhaps due to a configuration change?) " +
+ "and this activity doesn't currently know how to gracefully handle " +
+ "configuration changes."
+ )
+ }
+
+ registerReceiver(receiver, IntentFilter(BROADCAST_ACTION), RECEIVER_EXPORTED)
+ handleIntent(intent)
+ }
+
+ private fun handleIntent(providedIntent: Intent?, broacastAfterComplete: Boolean = false) {
+ if (providedIntent == null) {
+ return
+ }
+ val launchSecondActivity =
+ providedIntent.getBooleanExtra(EXTRA_START_SECOND_ACTIVITY, false)
+ notificationManager = baseContext.getSystemService(NotificationManager::class.java)!!
+ if (providedIntent.getBooleanExtra(EXTRA_START_SECOND_APP, false)) {
+ handler.postDelayed(
+ {
+ val intent2 = Intent(SECONDARY_APP_INTENT)
+ intent2.`package` = SECONDARY_APP_PKG
+ intent2.addCategory(Intent.CATEGORY_DEFAULT)
+ handler.postDelayed({ createChannel() }, DELAY_MS)
+ startActivity(intent2)
+ },
+ LONG_DELAY_MS
+ )
+ } else if (providedIntent.getBooleanExtra(EXTRA_CREATE_CHANNELS, false)) {
+ createChannel()
+ if (launchSecondActivity) {
+ launchActivityOnSecondResume = true
+ }
+ } else if (launchSecondActivity) {
+ launchSecondActivity()
+ }
+
+ if (providedIntent.getBooleanExtra(EXTRA_REQUEST_OTHER_PERMISSIONS, false)) {
+ requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), 0)
+ }
+
+ if (providedIntent.getBooleanExtra(EXTRA_REQUEST_NOTIF_PERMISSION, false)) {
+ requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 0)
+ }
+
+ if (broacastAfterComplete) {
+ sendBroadcast(Intent(BROADCAST_ACTION).setPackage(TEST_PKG))
+ }
+ }
+
+ private val receiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ handleIntent(intent, true)
+ }
+ }
+
+ private fun launchSecondActivity() {
+ handler.postDelayed(
+ {
+ val intent2 = Intent(Intent.ACTION_MAIN)
+ intent2.`package` = packageName
+ intent2.addCategory(Intent.CATEGORY_DEFAULT)
+ intent2.putExtra(EXTRA_CREATE_CHANNELS, true)
+ startActivity(intent2)
+ },
+ LONG_DELAY_MS
+ )
+ }
+
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ windowHasFocus = hasFocus
+ if (windowHasFocus && pendingCreateChannel) {
+ pendingCreateChannel = false
+ createChannel()
+ }
+ }
+
+ private fun createChannel() {
+ // Wait until window has focus so the permission prompt can be displayed
+ if (!windowHasFocus) {
+ pendingCreateChannel = true
+ return
+ }
+
+ if (notificationManager.getNotificationChannel(CHANNEL_ID_31) == null) {
+ notificationManager.createNotificationChannel(
+ NotificationChannel(
+ CHANNEL_ID_31,
+ "Foreground Services",
+ NotificationManager.IMPORTANCE_HIGH
+ )
+ )
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (!isFirstResume && launchActivityOnSecondResume) {
+ launchSecondActivity()
+ }
+ isFirstResume = false
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<out String>,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ val grantedPerms = arrayListOf<String>()
+ for ((i, permName) in permissions.withIndex()) {
+ if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
+ grantedPerms.add(permName)
+ }
+ }
+ sendBroadcast(
+ Intent(BROADCAST_ACTION)
+ .putStringArrayListExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS,
+ grantedPerms
+ )
+ .setPackage(TEST_PKG)
+ )
+ }
+
+ companion object {
+ private val TAG = CreateNotificationChannelsActivity::class.simpleName
+ }
+}
diff --git a/tests/cts/permissionui/DifferentPkgNameApp/Android.bp b/tests/cts/permissionui/DifferentPkgNameApp/Android.bp
new file mode 100644
index 000000000..3db3c30b2
--- /dev/null
+++ b/tests/cts/permissionui/DifferentPkgNameApp/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsDifferentPkgNameApp",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "31",
+
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+}
diff --git a/tests/cts/permissionui/DifferentPkgNameApp/AndroidManifest.xml b/tests/cts/permissionui/DifferentPkgNameApp/AndroidManifest.xml
new file mode 100644
index 000000000..d0b63b597
--- /dev/null
+++ b/tests/cts/permissionui/DifferentPkgNameApp/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermissionother"
+ android:versionCode="1">
+
+ <uses-sdk android:minSdkVersion="31" android:targetSdkVersion="31" />
+
+ <application android:label="EmptyActivity">
+ <activity android:name=".EmptyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="emptyactivity.main" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/DifferentPkgNameApp/src/android/permissionui/cts/usepermissionother/EmptyActivity.kt b/tests/cts/permissionui/DifferentPkgNameApp/src/android/permissionui/cts/usepermissionother/EmptyActivity.kt
new file mode 100644
index 000000000..fc4518a90
--- /dev/null
+++ b/tests/cts/permissionui/DifferentPkgNameApp/src/android/permissionui/cts/usepermissionother/EmptyActivity.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermissionother
+
+import android.app.Activity
+
+class EmptyActivity : Activity()
diff --git a/tests/cts/permissionui/HelperAppOverlay/Android.bp b/tests/cts/permissionui/HelperAppOverlay/Android.bp
new file mode 100644
index 000000000..94d9653e9
--- /dev/null
+++ b/tests/cts/permissionui/HelperAppOverlay/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsHelperAppOverlay",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "30",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+ certificate: ":cts-testkey2",
+}
diff --git a/tests/cts/permissionui/HelperAppOverlay/AndroidManifest.xml b/tests/cts/permissionui/HelperAppOverlay/AndroidManifest.xml
new file mode 100644
index 000000000..b26459660
--- /dev/null
+++ b/tests/cts/permissionui/HelperAppOverlay/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.helper.overlay">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+ <application>
+ <activity android:name=".OverlayActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/HelperAppOverlay/src/android/permissionui/cts/helper/overlay/OverlayActivity.kt b/tests/cts/permissionui/HelperAppOverlay/src/android/permissionui/cts/helper/overlay/OverlayActivity.kt
new file mode 100644
index 000000000..0ac0fd027
--- /dev/null
+++ b/tests/cts/permissionui/HelperAppOverlay/src/android/permissionui/cts/helper/overlay/OverlayActivity.kt
@@ -0,0 +1,26 @@
+package android.permissionui.cts.helper.overlay
+
+import android.app.Activity
+import android.os.Bundle
+import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.WindowManager
+import android.widget.LinearLayout
+import android.widget.TextView
+
+class OverlayActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val mainLayout = LinearLayout(this)
+ mainLayout.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+ val textView = TextView(this)
+
+ textView.text = "Find me!"
+ mainLayout.addView(textView)
+
+ val windowParams = WindowManager.LayoutParams()
+ windowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+ windowManager.addView(mainLayout, windowParams)
+ }
+}
diff --git a/tests/cts/permissionui/ImplicitUserSelectStorageApp/Android.bp b/tests/cts/permissionui/ImplicitUserSelectStorageApp/Android.bp
new file mode 100644
index 000000000..c341125fd
--- /dev/null
+++ b/tests/cts/permissionui/ImplicitUserSelectStorageApp/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionAppImplicitUserSelectStorage",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ target_sdk_version: "34",
+ min_sdk_version: "34",
+}
diff --git a/tests/cts/permissionui/ImplicitUserSelectStorageApp/AndroidManifest.xml b/tests/cts/permissionui/ImplicitUserSelectStorageApp/AndroidManifest.xml
new file mode 100644
index 000000000..212bf1508
--- /dev/null
+++ b/tests/cts/permissionui/ImplicitUserSelectStorageApp/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
+
+ <application>
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/MediaPermissionApp33WithStorage/Android.bp b/tests/cts/permissionui/MediaPermissionApp33WithStorage/Android.bp
new file mode 100644
index 000000000..77664c40b
--- /dev/null
+++ b/tests/cts/permissionui/MediaPermissionApp33WithStorage/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsMediaPermissionApp33WithStorage",
+ min_sdk_version: "33",
+ target_sdk_version: "33",
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+}
diff --git a/tests/cts/permissionui/MediaPermissionApp33WithStorage/AndroidManifest.xml b/tests/cts/permissionui/MediaPermissionApp33WithStorage/AndroidManifest.xml
new file mode 100644
index 000000000..ae21d1612
--- /dev/null
+++ b/tests/cts/permissionui/MediaPermissionApp33WithStorage/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission"
+ android:versionCode="1">
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <application>
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/OWNERS b/tests/cts/permissionui/OWNERS
new file mode 100644
index 000000000..01fbb4851
--- /dev/null
+++ b/tests/cts/permissionui/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 137825
+
+include platform/frameworks/base:/core/java/android/permission/OWNERS
+
diff --git a/tests/cts/permissionui/PermissionPolicyApp25/Android.bp b/tests/cts/permissionui/PermissionPolicyApp25/Android.bp
new file mode 100644
index 000000000..d3f88954c
--- /dev/null
+++ b/tests/cts/permissionui/PermissionPolicyApp25/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsPermissionPolicyApp25",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "25",
+}
diff --git a/tests/cts/permissionui/PermissionPolicyApp25/AndroidManifest.xml b/tests/cts/permissionui/PermissionPolicyApp25/AndroidManifest.xml
new file mode 100644
index 000000000..531ea47ac
--- /dev/null
+++ b/tests/cts/permissionui/PermissionPolicyApp25/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.permissionpolicy">
+
+ <uses-sdk android:minSdkVersion="25" android:targetSdkVersion="25" />
+
+ <application>
+ <activity android:name=".TestProtectionFlagsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/PermissionPolicyApp25/src/android/permissionui/cts/permissionpolicy/TestProtectionFlagsActivity.kt b/tests/cts/permissionui/PermissionPolicyApp25/src/android/permissionui/cts/permissionpolicy/TestProtectionFlagsActivity.kt
new file mode 100644
index 000000000..4bc81e7a9
--- /dev/null
+++ b/tests/cts/permissionui/PermissionPolicyApp25/src/android/permissionui/cts/permissionpolicy/TestProtectionFlagsActivity.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.permissionpolicy
+
+import android.app.Activity
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.PermissionInfo
+import android.os.Bundle
+
+/** An activity that can test platform permission protection flags. */
+class TestProtectionFlagsActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setResult(
+ RESULT_OK,
+ Intent().apply {
+ putExtra("$packageName.ERROR_MESSAGE", getProtectionFlagsErrorMessage())
+ }
+ )
+ finish()
+ }
+
+ private fun getProtectionFlagsErrorMessage(): String {
+ val packageInfo = packageManager.getPackageInfo("android", PackageManager.GET_PERMISSIONS)
+ val errorMessageBuilder = StringBuilder()
+ for (declaredPermissionInfo in packageInfo.permissions ?: emptyArray()) {
+ val permissionInfo = packageManager.getPermissionInfo(declaredPermissionInfo.name, 0)
+ val protection =
+ permissionInfo.protection and
+ (PermissionInfo.PROTECTION_NORMAL or
+ PermissionInfo.PROTECTION_DANGEROUS or
+ PermissionInfo.PROTECTION_SIGNATURE or
+ PermissionInfo.PROTECTION_INTERNAL)
+ val protectionFlags = permissionInfo.protectionLevel and protection.inv()
+ if (
+ (protection == PermissionInfo.PROTECTION_NORMAL ||
+ protection == PermissionInfo.PROTECTION_DANGEROUS) && protectionFlags != 0
+ ) {
+ errorMessageBuilder.apply {
+ if (isNotEmpty()) {
+ append("\n")
+ }
+ append(
+ "Cannot add protection flags ${protectionFlagsToString(protectionFlags)
+ } to a ${protectionToString(protection)} protection permission: ${
+ permissionInfo.name}"
+ )
+ }
+ }
+ }
+ return errorMessageBuilder.toString()
+ }
+
+ private fun protectionToString(protection: Int): String =
+ when (protection) {
+ PermissionInfo.PROTECTION_NORMAL -> "normal"
+ PermissionInfo.PROTECTION_DANGEROUS -> "dangerous"
+ PermissionInfo.PROTECTION_SIGNATURE -> "signature"
+ PermissionInfo.PROTECTION_INTERNAL -> "internal"
+ else -> Integer.toHexString(protection)
+ }
+
+ private fun protectionFlagsToString(protectionFlags: Int): String {
+ var unknownProtectionFlags = protectionFlags
+ val stringBuilder = StringBuilder()
+ val appendProtectionFlag = { protectionFlag: Int, protectionFlagString: String ->
+ if (unknownProtectionFlags and protectionFlag == protectionFlag) {
+ stringBuilder.apply {
+ if (isNotEmpty()) {
+ append("|")
+ }
+ append(protectionFlagString)
+ }
+ unknownProtectionFlags = unknownProtectionFlags and protectionFlag.inv()
+ }
+ }
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_PRIVILEGED, "privileged")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_DEVELOPMENT, "development")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_APPOP, "appop")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_PRE23, "pre23")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_INSTALLER, "installer")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_VERIFIER, "verifier")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_PREINSTALLED, "preinstalled")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_SETUP, "setup")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_INSTANT, "instant")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY, "runtimeOnly")
+ appendProtectionFlag(PermissionInfo.PROTECTION_FLAG_ROLE, "role")
+ if (unknownProtectionFlags != 0) {
+ appendProtectionFlag(
+ unknownProtectionFlags,
+ Integer.toHexString(unknownProtectionFlags)
+ )
+ }
+ return stringBuilder.toString()
+ }
+}
diff --git a/tests/cts/permissionui/StorageApp33/Android.bp b/tests/cts/permissionui/StorageApp33/Android.bp
new file mode 100644
index 000000000..35c79fada
--- /dev/null
+++ b/tests/cts/permissionui/StorageApp33/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionAppStorage33",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ target_sdk_version: "33",
+ min_sdk_version: "33",
+}
diff --git a/tests/cts/permissionui/StorageApp33/AndroidManifest.xml b/tests/cts/permissionui/StorageApp33/AndroidManifest.xml
new file mode 100644
index 000000000..212bf1508
--- /dev/null
+++ b/tests/cts/permissionui/StorageApp33/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
+
+ <application>
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/TEST_MAPPING b/tests/cts/permissionui/TEST_MAPPING
new file mode 100644
index 000000000..c703c539d
--- /dev/null
+++ b/tests/cts/permissionui/TEST_MAPPING
@@ -0,0 +1,32 @@
+{
+ "presubmit-large": [
+ {
+ "name": "CtsPermissionUiTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "CtsPermissionUiTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsPermissionUiTestCases"
+ }
+ ],
+ "mainline-postsubmit": [
+ {
+ "name": "CtsPermissionUiTestCases[com.google.android.permission.apex]"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/cts/permissionui/UsePermissionApp22/Android.bp b/tests/cts/permissionui/UsePermissionApp22/Android.bp
new file mode 100644
index 000000000..dcb04f6a4
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp22/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp22",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "22",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp22/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp22/AndroidManifest.xml
new file mode 100644
index 000000000..6a8bb1fd8
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp22/AndroidManifest.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22" />
+
+ <!-- Make sure permission code can handle invalid permissions -->
+ <uses-permission android:name="android.permissionui.cts.usepermission.INVALID_PERMISSION_NAME" />
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+ <!-- Contacts -->
+ <!-- Deliberately request WRITE_CONTACTS but *not* READ_CONTACTS -->
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+
+ <!-- Calendar -->
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+
+ <!-- SMS -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
+ <uses-permission android:name="android.permission.RECEIVE_MMS" />
+ <uses-permission android:name="android.permission.READ_CELL_BROADCASTS" />
+
+ <!-- Storage -->
+ <!-- Special case: WRITE_EXTERNAL_STORAGE implies READ_EXTERNAL_STORAGE -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <!-- Location -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.CALL_PHONE" />
+ <uses-permission android:name="android.permission.READ_CALL_LOG" />
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+ <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
+ <uses-permission android:name="android.permission.USE_SIP" />
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <!-- Camera -->
+ <uses-permission android:name="android.permission.CAMERA" />
+
+ <!-- Body Sensors -->
+ <uses-permission android:name="android.permission.BODY_SENSORS" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp22CalendarOnly/Android.bp b/tests/cts/permissionui/UsePermissionApp22CalendarOnly/Android.bp
new file mode 100644
index 000000000..26ff13566
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp22CalendarOnly/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp22CalendarOnly",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "22",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp22CalendarOnly/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp22CalendarOnly/AndroidManifest.xml
new file mode 100644
index 000000000..0610562b0
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp22CalendarOnly/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22" />
+
+ <!-- Calendar -->
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ <activity android:name=".StartCheckPermissionServiceActivity" android:exported="true" />
+ <service android:name=".CheckPermissionService" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp22CalendarOnly/src/android/permissionui/cts/usepermission/CheckPermissionService.kt b/tests/cts/permissionui/UsePermissionApp22CalendarOnly/src/android/permissionui/cts/usepermission/CheckPermissionService.kt
new file mode 100644
index 000000000..563f5255d
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp22CalendarOnly/src/android/permissionui/cts/usepermission/CheckPermissionService.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermission
+
+import android.app.IntentService
+import android.content.Intent
+import android.os.ResultReceiver
+
+/** A service that can check if a permission is currently granted */
+class CheckPermissionService : IntentService(CheckPermissionService::class.java.simpleName) {
+ companion object {
+ private const val TEST_PACKAGE_NAME = "android.permissionui.cts"
+ }
+
+ override fun onHandleIntent(intent: Intent?) {
+ val extras = intent!!.extras!!
+ // Load bundle with context of client package so ResultReceiver class can be resolved
+ val testContext =
+ createPackageContext(TEST_PACKAGE_NAME, CONTEXT_INCLUDE_CODE or CONTEXT_IGNORE_SECURITY)
+ extras.classLoader = testContext.classLoader
+ val result = extras.getParcelable<ResultReceiver>("$packageName.RESULT")!!
+ val permission = extras.getString("$packageName.PERMISSION")!!
+ result.send(checkSelfPermission(permission), null)
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionApp22CalendarOnly/src/android/permissionui/cts/usepermission/StartCheckPermissionServiceActivity.kt b/tests/cts/permissionui/UsePermissionApp22CalendarOnly/src/android/permissionui/cts/usepermission/StartCheckPermissionServiceActivity.kt
new file mode 100644
index 000000000..ebb4c2f12
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp22CalendarOnly/src/android/permissionui/cts/usepermission/StartCheckPermissionServiceActivity.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermission
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+
+class StartCheckPermissionServiceActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ startService(Intent(this, CheckPermissionService::class.java).putExtras(intent))
+ finish()
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionApp22None/Android.bp b/tests/cts/permissionui/UsePermissionApp22None/Android.bp
new file mode 100644
index 000000000..7d43f46ef
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp22None/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp22None",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "22",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp22None/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp22None/AndroidManifest.xml
new file mode 100644
index 000000000..8ee3094ea
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp22None/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp23/Android.bp b/tests/cts/permissionui/UsePermissionApp23/Android.bp
new file mode 100644
index 000000000..b98b2d3a3
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp23/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp23",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "23",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp23/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp23/AndroidManifest.xml
new file mode 100644
index 000000000..c1bb806a5
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp23/AndroidManifest.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23" />
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+ <!-- Contacts -->
+ <!-- Deliberately request WRITE_CONTACTS but *not* READ_CONTACTS -->
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+
+ <!-- Calendar -->
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+
+ <!-- SMS -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
+ <uses-permission android:name="android.permission.RECEIVE_MMS" />
+ <uses-permission android:name="android.permission.READ_CELL_BROADCASTS" />
+
+ <!-- Storage -->
+ <!-- Special case: WRITE_EXTERNAL_STORAGE implies READ_EXTERNAL_STORAGE -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <!-- Location -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.CALL_PHONE" />
+ <uses-permission android:name="android.permission.READ_CALL_LOG" />
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+ <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
+ <uses-permission android:name="android.permission.USE_SIP" />
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <!-- Camera -->
+ <uses-permission android:name="android.permission.CAMERA" />
+
+ <!-- Body Sensors -->
+ <uses-permission android:name="android.permission.BODY_SENSORS" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp25/Android.bp b/tests/cts/permissionui/UsePermissionApp25/Android.bp
new file mode 100644
index 000000000..d16d2c486
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp25/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp25",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "25",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp25/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp25/AndroidManifest.xml
new file mode 100644
index 000000000..f97a6b329
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp25/AndroidManifest.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="25" android:targetSdkVersion="25" />
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+ <!-- Contacts -->
+ <!-- Deliberately request WRITE_CONTACTS but *not* READ_CONTACTS -->
+ <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+ <!-- Calendar -->
+ <uses-permission android:name="android.permission.READ_CALENDAR"/>
+ <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
+
+ <!-- SMS -->
+ <uses-permission android:name="android.permission.SEND_SMS"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+ <uses-permission android:name="android.permission.READ_SMS"/>
+ <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
+ <uses-permission android:name="android.permission.RECEIVE_MMS"/>
+ <uses-permission android:name="android.permission.READ_CELL_BROADCASTS"/>
+
+ <!-- Storage -->
+ <!-- Special case: WRITE_EXTERNAL_STORAGE implies READ_EXTERNAL_STORAGE -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <!-- Location -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.CALL_PHONE"/>
+ <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
+ <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"/>
+ <uses-permission android:name="android.permission.USE_SIP"/>
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+ <!-- Camera -->
+ <uses-permission android:name="android.permission.CAMERA"/>
+
+ <!-- Body Sensors -->
+ <uses-permission android:name="android.permission.BODY_SENSORS"/>
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp26/Android.bp b/tests/cts/permissionui/UsePermissionApp26/Android.bp
new file mode 100644
index 000000000..d76163b3a
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp26/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp26",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "26",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp26/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp26/AndroidManifest.xml
new file mode 100644
index 000000000..4c29436cf
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp26/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="26" />
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp28/Android.bp b/tests/cts/permissionui/UsePermissionApp28/Android.bp
new file mode 100644
index 000000000..1f388fdc7
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp28/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp28",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "28",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp28/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp28/AndroidManifest.xml
new file mode 100644
index 000000000..98ede951f
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp28/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp29/Android.bp b/tests/cts/permissionui/UsePermissionApp29/Android.bp
new file mode 100644
index 000000000..8375b1e77
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp29/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp29",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ min_sdk_version: "29",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp29/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp29/AndroidManifest.xml
new file mode 100644
index 000000000..f1ae6c9d8
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp29/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp30/Android.bp b/tests/cts/permissionui/UsePermissionApp30/Android.bp
new file mode 100644
index 000000000..c1b4b8a9f
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp30/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp30",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+
+ min_sdk_version: "30",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp30/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp30/AndroidManifest.xml
new file mode 100644
index 000000000..7266fc1b6
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp30/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <uses-permission android:name="android.permission.CAMERA" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp30WithBackground/Android.bp b/tests/cts/permissionui/UsePermissionApp30WithBackground/Android.bp
new file mode 100644
index 000000000..eeac4ff8b
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp30WithBackground/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp30WithBackground",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+ certificate: ":cts-testkey2",
+
+ min_sdk_version: "30",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp30WithBackground/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp30WithBackground/AndroidManifest.xml
new file mode 100644
index 000000000..5949d08f2
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp30WithBackground/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <application>
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp30WithBackground/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt b/tests/cts/permissionui/UsePermissionApp30WithBackground/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt
new file mode 100644
index 000000000..31ff0fa04
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp30WithBackground/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermission
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+
+class RequestPermissionsActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ Log.w(TAG, "Activity was recreated. (Perhaps due to a configuration change?)")
+ return
+ }
+
+ val permissions = intent.getStringArrayExtra("$packageName.PERMISSIONS")!!
+ requestPermissions(permissions, 1)
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<out String>,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+
+ setResult(
+ RESULT_OK,
+ Intent().apply {
+ putExtra("$packageName.PERMISSIONS", permissions)
+ putExtra("$packageName.GRANT_RESULTS", grantResults)
+ }
+ )
+ finish()
+ }
+
+ companion object {
+ private val TAG = RequestPermissionsActivity::class.simpleName
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionApp30WithBluetooth/Android.bp b/tests/cts/permissionui/UsePermissionApp30WithBluetooth/Android.bp
new file mode 100644
index 000000000..d92ce5732
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp30WithBluetooth/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp30WithBluetooth",
+ srcs: [
+ "src/**/*.kt"
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ ],
+ certificate: ":cts-testkey2",
+
+ min_sdk_version: "30",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp30WithBluetooth/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp30WithBluetooth/AndroidManifest.xml
new file mode 100644
index 000000000..4d01e99c5
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp30WithBluetooth/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+
+ <application>
+ <provider
+ android:name=".AccessBluetoothOnCommand"
+ android:authorities="android.permissionui.cts.usepermission.AccessBluetoothOnCommand"
+ android:exported="true" />
+ </application>
+
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp30WithBluetooth/src/android/permissionui/cts/usepermission/AccessBluetoothOnCommand.kt b/tests/cts/permissionui/UsePermissionApp30WithBluetooth/src/android/permissionui/cts/usepermission/AccessBluetoothOnCommand.kt
new file mode 100644
index 000000000..b19f62362
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp30WithBluetooth/src/android/permissionui/cts/usepermission/AccessBluetoothOnCommand.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permissionui.cts.usepermission
+
+import android.bluetooth.BluetoothManager
+import android.bluetooth.le.BluetoothLeScanner
+import android.bluetooth.le.ScanCallback
+import android.bluetooth.le.ScanResult
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.content.Intent
+import android.database.Cursor
+import android.net.Uri
+import android.os.Bundle
+import android.os.SystemClock
+import android.util.Base64
+import android.util.Log
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.atomic.AtomicInteger
+
+private const val LOG_TAG = "AccessBluetoothOnCommand"
+
+class AccessBluetoothOnCommand : ContentProvider() {
+
+ private enum class Result {
+ UNKNOWN,
+ ERROR,
+ EXCEPTION,
+ EMPTY,
+ FILTERED,
+ FULL
+ }
+
+ override fun call(authority: String, method: String, arg: String?, extras: Bundle?): Bundle? {
+ Log.v(LOG_TAG, "call() - start")
+ val res = Bundle()
+
+ var scanner: BluetoothLeScanner? = null
+ var scanCallback: ScanCallback? = null
+
+ try {
+
+ scanner =
+ context!!
+ .getSystemService(BluetoothManager::class.java)
+ ?.adapter!!
+ .bluetoothLeScanner
+
+ val observedScans: MutableSet<String> = ConcurrentHashMap.newKeySet()
+ val observedErrorCode = AtomicInteger(0)
+
+ scanCallback =
+ object : ScanCallback() {
+ override fun onScanResult(callbackType: Int, result: ScanResult) {
+ Log.v(LOG_TAG, "onScanResult() - result = $result")
+ observedScans.add(Base64.encodeToString(result.scanRecord!!.bytes, 0))
+ }
+
+ override fun onBatchScanResults(results: List<ScanResult>) {
+ Log.v(LOG_TAG, "onBatchScanResults() - results.size = ${results.size}")
+ for (result in results) {
+ onScanResult(0, result)
+ }
+ }
+
+ override fun onScanFailed(errorCode: Int) {
+ Log.e(LOG_TAG, "onScanFailed() - errorCode = $errorCode")
+ observedErrorCode.set(errorCode)
+ }
+ }
+
+ Log.v(LOG_TAG, "call() - startScan...")
+ scanner.startScan(scanCallback)
+
+ // Wait a few seconds to figure out what we actually observed
+ Log.v(LOG_TAG, "call() - sleep...")
+ SystemClock.sleep(3000)
+
+ if (observedErrorCode.get() > 0) {
+ Log.v(LOG_TAG, "call() observed error: ${observedErrorCode.get()}")
+ res.putInt(Intent.EXTRA_INDEX, Result.ERROR.ordinal)
+ return res
+ }
+ Log.v(LOG_TAG, "call() - (scanCount=${observedScans.size})")
+
+ when (observedScans.size) {
+ 0 -> res.putInt(Intent.EXTRA_INDEX, Result.EMPTY.ordinal)
+ 1 -> res.putInt(Intent.EXTRA_INDEX, Result.FILTERED.ordinal)
+ 5 -> res.putInt(Intent.EXTRA_INDEX, Result.FULL.ordinal)
+ else -> res.putInt(Intent.EXTRA_INDEX, Result.UNKNOWN.ordinal)
+ }
+ } catch (t: Throwable) {
+ Log.e(LOG_TAG, "call() - EXCEPTION", t)
+ res.putInt(Intent.EXTRA_INDEX, Result.EXCEPTION.ordinal)
+ } finally {
+ try {
+ Log.v(LOG_TAG, "call() - finally - stopScan...")
+ scanner!!.stopScan(scanCallback)
+ } catch (e: Exception) {
+ Log.e(LOG_TAG, "call() - finally - EXCEPTION", e)
+ }
+ }
+ Log.v(LOG_TAG, "call() - end")
+ return res
+ }
+
+ override fun onCreate(): Boolean {
+ return true
+ }
+
+ override fun query(
+ uri: Uri,
+ projection: Array<String>?,
+ selection: String?,
+ selectionArgs: Array<String>?,
+ sortOrder: String?
+ ): Cursor? {
+ throw UnsupportedOperationException()
+ }
+
+ override fun getType(uri: Uri): String? {
+ throw UnsupportedOperationException()
+ }
+
+ override fun insert(uri: Uri, values: ContentValues?): Uri? {
+ throw UnsupportedOperationException()
+ }
+
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
+ throw UnsupportedOperationException()
+ }
+
+ override fun update(
+ uri: Uri,
+ values: ContentValues?,
+ selection: String?,
+ selectionArgs: Array<String>?
+ ): Int {
+ throw UnsupportedOperationException()
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionApp31/Android.bp b/tests/cts/permissionui/UsePermissionApp31/Android.bp
new file mode 100644
index 000000000..4424d95fe
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp31/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp31",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+ target_sdk_version: "31",
+ min_sdk_version: "31",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp31/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp31/AndroidManifest.xml
new file mode 100644
index 000000000..31d025ea0
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp31/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.BODY_SENSORS" />
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionApp32/Android.bp b/tests/cts/permissionui/UsePermissionApp32/Android.bp
new file mode 100644
index 000000000..874af0e06
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp32/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionApp32",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+
+ min_sdk_version: "32",
+ target_sdk_version: "32",
+}
diff --git a/tests/cts/permissionui/UsePermissionApp32/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp32/AndroidManifest.xml
new file mode 100644
index 000000000..923139e66
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionApp32/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+ <uses-permission android:name="android.permission.BODY_SENSORS" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application>
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionAppLatest/Android.bp b/tests/cts/permissionui/UsePermissionAppLatest/Android.bp
new file mode 100644
index 000000000..c9e9f8fb0
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLatest/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "CtsUsePermissionAppSrc",
+ srcs: [
+ "src/**/*.kt",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionAppLatest",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "30",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+}
diff --git a/tests/cts/permissionui/UsePermissionAppLatest/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionAppLatest/AndroidManifest.xml
new file mode 100644
index 000000000..49e45fc01
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLatest/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.BODY_SENSORS" />
+
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+ <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
+
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ <activity-alias
+ android:name=".ViewPermissionUsageActivity"
+ android:exported="true"
+ android:permission="android.permission.START_VIEW_PERMISSION_USAGE"
+ android:targetActivity=".FinishOnCreateActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW_PERMISSION_USAGE" />
+ </intent-filter>
+ </activity-alias>
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/CheckCalendarAccessActivity.kt b/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/CheckCalendarAccessActivity.kt
new file mode 100644
index 000000000..55fd104cb
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/CheckCalendarAccessActivity.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermission
+
+import android.app.Activity
+import android.content.ContentValues
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.provider.CalendarContract
+
+/** An activity that can check calendar access. */
+class CheckCalendarAccessActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val supportsRuntimePermissions = applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M
+ val hasAccess: Boolean
+ val uri =
+ try {
+ contentResolver.insert(
+ CalendarContract.Calendars.CONTENT_URI,
+ ContentValues().apply {
+ put(CalendarContract.Calendars.NAME, "cts" + System.nanoTime())
+ put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "cts")
+ put(CalendarContract.Calendars.CALENDAR_COLOR, 0xffff0000)
+ }
+ )!!
+ } catch (e: SecurityException) {
+ null
+ }
+ hasAccess =
+ if (uri != null) {
+ val count = contentResolver.query(uri, null, null, null).use { it!!.count }
+ if (supportsRuntimePermissions) {
+ assert(count == 1)
+ true
+ } else {
+ // Without access we're handed back a "fake" Uri that doesn't contain
+ // any of the data we tried persisting
+ assert(count == 0 || count == 1)
+ count == 1
+ }
+ } else {
+ assert(supportsRuntimePermissions)
+ try {
+ contentResolver
+ .query(CalendarContract.Calendars.CONTENT_URI, null, null, null)
+ .use {}
+ error("Expected SecurityException")
+ } catch (e: SecurityException) {}
+ false
+ }
+ setResult(RESULT_OK, Intent().apply { putExtra("$packageName.HAS_ACCESS", hasAccess) })
+ finish()
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/FinishOnCreateActivity.kt b/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/FinishOnCreateActivity.kt
new file mode 100644
index 000000000..693a8c8f9
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/FinishOnCreateActivity.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermission
+
+import android.app.Activity
+import android.os.Bundle
+
+class FinishOnCreateActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setResult(RESULT_OK)
+ finish()
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt b/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt
new file mode 100644
index 000000000..3eea77340
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLatest/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermission
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import com.android.modules.utils.build.SdkLevel
+
+class RequestPermissionsActivity : Activity() {
+
+ private var shouldAskTwice = false
+ private var timesAsked = 0
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ Log.w(TAG, "Activity was recreated. (Perhaps due to a configuration change?)")
+ return
+ }
+
+ val permissions = intent.getStringArrayExtra("$packageName.PERMISSIONS")!!
+ shouldAskTwice = intent.getBooleanExtra("$packageName.ASK_TWICE", false)
+ if (SdkLevel.isAtLeastV()) {
+ // TODO: make deviceId dynamic
+ requestPermissions(permissions, 1, Context.DEVICE_ID_DEFAULT)
+ } else {
+ requestPermissions(permissions, 1)
+ }
+ timesAsked = 1
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<out String>,
+ grantResults: IntArray
+ ) {
+ handleResult(permissions, grantResults)
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<out String>,
+ grantResults: IntArray,
+ deviceId: Int
+ ) {
+ handleResult(permissions, grantResults, deviceId)
+ }
+
+ private fun handleResult(
+ permissions: Array<out String>,
+ grantResults: IntArray,
+ deviceId: Int? = null
+ ) {
+ if (shouldAskTwice && timesAsked < 2) {
+ requestPermissions(permissions, 1)
+ timesAsked += 1
+ return
+ }
+
+ setResult(
+ RESULT_OK,
+ Intent().apply {
+ putExtra("$packageName.PERMISSIONS", permissions)
+ putExtra("$packageName.GRANT_RESULTS", grantResults)
+ if (deviceId != null) {
+ putExtra("$packageName.DEVICE_ID", deviceId)
+ }
+ }
+ )
+ finish()
+ }
+
+ companion object {
+ private val TAG = RequestPermissionsActivity::class.simpleName
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionAppLatestNone/Android.bp b/tests/cts/permissionui/UsePermissionAppLatestNone/Android.bp
new file mode 100644
index 000000000..cbc934eef
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLatestNone/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionAppLatestNone",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "30",
+ srcs: [
+ ":CtsUsePermissionAppSrc",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "compatibility-device-util-axt",
+ ],
+ certificate: ":cts-testkey2",
+}
diff --git a/tests/cts/permissionui/UsePermissionAppLatestNone/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionAppLatestNone/AndroidManifest.xml
new file mode 100644
index 000000000..49103769e
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLatestNone/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <application>
+ <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
+ <activity android:name=".FinishOnCreateActivity" android:exported="true" />
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionAppLocationProvider/Android.bp b/tests/cts/permissionui/UsePermissionAppLocationProvider/Android.bp
new file mode 100644
index 000000000..a2cd88d4e
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLocationProvider/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAccessMicrophoneAppLocationProvider",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "31",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+} \ No newline at end of file
diff --git a/tests/cts/permissionui/UsePermissionAppLocationProvider/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionAppLocationProvider/AndroidManifest.xml
new file mode 100644
index 000000000..03edc78a2
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLocationProvider/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.accessmicrophoneapplocationprovider">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <attribution
+ android:label="@string/attribution_label"
+ android:tag="test.tag" />
+
+ <application
+ android:attributionsAreUserVisible="true"
+ android:label="LocationProviderWithMicApp">
+ <activity android:name=".AddLocationProviderActivity" android:exported="true" />
+ <activity android:name=".UseMicrophoneActivity" android:exported="true"/>
+ </application>
+</manifest>
diff --git a/PermissionController/res/values-w764dp-v33/dimens.xml b/tests/cts/permissionui/UsePermissionAppLocationProvider/res/values/strings.xml
index 78b4675f2..9682d7f8a 100644
--- a/PermissionController/res/values-w764dp-v33/dimens.xml
+++ b/tests/cts/permissionui/UsePermissionAppLocationProvider/res/values/strings.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,5 +17,5 @@
-->
<resources>
- <dimen name="sc_button_horizontal_padding">@dimen/sc_large_screen_button_padding</dimen>
+ <string name="attribution_label">Attribution Label</string>
</resources>
diff --git a/tests/cts/permissionui/UsePermissionAppLocationProvider/src/android/permissionui/cts/accessmicrophoneapplocationprovider/AddLocationProviderActivity.kt b/tests/cts/permissionui/UsePermissionAppLocationProvider/src/android/permissionui/cts/accessmicrophoneapplocationprovider/AddLocationProviderActivity.kt
new file mode 100644
index 000000000..b4bd16f05
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLocationProvider/src/android/permissionui/cts/accessmicrophoneapplocationprovider/AddLocationProviderActivity.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permissionui.cts.accessmicrophoneapplocationprovider
+
+import android.app.Activity
+import android.location.Criteria
+import android.location.LocationManager
+import android.os.Bundle
+
+/** An activity that adds this package as a test location provider and uses microphone. */
+class AddLocationProviderActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val attrContext = createAttributionContext("test.tag")
+ val locationManager = attrContext.getSystemService(LocationManager::class.java)!!
+ locationManager.addTestProvider(
+ packageName,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ Criteria.POWER_LOW,
+ Criteria.ACCURACY_COARSE
+ )
+
+ setResult(RESULT_OK)
+ finish()
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionAppLocationProvider/src/android/permissionui/cts/accessmicrophoneapplocationprovider/UseMicrophoneActivity.kt b/tests/cts/permissionui/UsePermissionAppLocationProvider/src/android/permissionui/cts/accessmicrophoneapplocationprovider/UseMicrophoneActivity.kt
new file mode 100644
index 000000000..897949b95
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppLocationProvider/src/android/permissionui/cts/accessmicrophoneapplocationprovider/UseMicrophoneActivity.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permissionui.cts.accessmicrophoneapplocationprovider
+
+import android.app.Activity
+import android.content.Context
+import android.media.AudioFormat
+import android.media.AudioRecord
+import android.media.MediaRecorder
+import android.os.Bundle
+import android.os.Handler
+
+private const val USE_DURATION_MS = 10000L
+private const val SAMPLE_RATE_HZ = 44100
+
+/** An activity that uses microphone. */
+class UseMicrophoneActivity : Activity() {
+ private var recorder: AudioRecord? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val attrContext = createAttributionContext("test.tag")
+ useMic(attrContext)
+ setResult(RESULT_OK)
+ finish()
+ }
+
+ override fun finish() {
+ recorder?.stop()
+ recorder = null
+ super.finish()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ finish()
+ }
+
+ private fun useMic(context: Context) {
+ recorder =
+ AudioRecord.Builder()
+ .setAudioSource(MediaRecorder.AudioSource.MIC)
+ .setAudioFormat(
+ AudioFormat.Builder()
+ .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ .setSampleRate(SAMPLE_RATE_HZ)
+ .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
+ .build()
+ )
+ .setContext(context)
+ .build()
+ recorder?.startRecording()
+ Handler().postDelayed({ finish() }, USE_DURATION_MS)
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionAppWithOverlay/Android.bp b/tests/cts/permissionui/UsePermissionAppWithOverlay/Android.bp
new file mode 100644
index 000000000..6ae324577
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppWithOverlay/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsUsePermissionAppWithOverlay",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "30",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+ certificate: ":cts-testkey2",
+}
diff --git a/tests/cts/permissionui/UsePermissionAppWithOverlay/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionAppWithOverlay/AndroidManifest.xml
new file mode 100644
index 000000000..037ff548f
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppWithOverlay/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permissionui.cts.usepermission">
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <application>
+ <activity android:name=".RequestPermissionsActivity" android:exported="true" />
+ <activity android:name=".OverlayActivity"
+ android:theme="@style/OverlayTheme" />
+ </application>
+</manifest>
diff --git a/tests/cts/permissionui/UsePermissionAppWithOverlay/res/drawable/border.xml b/tests/cts/permissionui/UsePermissionAppWithOverlay/res/drawable/border.xml
new file mode 100644
index 000000000..1e637be61
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppWithOverlay/res/drawable/border.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#FFFFFF" />
+ <corners
+ android:radius="4dp"/>
+ <stroke
+ android:width="4dp"
+ android:color="@android:color/black" />
+</shape>
diff --git a/tests/cts/permissionui/UsePermissionAppWithOverlay/res/layout/overlay_activity.xml b/tests/cts/permissionui/UsePermissionAppWithOverlay/res/layout/overlay_activity.xml
new file mode 100644
index 000000000..ea355f761
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppWithOverlay/res/layout/overlay_activity.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/overlay"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/border"
+ android:padding="8dp" >
+
+ <View android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <TextView android:id="@+id/overlay_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:text="@string/app_description" />
+</LinearLayout> \ No newline at end of file
diff --git a/tests/cts/permissionui/UsePermissionAppWithOverlay/res/values/strings.xml b/tests/cts/permissionui/UsePermissionAppWithOverlay/res/values/strings.xml
new file mode 100644
index 000000000..ca0b4ffc1
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppWithOverlay/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_description">This activity attempts to tapjack the activity below.\nAny security sensitive controls below should not respond to taps as long as this activity is visible.</string>
+</resources> \ No newline at end of file
diff --git a/tests/cts/permissionui/UsePermissionAppWithOverlay/res/values/styles.xml b/tests/cts/permissionui/UsePermissionAppWithOverlay/res/values/styles.xml
new file mode 100644
index 000000000..880d94037
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppWithOverlay/res/values/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2020 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <style name="OverlayTheme" parent="android:Theme.Dialog">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ </style>
+</resources>
diff --git a/tests/cts/permissionui/UsePermissionAppWithOverlay/src/android/permissionui/cts/usepermission/OverlayActivity.kt b/tests/cts/permissionui/UsePermissionAppWithOverlay/src/android/permissionui/cts/usepermission/OverlayActivity.kt
new file mode 100644
index 000000000..bcd5496dc
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppWithOverlay/src/android/permissionui/cts/usepermission/OverlayActivity.kt
@@ -0,0 +1,60 @@
+package android.permissionui.cts.usepermission
+
+import android.app.Activity
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Bundle
+import android.view.Gravity
+import android.view.WindowManager
+
+class OverlayActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.overlay_activity)
+ val params = window.attributes
+ params.flags =
+ (WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
+ WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
+
+ if (!intent.getBooleanExtra(EXTRA_FULL_OVERLAY, true)) {
+ params.gravity = Gravity.LEFT or Gravity.TOP
+ val left = intent.getIntExtra(OVERLAY_LEFT, params.x)
+ val top = intent.getIntExtra(OVERLAY_TOP, params.y)
+ val right = intent.getIntExtra(OVERLAY_RIGHT, params.x + params.width)
+ val bottom = intent.getIntExtra(OVERLAY_BOTTOM, top + 1)
+ params.x = left
+ params.y = top
+ params.width = right - left
+ params.height = bottom - top
+ }
+
+ registerReceiver(
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (intent?.action != RequestPermissionsActivity.ACTION_HIDE_OVERLAY) {
+ return
+ }
+
+ finish()
+ }
+ },
+ IntentFilter(RequestPermissionsActivity.ACTION_HIDE_OVERLAY),
+ RECEIVER_EXPORTED
+ )
+ }
+
+ companion object {
+ const val EXTRA_FULL_OVERLAY = "android.permissionui.cts.usepermission.extra.FULL_OVERLAY"
+
+ const val OVERLAY_LEFT = "android.permissionui.cts.usepermission.extra.OVERLAY_LEFT"
+ const val OVERLAY_TOP = "android.permissionui.cts.usepermission.extra.OVERLAY_TOP"
+ const val OVERLAY_RIGHT = "android.permissionui.cts.usepermission.extra.OVERLAY_RIGHT"
+ const val OVERLAY_BOTTOM = "android.permissionui.cts.usepermission.extra.OVERLAY_BOTTOM"
+ }
+}
diff --git a/tests/cts/permissionui/UsePermissionAppWithOverlay/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt b/tests/cts/permissionui/UsePermissionAppWithOverlay/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt
new file mode 100644
index 000000000..c13a02392
--- /dev/null
+++ b/tests/cts/permissionui/UsePermissionAppWithOverlay/src/android/permissionui/cts/usepermission/RequestPermissionsActivity.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts.usepermission
+
+import android.app.Activity
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Bundle
+import android.os.Handler
+import android.util.Log
+
+class RequestPermissionsActivity : Activity() {
+
+ var paused = false
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ Log.w(TAG, "Activity was recreated. (Perhaps due to a configuration change?)")
+ return
+ }
+
+ registerReceiver(
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (intent?.action != ACTION_SHOW_OVERLAY) {
+ return
+ }
+
+ startActivity(
+ intent
+ .setAction(null)
+ .setComponent(ComponentName(context!!, OverlayActivity::class.java))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ )
+ }
+ },
+ IntentFilter(ACTION_SHOW_OVERLAY),
+ RECEIVER_EXPORTED
+ )
+ Handler(mainLooper).post(this::eventuallyRequestPermission)
+ }
+
+ /**
+ * Keep trying to requestPermissions until the dialog shows. It may fail the first few times due
+ * to rapid install/uninstall tests do
+ */
+ private fun eventuallyRequestPermission() {
+ if (!paused) {
+ val permissions = intent.getStringArrayExtra("$packageName.PERMISSIONS")!!
+ requestPermissions(permissions, 1)
+ Handler(mainLooper).postDelayed(this::eventuallyRequestPermission, 200)
+ }
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<out String>,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+
+ setResult(
+ RESULT_OK,
+ Intent().apply {
+ putExtra("$packageName.PERMISSIONS", permissions)
+ putExtra("$packageName.GRANT_RESULTS", grantResults)
+ }
+ )
+ finish()
+ }
+
+ override fun onPause() {
+ paused = true
+ super.onPause()
+ }
+
+ override fun onResume() {
+ paused = false
+ super.onResume()
+ }
+
+ companion object {
+ const val ACTION_SHOW_OVERLAY = "android.permissionui.cts.usepermission.ACTION_SHOW_OVERLAY"
+ const val ACTION_HIDE_OVERLAY = "android.permissionui.cts.usepermission.ACTION_HIDE_OVERLAY"
+ private val TAG = RequestPermissionsActivity::class.simpleName
+ }
+}
diff --git a/tests/cts/permissionui/res/raw/lg_g4_iso_800_jpg.jpg b/tests/cts/permissionui/res/raw/lg_g4_iso_800_jpg.jpg
new file mode 100644
index 000000000..d26419604
--- /dev/null
+++ b/tests/cts/permissionui/res/raw/lg_g4_iso_800_jpg.jpg
Binary files differ
diff --git a/tests/cts/permissionui/res/raw/test_video.mp4 b/tests/cts/permissionui/res/raw/test_video.mp4
new file mode 100644
index 000000000..ab95ac07d
--- /dev/null
+++ b/tests/cts/permissionui/res/raw/test_video.mp4
Binary files differ
diff --git a/PermissionController/res/values-w764dp-v34/dimens.xml b/tests/cts/permissionui/res/values-en-rGB/strings.xml
index cb336fc3e..7c98df768 100644..100755
--- a/PermissionController/res/values-w764dp-v34/dimens.xml
+++ b/tests/cts/permissionui/res/values-en-rGB/strings.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2017 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,5 +17,5 @@
-->
<resources>
- <dimen name="sc_action_button_list_margin">@dimen/sc_spacing_large</dimen>
+ <string name="permissions">Permission</string>
</resources>
diff --git a/tests/cts/permissionui/res/values/strings.xml b/tests/cts/permissionui/res/values/strings.xml
new file mode 100755
index 000000000..b2f8e3dac
--- /dev/null
+++ b/tests/cts/permissionui/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <string name="permissions">Permissions</string>
+ <string name="allow_foreground">Allow only while using the app</string>
+ <string name="allow_media_storage">Allow access to media only</string>
+ <string name="allow_external_storage">Allow management of all files</string>
+ <string name="car_mic_privacy_chip_id">com.android.systemui:id/mic_privacy_chip</string>
+ <string name="car_camera_privacy_chip_id">com.android.systemui:id/camera_privacy_chip</string>
+ <string name="test_accessibility_service">TestService1</string>
+ <string name="test_accessibility_service_2">TestService2</string>
+</resources>
diff --git a/tests/cts/permissionui/res/xml/test_accessibilityservice.xml b/tests/cts/permissionui/res/xml/test_accessibilityservice.xml
new file mode 100644
index 000000000..fa87e2e0f
--- /dev/null
+++ b/tests/cts/permissionui/res/xml/test_accessibilityservice.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accessibilityEventTypes="typeAllMask"
+ android:accessibilityFeedbackType="feedbackGeneric"
+ android:canRetrieveWindowContent="true"
+ android:accessibilityFlags="flagDefault"
+ android:notificationTimeout="0" />
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/AppDataSharingUpdatesTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/AppDataSharingUpdatesTest.kt
new file mode 100644
index 000000000..cd002ebfc
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/AppDataSharingUpdatesTest.kt
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.ActivityManager
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_OTHER
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_STORE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED
+import android.os.Build
+import android.os.PersistableBundle
+import android.permission.cts.PermissionUtils
+import android.permissionui.cts.AppMetadata.createAppMetadataWithLocationSharingAds
+import android.permissionui.cts.AppMetadata.createAppMetadataWithLocationSharingNoAds
+import android.permissionui.cts.AppMetadata.createAppMetadataWithNoSharing
+import android.provider.DeviceConfig
+import android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED
+import android.util.Log
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.waitForBroadcasts
+import com.android.modules.utils.build.SdkLevel
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+/** Tests the UI that displays information about apps' updates to their data sharing policies. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@FlakyTest
+class AppDataSharingUpdatesTest : BaseUsePermissionTest() {
+ // TODO(b/263838456): Add tests for personal and work profile.
+
+ private var activityManager: ActivityManager? = null
+
+ @get:Rule
+ val deviceConfigSafetyLabelChangeNotificationsEnabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED,
+ true.toString()
+ )
+
+ @get:Rule
+ val deviceConfigDataSharingUpdatesPeriod =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_DATA_SHARING_UPDATE_PERIOD_MILLIS,
+ "600000"
+ )
+
+ /**
+ * This rule serves to limit the max number of safety labels that can be persisted, so that
+ * repeated tests don't overwhelm the disk storage on the device.
+ */
+ @get:Rule
+ val deviceConfigMaxSafetyLabelsPersistedPerApp =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP,
+ "2"
+ )
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(
+ "Data sharing updates page is only available on U+",
+ SdkLevel.isAtLeastU()
+ )
+ Assume.assumeFalse(isAutomotive)
+ Assume.assumeFalse(isTv)
+ Assume.assumeFalse(isWatch)
+
+ PermissionUtils.clearAppState(context.packageManager.permissionControllerPackageName)
+ waitForBroadcasts()
+ activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedCoarseLocation_noSharingToNoAdsSharing_showsUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ grantCoarseLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+ findView(By.textContains(NOW_SHARED_WITH_THIRD_PARTIES), true)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedFineLocation_showsUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ grantFineLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+ findView(By.textContains(NOW_SHARED_WITH_THIRD_PARTIES), true)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedBackgroundLocation_showsUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ grantBackgroundLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+ findView(By.textContains(NOW_SHARED_WITH_THIRD_PARTIES), true)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_noSharingToAdsSharing_showsUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithLocationSharingAds())
+ grantCoarseLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+ findView(By.textContains(NOW_SHARED_WITH_THIRD_PARTIES_FOR_ADS), true)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_noAdsSharingToAdsSharing_showsUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithLocationSharingAds())
+ grantCoarseLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+ findView(By.textContains(NOW_SHARED_WITH_THIRD_PARTIES_FOR_ADS), true)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_adsSharingToNoAdsSharing_showsNoUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingAds(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ grantCoarseLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertNoUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), false)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_noAdsSharingToNoSharing_showsNoUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ grantCoarseLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertNoUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), false)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_adsSharingToNoSharing_showsNoUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingAds(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ grantCoarseLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertNoUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), false)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Ignore("b/282063206")
+ @Test
+ fun clickLearnMore_opensHelpCenter() {
+ Assume.assumeFalse(getPermissionControllerResString(HELP_CENTER_URL_ID).isNullOrEmpty())
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ findView(By.descContains(DATA_SHARING_UPDATES), true)
+ findView(By.textContains(LEARN_ABOUT_DATA_SHARING), true)
+
+ clickAndWaitForWindowTransition(By.textContains(LEARN_ABOUT_DATA_SHARING))
+
+ eventually({ assertHelpCenterLinkClickSuccessful() }, HELP_CENTER_TIMEOUT_MILLIS)
+ } finally {
+ pressBack()
+ pressBack()
+ }
+ }
+
+ @Test
+ fun noHelpCenterLinkAvailable_noHelpCenterClickAction() {
+ Assume.assumeTrue(getPermissionControllerResString(HELP_CENTER_URL_ID).isNullOrEmpty())
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ findView(By.descContains(DATA_SHARING_UPDATES), true)
+ findView(By.textContains(LEARN_ABOUT_DATA_SHARING), false)
+ } finally {
+ pressBack()
+ pressBack()
+ }
+ }
+
+ @Test
+ fun clickUpdate_opensAppLocationPermissionPage() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ grantFineLocationPermission(APP_PACKAGE_NAME)
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ findView(By.descContains(DATA_SHARING_UPDATES), true)
+ findView(By.textContains(UPDATES_IN_LAST_30_DAYS), true)
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+
+ clickAndWaitForWindowTransition(By.textContains(APP_PACKAGE_NAME_SUBSTRING))
+
+ findView(By.descContains(LOCATION_PERMISSION), true)
+ findView(By.textContains(APP_PACKAGE_NAME), true)
+ } finally {
+ pressBack()
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppNotGrantedLocation_showsNoUpdates() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertNoUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), false)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_noMetadata_showsNoUpdates() {
+ installPackageWithoutInstallSource(APP_APK_PATH_31)
+ waitForBroadcasts()
+ installPackageWithoutInstallSource(APP_APK_PATH_31)
+ waitForBroadcasts()
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertNoUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), false)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_featureDisabled_doesNotOpenDataSharingUpdatesPage() {
+ setDeviceConfigPrivacyProperty(SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false.toString())
+
+ startAppDataSharingUpdatesActivity()
+
+ findView(By.descContains(DATA_SHARING_UPDATES), false)
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedFineLocation_packageSourceUnspecified_showsUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_UNSPECIFIED,
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_UNSPECIFIED
+ )
+ grantFineLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+ findView(By.textContains(NOW_SHARED_WITH_THIRD_PARTIES), true)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_packageSourceOther_doesntShowUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_OTHER,
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_OTHER
+ )
+ grantFineLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertNoUpdatesPresent()
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_packageSourceStore_showsUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_STORE,
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_STORE
+ )
+ grantFineLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertUpdatesPresent()
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+ findView(By.textContains(NOW_SHARED_WITH_THIRD_PARTIES), true)
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_packageSourceLocalFile_doesntShowUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_LOCAL_FILE,
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_LOCAL_FILE
+ )
+ grantFineLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertNoUpdatesPresent()
+ } finally {
+ pressBack()
+ }
+ }
+
+ @Test
+ fun startActivityWithIntent_whenAppGrantedLocation_packageSourceDownloaded_doesntShowUpdate() {
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_DOWNLOADED_FILE,
+ waitTillBroadcastProcessed = true
+ )
+ installAndWaitTillPackageAdded(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_DOWNLOADED_FILE
+ )
+ grantFineLocationPermission(APP_PACKAGE_NAME)
+
+ startAppDataSharingUpdatesActivity()
+
+ try {
+ assertNoUpdatesPresent()
+ } finally {
+ pressBack()
+ }
+ }
+
+ /** Installs an app and waits for the package added broadcast to be dispatched. */
+ private fun installAndWaitTillPackageAdded(
+ apkPath: String,
+ appMetadata: PersistableBundle,
+ packageSource: Int? = null,
+ waitTillBroadcastProcessed: Boolean = false
+ ) {
+ installPackageViaSession(apkPath, appMetadata, packageSource)
+ waitForBroadcasts()
+ // TODO(b/279455955): Investigate why this is necessary and remove if possible.
+ if (waitTillBroadcastProcessed) Thread.sleep(500)
+ }
+
+ private fun assertUpdatesPresent() {
+ findView(By.descContains(DATA_SHARING_UPDATES), true)
+ findView(By.textContains(DATA_SHARING_UPDATES_SUBTITLE), true)
+ findView(By.textContains(UPDATES_IN_LAST_30_DAYS), true)
+ findView(By.textContains(DATA_SHARING_UPDATES_FOOTER_MESSAGE), true)
+ findView(By.textContains(LEARN_ABOUT_DATA_SHARING), shouldShowLearnMoreLink())
+ }
+
+ private fun assertNoUpdatesPresent() {
+ findView(By.descContains(DATA_SHARING_UPDATES), true)
+ findView(By.textContains(DATA_SHARING_UPDATES_SUBTITLE), true)
+ findView(By.textContains(DATA_SHARING_NO_UPDATES_MESSAGE), true)
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), false)
+ findView(By.textContains(UPDATES_IN_LAST_30_DAYS), false)
+ findView(By.textContains(DATA_SHARING_UPDATES_FOOTER_MESSAGE), true)
+ findView(By.textContains(LEARN_ABOUT_DATA_SHARING), shouldShowLearnMoreLink())
+ }
+
+ private fun grantFineLocationPermission(packageName: String) {
+ uiAutomation.grantRuntimePermission(
+ packageName,
+ android.Manifest.permission.ACCESS_FINE_LOCATION
+ )
+ }
+ private fun grantCoarseLocationPermission(packageName: String) {
+ uiAutomation.grantRuntimePermission(
+ packageName,
+ android.Manifest.permission.ACCESS_COARSE_LOCATION
+ )
+ }
+ private fun grantBackgroundLocationPermission(packageName: String) {
+ uiAutomation.grantRuntimePermission(
+ packageName,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
+ )
+ }
+
+ private fun assertHelpCenterLinkClickSuccessful() {
+ runWithShellPermissionIdentity {
+ val runningTasks = activityManager!!.getRunningTasks(5)
+
+ Log.v(TAG, "# running tasks: ${runningTasks.size}")
+ assertFalse("Expected runningTasks to not be empty", runningTasks.isEmpty())
+
+ runningTasks.forEachIndexed { index, runningTaskInfo ->
+ Log.v(TAG, "task $index ${runningTaskInfo.baseIntent}")
+ }
+
+ val taskInfo = runningTasks[0]
+ val observedIntentAction = taskInfo.baseIntent.action
+ val observedIntentDataString = taskInfo.baseIntent.dataString
+ val observedIntentScheme: String? = taskInfo.baseIntent.scheme
+
+ Log.v(TAG, "task base intent: ${taskInfo.baseIntent}")
+ assertEquals("Unexpected intent action", Intent.ACTION_VIEW, observedIntentAction)
+
+ val expectedUrl = getPermissionControllerResString(HELP_CENTER_URL_ID)!!
+ assertFalse(observedIntentDataString.isNullOrEmpty())
+ assertTrue(observedIntentDataString?.startsWith(expectedUrl) ?: false)
+
+ assertFalse(observedIntentScheme.isNullOrEmpty())
+ assertEquals("https", observedIntentScheme)
+ }
+ }
+
+ private fun shouldShowLearnMoreLink(): Boolean {
+ return !getPermissionControllerResString(HELP_CENTER_URL_ID).isNullOrEmpty()
+ }
+
+ /** Companion object for [AppDataSharingUpdatesTest]. */
+ companion object {
+ private val TAG = AppDataSharingUpdatesTest::class.java.simpleName
+
+ private const val HELP_CENTER_URL_ID = "data_sharing_help_center_link"
+ private const val HELP_CENTER_TIMEOUT_MILLIS: Long = 20000
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/AppMetadata.kt b/tests/cts/permissionui/src/android/permissionui/cts/AppMetadata.kt
new file mode 100644
index 000000000..8c61f0366
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/AppMetadata.kt
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.os.PersistableBundle
+
+/** Helper methods for creating test app metadata [PersistableBundle] */
+object AppMetadata {
+ /** Returns empty App Metadata [PersistableBundle] representation */
+ fun createEmptyAppMetadata(): PersistableBundle {
+ return PersistableBundle()
+ }
+
+ /** Returns valid App Metadata [PersistableBundle] representation */
+ fun createDefaultAppMetadata(): PersistableBundle {
+ val approximateLocationBundle =
+ PersistableBundle().apply { putIntArray(KEY_PURPOSES, (1..7).toList().toIntArray()) }
+
+ val locationBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(APPROX_LOCATION, approximateLocationBundle)
+ }
+
+ val dataSharedBundle =
+ PersistableBundle().apply { putPersistableBundle(LOCATION_CATEGORY, locationBundle) }
+
+ val dataLabelBundle =
+ PersistableBundle().apply { putPersistableBundle(KEY_DATA_SHARED, dataSharedBundle) }
+
+ val safetyLabelBundle =
+ PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_SAFETY_LABELS_VERSION)
+ putPersistableBundle(KEY_DATA_LABELS, dataLabelBundle)
+ }
+
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_TOP_LEVEL_VERSION)
+ putPersistableBundle(KEY_SAFETY_LABELS, safetyLabelBundle)
+ }
+ }
+
+ /**
+ * Returns invalid App Metadata [PersistableBundle] representation. Invalidity due to invalid
+ * label name usage
+ */
+ fun createInvalidAppMetadata(): PersistableBundle {
+ val validAppMetaData = createDefaultAppMetadata()
+ val validSafetyLabel = validAppMetaData.getPersistableBundle(KEY_SAFETY_LABELS)
+
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_TOP_LEVEL_VERSION)
+ putPersistableBundle(KEY_INVALID, validSafetyLabel)
+ }
+ }
+
+ /**
+ * Returns invalid App Metadata [PersistableBundle] representation. Invalidity due to no top
+ * level meta data version number.
+ */
+ fun createInvalidAppMetadataWithoutTopLevelVersion(): PersistableBundle {
+ val validAppMetaData = createDefaultAppMetadata()
+ val validSafetyLabel = validAppMetaData.getPersistableBundle(KEY_SAFETY_LABELS)
+
+ return PersistableBundle().apply {
+ putPersistableBundle(KEY_SAFETY_LABELS, validSafetyLabel)
+ }
+ }
+
+ /**
+ * Returns invalid App Metadata [PersistableBundle] representation. Invalidity due to invalid
+ * top level meta data version number.
+ */
+ fun createInvalidAppMetadataWithInvalidTopLevelVersion(): PersistableBundle {
+ val validAppMetaData = createDefaultAppMetadata()
+ val validSafetyLabel = validAppMetaData.getPersistableBundle(KEY_SAFETY_LABELS)
+
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, INVALID_TOP_LEVEL_VERSION)
+ putPersistableBundle(KEY_SAFETY_LABELS, validSafetyLabel)
+ }
+ }
+
+ /**
+ * Returns invalid App Metadata [PersistableBundle] representation. Invalidity due to no safety
+ * label version number.
+ */
+ fun createInvalidAppMetadataWithoutSafetyLabelVersion(): PersistableBundle {
+ val validAppMetaData = createDefaultAppMetadata()
+ val invalidSafetyLabel =
+ validAppMetaData.getPersistableBundle(KEY_SAFETY_LABELS).apply {
+ this?.remove(KEY_VERSION)
+ }
+
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_TOP_LEVEL_VERSION)
+ putPersistableBundle(KEY_SAFETY_LABELS, invalidSafetyLabel)
+ }
+ }
+
+ /**
+ * Returns invalid App Metadata [PersistableBundle] representation. Invalidity due to invalid
+ * safety label version number.
+ */
+ fun createInvalidAppMetadataWithInvalidSafetyLabelVersion(): PersistableBundle {
+ val validAppMetaData = createDefaultAppMetadata()
+ val invalidSafetyLabel =
+ validAppMetaData.getPersistableBundle(KEY_SAFETY_LABELS)?.apply {
+ putLong(KEY_VERSION, INVALID_SAFETY_LABELS_VERSION)
+ }
+
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_TOP_LEVEL_VERSION)
+ putPersistableBundle(KEY_SAFETY_LABELS, invalidSafetyLabel)
+ }
+ }
+ /** Returns an App Metadata [PersistableBundle] representation where no data is shared. */
+ fun createAppMetadataWithNoSharing(): PersistableBundle {
+ return createMetadataWithDataShared(PersistableBundle())
+ }
+
+ /**
+ * Returns an App Metadata [PersistableBundle] representation where location data is shared, but
+ * not for advertising purpose.
+ */
+ fun createAppMetadataWithLocationSharingNoAds(): PersistableBundle {
+ val locationBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(
+ APPROX_LOCATION,
+ PersistableBundle().apply {
+ putIntArray(
+ KEY_PURPOSES,
+ listOf(PURPOSE_FRAUD_PREVENTION_SECURITY).toIntArray()
+ )
+ }
+ )
+ }
+
+ val dataSharedBundle =
+ PersistableBundle().apply { putPersistableBundle(LOCATION_CATEGORY, locationBundle) }
+
+ return createMetadataWithDataShared(dataSharedBundle)
+ }
+
+ /**
+ * Returns an App Metadata [PersistableBundle] representation where location data is shared,
+ * including for advertising purpose.
+ */
+ fun createAppMetadataWithLocationSharingAds(): PersistableBundle {
+ val locationBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(
+ APPROX_LOCATION,
+ PersistableBundle().apply {
+ putIntArray(KEY_PURPOSES, listOf(PURPOSE_ADVERTISING).toIntArray())
+ }
+ )
+ }
+
+ val dataSharedBundle =
+ PersistableBundle().apply { putPersistableBundle(LOCATION_CATEGORY, locationBundle) }
+
+ return createMetadataWithDataShared(dataSharedBundle)
+ }
+
+ private fun createMetadataWithDataShared(
+ dataSharedBundle: PersistableBundle
+ ): PersistableBundle {
+ val dataLabelBundle =
+ PersistableBundle().apply { putPersistableBundle(KEY_DATA_SHARED, dataSharedBundle) }
+
+ val safetyLabelBundle =
+ PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_SAFETY_LABELS_VERSION)
+ putPersistableBundle(KEY_DATA_LABELS, dataLabelBundle)
+ }
+
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, INITIAL_TOP_LEVEL_VERSION)
+ putPersistableBundle(KEY_SAFETY_LABELS, safetyLabelBundle)
+ }
+ }
+
+ private const val INITIAL_SAFETY_LABELS_VERSION = 1L
+ private const val INITIAL_TOP_LEVEL_VERSION = 1L
+ private const val INVALID_SAFETY_LABELS_VERSION = -1L
+ private const val INVALID_TOP_LEVEL_VERSION = 0L
+
+ private const val LOCATION_CATEGORY = "location"
+ private const val APPROX_LOCATION = "approx_location"
+ private const val PURPOSE_FRAUD_PREVENTION_SECURITY = 4
+ private const val PURPOSE_ADVERTISING = 5
+
+ private const val KEY_VERSION = "version"
+ private const val KEY_SAFETY_LABELS = "safety_labels"
+ private const val KEY_INVALID = "invalid_safety_labels"
+ private const val KEY_DATA_SHARED = "data_shared"
+ private const val KEY_DATA_LABELS = "data_labels"
+ private const val KEY_PURPOSES = "purposes"
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt
new file mode 100644
index 000000000..99fed6b79
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.os.Build
+import android.provider.DeviceConfig
+import android.provider.Settings
+import android.provider.Settings.Secure.USER_SETUP_COMPLETE
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule
+import com.android.modules.utils.build.SdkLevel
+import com.google.common.truth.Truth
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+/** App Permission page UI tests. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@FlakyTest
+class AppPermissionTest : BaseUsePermissionTest() {
+
+ @get:Rule
+ val deviceConfigPermissionRationaleEnabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PERMISSION_RATIONALE_ENABLED,
+ true.toString()
+ )
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue("Permission rationale is only available on U+", SdkLevel.isAtLeastU())
+ Assume.assumeFalse(isAutomotive)
+ Assume.assumeFalse(isTv)
+ Assume.assumeFalse(isWatch)
+
+ val userSetupComplete =
+ Settings.Secure.getInt(context.contentResolver, USER_SETUP_COMPLETE, 0) == 1
+
+ Truth.assertWithMessage("User setup must be complete before running this test")
+ .that(userSetupComplete)
+ .isTrue()
+ }
+
+ @Test
+ fun showPermissionRationaleContainer_withInstallSourceAndMetadata_packageSourceUnspecified() {
+ // Unspecified is the default, so no need to explicitly set it
+ installPackageWithInstallSourceAndMetadata(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(true)
+
+ clickPermissionRationaleContentInAppPermission()
+ assertPermissionRationaleDialogIsVisible(expected = true, showSettingsSection = false)
+ }
+
+ @Test
+ fun showPermissionRationaleContainer_withInstallSourceAndMetadata_packageSourceStore() {
+ installPackageWithInstallSourceAndMetadataFromStore(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(true)
+
+ clickPermissionRationaleContentInAppPermission()
+ assertPermissionRationaleDialogIsVisible(expected = true, showSettingsSection = false)
+ }
+
+ @Test
+ fun showPermissionRationaleContainer_withInstallSourceAndMetadata_packageSourceLocalFile() {
+ installPackageWithInstallSourceAndMetadataFromLocalFile(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun showPermissionRationaleContainer_withInstallSourceAndMetadata_packageSourceDownloadedFile() {
+ installPackageWithInstallSourceAndMetadataFromDownloadedFile(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun showPermissionRationaleContainer_withInstallSourceAndMetadata_packageSourceOther() {
+ installPackageWithInstallSourceAndMetadataFromOther(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withInstallSourceAndNoMetadata() {
+ installPackageWithInstallSourceAndNoMetadata(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withInstallSourceAndNullMetadata() {
+ installPackageWithInstallSourceAndNoMetadata(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withInstallSourceAndEmptyMetadata() {
+ installPackageWithInstallSourceAndEmptyMetadata(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withInstallSourceAndInvalidMetadata() {
+ installPackageWithInstallSourceAndInvalidMetadata(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withInstallSourceAndMetadataWithoutTopLevelVersion() {
+ installPackageWithInstallSourceAndMetadataWithoutTopLevelVersion(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withInstallSourceAndMetadataWithInvalidTopLevelVersion() {
+ installPackageWithInstallSourceAndMetadataWithInvalidTopLevelVersion(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withInstallSourceAndMetadataWithoutSafetyLabelVersion() {
+ installPackageWithInstallSourceAndMetadataWithoutSafetyLabelVersion(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withInstallSourceAndMetadataWithInvalidSafetyLabelVersion() {
+ installPackageWithInstallSourceAndMetadataWithInvalidSafetyLabelVersion(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withOutInstallSource() {
+ installPackageWithoutInstallSource(APP_APK_PATH_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ @Test
+ fun noShowPermissionRationaleContainer_withoutMetadata() {
+ installPackageWithInstallSourceAndNoMetadata(APP_APK_NAME_31)
+
+ navigateToIndividualPermissionSetting(ACCESS_COARSE_LOCATION)
+
+ assertAppPermissionRationaleContainerIsVisible(false)
+ }
+
+ private fun assertAppPermissionRationaleContainerIsVisible(expected: Boolean) {
+ findView(By.res(APP_PERMISSION_RATIONALE_CONTAINER_VIEW), expected)
+ }
+
+ companion object {
+ private const val PERMISSION_RATIONALE_ENABLED = "permission_rationale_enabled"
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt
new file mode 100644
index 000000000..6f80ea5d6
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.Instrumentation
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_MUTABLE
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.app.UiAutomation
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Context.RECEIVER_EXPORTED
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageInstaller
+import android.content.pm.PackageInstaller.EXTRA_STATUS
+import android.content.pm.PackageInstaller.EXTRA_STATUS_MESSAGE
+import android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID
+import android.content.pm.PackageInstaller.STATUS_SUCCESS
+import android.content.pm.PackageInstaller.SessionParams
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import android.os.PersistableBundle
+import android.os.SystemClock
+import android.platform.test.rule.ScreenRecordRule
+import android.provider.DeviceConfig
+import android.provider.Settings
+import android.text.Html
+import android.util.Log
+import androidx.test.core.app.ActivityScenario
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.StaleObjectException
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.UiScrollable
+import androidx.test.uiautomator.UiSelector
+import androidx.test.uiautomator.Until
+import com.android.compatibility.common.util.DisableAnimationRule
+import com.android.compatibility.common.util.FreezeRotationRule
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.UiAutomatorUtils2
+import com.android.modules.utils.build.SdkLevel
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+import java.util.regex.Pattern
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
+import org.junit.Before
+import org.junit.Rule
+
+@ScreenRecordRule.ScreenRecord
+abstract class BasePermissionTest {
+ companion object {
+ private const val TAG = "BasePermissionTest"
+
+ private const val INSTALL_ACTION_CALLBACK = "BasePermissionTest.install_callback"
+
+ private const val MAX_SWIPES = 5
+
+ const val APK_DIRECTORY = "/data/local/tmp/cts-permissionui"
+
+ const val QUICK_CHECK_TIMEOUT_MILLIS = 100L
+ const val IDLE_TIMEOUT_MILLIS: Long = 1000
+ const val UNEXPECTED_TIMEOUT_MILLIS = 1000
+ const val TIMEOUT_MILLIS: Long = 20000
+ const val PACKAGE_INSTALLER_TIMEOUT = 60000L
+ const val NEW_WINDOW_TIMEOUT_MILLIS: Long = 20_000
+
+ @JvmStatic
+ protected val instrumentation: Instrumentation =
+ InstrumentationRegistry.getInstrumentation()
+ @JvmStatic protected val context: Context = instrumentation.context
+ @JvmStatic protected val uiAutomation: UiAutomation = instrumentation.uiAutomation
+ @JvmStatic protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+ @JvmStatic protected val packageManager: PackageManager = context.packageManager
+ private val packageInstaller = packageManager.packageInstaller
+ @JvmStatic
+ private val mPermissionControllerResources: Resources =
+ context
+ .createPackageContext(context.packageManager.permissionControllerPackageName, 0)
+ .resources
+
+ @JvmStatic
+ protected val isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ @JvmStatic
+ protected val isWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
+ @JvmStatic
+ protected val isAutomotive =
+ packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ @JvmStatic
+ protected val isAutomotiveSplitscreen = isAutomotive &&
+ packageManager.hasSystemFeature(
+ /* PackageManager.FEATURE_CAR_SPLITSCREEN_MULTITASKING */
+ "android.software.car.splitscreen_multitasking")
+ }
+
+ @get:Rule val screenRecordRule = ScreenRecordRule(false, false)
+
+ @get:Rule val disableAnimationRule = DisableAnimationRule()
+
+ @get:Rule val freezeRotationRule = FreezeRotationRule()
+
+ var activityScenario: ActivityScenario<StartForFutureActivity>? = null
+
+ data class SessionResult(val status: Int?)
+
+ /** If a status was received the value of the status, otherwise null */
+ private var installSessionResult = LinkedBlockingQueue<SessionResult>()
+
+ private val installSessionResultReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val status = intent.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID)
+ val msg = intent.getStringExtra(EXTRA_STATUS_MESSAGE)
+ Log.d(TAG, "status: $status, msg: $msg")
+
+ installSessionResult.offer(SessionResult(status))
+ }
+ }
+
+ private var screenTimeoutBeforeTest: Long = 0L
+
+ @Before
+ fun setUp() {
+ runWithShellPermissionIdentity {
+ screenTimeoutBeforeTest =
+ Settings.System.getLong(context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT)
+ Settings.System.putLong(
+ context.contentResolver,
+ Settings.System.SCREEN_OFF_TIMEOUT,
+ 1800000L
+ )
+ }
+
+ uiDevice.wakeUp()
+ runShellCommand(instrumentation, "wm dismiss-keyguard")
+
+ uiDevice.findObject(By.text("Close"))?.click()
+ }
+
+ @Before
+ fun registerInstallSessionResultReceiver() {
+ context.registerReceiver(
+ installSessionResultReceiver,
+ IntentFilter(INSTALL_ACTION_CALLBACK),
+ RECEIVER_EXPORTED
+ )
+ }
+
+ @After
+ fun unregisterInstallSessionResultReceiver() {
+ try {
+ context.unregisterReceiver(installSessionResultReceiver)
+ } catch (ignored: IllegalArgumentException) {}
+ }
+
+ @After
+ fun tearDown() {
+ runWithShellPermissionIdentity {
+ Settings.System.putLong(
+ context.contentResolver,
+ Settings.System.SCREEN_OFF_TIMEOUT,
+ screenTimeoutBeforeTest
+ )
+ }
+
+ try {
+ activityScenario?.close()
+ } catch (e: NullPointerException) {
+ // ignore
+ }
+
+ pressHome()
+ }
+
+ protected fun setDeviceConfigPrivacyProperty(
+ propertyName: String,
+ value: String,
+ ) {
+ runWithShellPermissionIdentity(instrumentation.uiAutomation) {
+ val valueWasSet =
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ /* name = */ propertyName,
+ /* value = */ value,
+ /* makeDefault = */ false
+ )
+ check(valueWasSet) { "Could not set $propertyName to $value" }
+ }
+ }
+
+ protected fun getPermissionControllerString(res: String, vararg formatArgs: Any): Pattern {
+ val textWithHtml =
+ mPermissionControllerResources.getString(
+ mPermissionControllerResources.getIdentifier(
+ res,
+ "string",
+ "com.android.permissioncontroller"
+ ),
+ *formatArgs
+ )
+ val textWithoutHtml = Html.fromHtml(textWithHtml, 0).toString()
+ return Pattern.compile(
+ Pattern.quote(textWithoutHtml),
+ Pattern.CASE_INSENSITIVE or Pattern.UNICODE_CASE
+ )
+ }
+
+ protected fun getPermissionControllerResString(res: String): String? {
+ try {
+ return mPermissionControllerResources.getString(
+ mPermissionControllerResources.getIdentifier(
+ res,
+ "string",
+ "com.android.permissioncontroller"
+ )
+ )
+ } catch (e: Resources.NotFoundException) {
+ return null
+ }
+ }
+
+ protected fun byAnyText(vararg texts: String?): BySelector {
+ var regex = ""
+ for (text in texts) {
+ if (text != null) {
+ regex = regex + Pattern.quote(text) + "|"
+ }
+ }
+ if (regex.endsWith("|")) {
+ regex = regex.dropLast(1)
+ }
+ return By.text(Pattern.compile(regex, Pattern.CASE_INSENSITIVE or Pattern.UNICODE_CASE))
+ }
+
+ protected open fun installPackage(
+ apkPath: String,
+ reinstall: Boolean = false,
+ grantRuntimePermissions: Boolean = false,
+ expectSuccess: Boolean = true,
+ installSource: String? = null
+ ) {
+ val output =
+ runShellCommandOrThrow(
+ "pm install${if (SdkLevel.isAtLeastU()) " --bypass-low-target-sdk-block" else ""} " +
+ "${if (reinstall) " -r" else ""}${if (grantRuntimePermissions) " -g"
+ else ""}${if (installSource != null) " -i $installSource" else ""} $apkPath"
+ )
+ .trim()
+ if (expectSuccess) {
+ assertEquals("Success", output)
+ } else {
+ assertNotEquals("Success", output)
+ }
+ }
+
+ protected fun installPackageViaSession(
+ apkName: String,
+ appMetadata: PersistableBundle? = null,
+ packageSource: Int? = null
+ ) {
+ val (sessionId, session) = createPackageInstallerSession(packageSource)
+ runWithShellPermissionIdentity {
+ writePackageInstallerSession(session, apkName)
+ if (appMetadata != null) {
+ setAppMetadata(session, appMetadata)
+ }
+ commitPackageInstallerSession(session)
+
+ // No need to click installer UI here due to running in shell permission identity and
+ // not needing user interaciton to complete install. Install should have succeeded.
+ val result = getInstallSessionResult()
+ assertThat(result.status).isEqualTo(STATUS_SUCCESS)
+ }
+ }
+
+ protected fun uninstallPackage(packageName: String, requireSuccess: Boolean = true) {
+ val output = runShellCommand("pm uninstall $packageName").trim()
+ if (requireSuccess) {
+ assertEquals("Success", output)
+ }
+ }
+
+ protected fun waitFindObject(selector: BySelector): UiObject2 {
+ return findObjectWithRetry({ t -> UiAutomatorUtils2.waitFindObject(selector, t) })!!
+ }
+
+ protected fun waitFindObject(selector: BySelector, timeoutMillis: Long): UiObject2 {
+ return findObjectWithRetry(
+ { t -> UiAutomatorUtils2.waitFindObject(selector, t) },
+ timeoutMillis
+ )!!
+ }
+
+ protected fun waitFindObjectOrNull(selector: BySelector): UiObject2? {
+ return findObjectWithRetry({ t -> UiAutomatorUtils2.waitFindObjectOrNull(selector, t) })
+ }
+
+ protected fun waitFindObjectOrNull(selector: BySelector, timeoutMillis: Long): UiObject2? {
+ return findObjectWithRetry(
+ { t -> UiAutomatorUtils2.waitFindObjectOrNull(selector, t) },
+ timeoutMillis
+ )
+ }
+
+ private fun findObjectWithRetry(
+ automatorMethod: (timeoutMillis: Long) -> UiObject2?,
+ timeoutMillis: Long = 20_000L
+ ): UiObject2? {
+ val startTime = SystemClock.elapsedRealtime()
+ return try {
+ automatorMethod(timeoutMillis)
+ } catch (e: StaleObjectException) {
+ val remainingTime = timeoutMillis - (SystemClock.elapsedRealtime() - startTime)
+ if (remainingTime <= 0) {
+ throw e
+ }
+ automatorMethod(remainingTime)
+ }
+ }
+
+ protected fun click(selector: BySelector, timeoutMillis: Long = 20_000) {
+ waitFindObject(selector, timeoutMillis).click()
+ }
+
+ protected fun clickAndWaitForWindowTransition(
+ selector: BySelector,
+ timeoutMillis: Long = 20_000
+ ) {
+ waitFindObject(selector, timeoutMillis)
+ .clickAndWait(Until.newWindow(), NEW_WINDOW_TIMEOUT_MILLIS)
+ }
+
+ protected fun findView(selector: BySelector, expected: Boolean) {
+ val timeoutMs =
+ if (expected) {
+ 10000L
+ } else {
+ 1000L
+ }
+
+ val exception =
+ try {
+ waitFindObject(selector, timeoutMs)
+ null
+ } catch (e: Exception) {
+ e
+ }
+ Assert.assertTrue("Expected to find view: $expected", (exception == null) == expected)
+ }
+
+ protected fun clickPermissionControllerUi(selector: BySelector, timeoutMillis: Long = 20_000) {
+ click(selector.pkg(context.packageManager.permissionControllerPackageName), timeoutMillis)
+ }
+
+ /**
+ * Clicks Permission Controller UI with a swipe based timeout instead of a time based one
+ *
+ * Use this if finding some Permission Controller UI isn't time bound.
+ *
+ * @param text The text to search for
+ * @param maxSearchSwipes See {@link UiScrollable#setMaxSearchSwipes}
+ */
+ protected fun clickPermissionControllerUi(text: String, maxSearchSwipes: Int = 5) {
+ scrollToText(text, maxSearchSwipes).click()
+ }
+
+ private fun scrollToText(text: String, maxSearchSwipes: Int = MAX_SWIPES): UiObject2 {
+ val scrollable =
+ UiScrollable(UiSelector().scrollable(true)).apply {
+ this.maxSearchSwipes = maxSearchSwipes
+ }
+
+ scrollable.scrollTextIntoView(text)
+
+ val foundObject =
+ uiDevice.findObject(
+ By.text(text).pkg(context.packageManager.permissionControllerPackageName)
+ )
+ Assert.assertNotNull("View not found after scrolling", foundObject)
+
+ return foundObject
+ }
+
+ protected fun pressBack() {
+ uiDevice.pressBack()
+ }
+
+ protected fun pressHome() {
+ uiDevice.pressHome()
+ }
+
+ protected fun pressDPadDown() {
+ uiDevice.pressDPadDown()
+ waitForIdle()
+ }
+
+ protected fun waitForIdle() = uiAutomation.waitForIdle(IDLE_TIMEOUT_MILLIS, TIMEOUT_MILLIS)
+
+ protected fun startActivityForFuture(
+ intent: Intent
+ ): CompletableFuture<Instrumentation.ActivityResult> =
+ CompletableFuture<Instrumentation.ActivityResult>().also {
+ activityScenario =
+ ActivityScenario.launch(StartForFutureActivity::class.java).onActivity { activity ->
+ activity.startActivityForFuture(intent, it)
+ }
+ }
+
+ open fun enableComponent(component: ComponentName) {
+ packageManager.setComponentEnabledSetting(
+ component,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ }
+
+ open fun disableComponent(component: ComponentName) {
+ packageManager.setComponentEnabledSetting(
+ component,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ }
+
+ private fun createPackageInstallerSession(
+ packageSource: Int? = null
+ ): Pair<Int, PackageInstaller.Session> {
+ // Create session
+ val sessionParam = SessionParams(SessionParams.MODE_FULL_INSTALL)
+ if (packageSource != null) {
+ sessionParam.setPackageSource(packageSource)
+ }
+
+ val sessionId = packageInstaller.createSession(sessionParam)
+ val session = packageInstaller.openSession(sessionId)!!
+
+ return Pair(sessionId, session)
+ }
+
+ private fun writePackageInstallerSession(session: PackageInstaller.Session, apkName: String) {
+ val apkFile = File(APK_DIRECTORY, apkName)
+ // Write data to session
+ apkFile.inputStream().use { fileOnDisk ->
+ session
+ .openWrite(/* name= */ apkName, /* offsetBytes= */ 0, /* lengthBytes= */ -1)
+ .use { sessionFile -> fileOnDisk.copyTo(sessionFile) }
+ }
+ }
+
+ private fun commitPackageInstallerSession(session: PackageInstaller.Session) {
+ // PendingIntent that triggers a INSTALL_ACTION_CALLBACK broadcast that gets received by
+ // installSessionResultReceiver when install actions occur with this session
+ val installActionPendingIntent =
+ PendingIntent.getBroadcast(
+ context,
+ 0,
+ Intent(INSTALL_ACTION_CALLBACK).setPackage(context.packageName),
+ FLAG_UPDATE_CURRENT or FLAG_MUTABLE
+ )
+ session.commit(installActionPendingIntent.intentSender)
+ }
+
+ private fun setAppMetadata(session: PackageInstaller.Session, data: PersistableBundle) {
+ try {
+ session.setAppMetadata(data)
+ } catch (e: Exception) {
+ session.abandon()
+ throw e
+ }
+ }
+
+ /** Wait for session's install result and return it */
+ private fun getInstallSessionResult(timeout: Long = PACKAGE_INSTALLER_TIMEOUT): SessionResult {
+ return installSessionResult.poll(timeout, TimeUnit.MILLISECONDS)
+ ?: SessionResult(null /* status */)
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
new file mode 100644
index 000000000..d24f4fd27
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
@@ -0,0 +1,1327 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest
+import android.app.Activity
+import android.app.ActivityManager
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.content.Intent
+import android.content.Intent.ACTION_REVIEW_APP_DATA_SHARING_UPDATES
+import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_OTHER
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_STORE
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import android.os.Process
+import android.provider.DeviceConfig
+import android.provider.Settings
+import android.text.Spanned
+import android.text.style.ClickableSpan
+import android.view.View
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.StaleObjectException
+import androidx.test.uiautomator.UiObjectNotFoundException
+import androidx.test.uiautomator.UiScrollable
+import androidx.test.uiautomator.UiSelector
+import androidx.test.uiautomator.Until
+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.modules.utils.build.SdkLevel
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+import java.util.regex.Pattern
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+
+abstract class BaseUsePermissionTest : BasePermissionTest() {
+ companion object {
+ const val APP_APK_NAME_31 = "CtsUsePermissionApp31.apk"
+
+ const val APP_APK_PATH_22 = "$APK_DIRECTORY/CtsUsePermissionApp22.apk"
+ const val APP_APK_PATH_22_CALENDAR_ONLY =
+ "$APK_DIRECTORY/CtsUsePermissionApp22CalendarOnly.apk"
+ const val APP_APK_PATH_22_NONE = "$APK_DIRECTORY/CtsUsePermissionApp22None.apk"
+ const val APP_APK_PATH_23 = "$APK_DIRECTORY/CtsUsePermissionApp23.apk"
+ const val APP_APK_PATH_25 = "$APK_DIRECTORY/CtsUsePermissionApp25.apk"
+ const val APP_APK_PATH_26 = "$APK_DIRECTORY/CtsUsePermissionApp26.apk"
+ const val APP_APK_PATH_28 = "$APK_DIRECTORY/CtsUsePermissionApp28.apk"
+ const val APP_APK_PATH_29 = "$APK_DIRECTORY/CtsUsePermissionApp29.apk"
+ const val APP_APK_PATH_30 = "$APK_DIRECTORY/CtsUsePermissionApp30.apk"
+ const val APP_APK_PATH_31 = "$APK_DIRECTORY/$APP_APK_NAME_31"
+ const val APP_APK_PATH_32 = "$APK_DIRECTORY/CtsUsePermissionApp32.apk"
+
+ const val APP_APK_PATH_30_WITH_BACKGROUND =
+ "$APK_DIRECTORY/CtsUsePermissionApp30WithBackground.apk"
+ const val APP_APK_PATH_30_WITH_BLUETOOTH =
+ "$APK_DIRECTORY/CtsUsePermissionApp30WithBluetooth.apk"
+ const val APP_APK_PATH_LATEST = "$APK_DIRECTORY/CtsUsePermissionAppLatest.apk"
+ const val APP_APK_PATH_LATEST_NONE = "$APK_DIRECTORY/CtsUsePermissionAppLatestNone.apk"
+ const val APP_APK_PATH_WITH_OVERLAY = "$APK_DIRECTORY/CtsUsePermissionAppWithOverlay.apk"
+ const val APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31 =
+ "$APK_DIRECTORY/CtsCreateNotificationChannelsApp31.apk"
+ const val APP_APK_PATH_MEDIA_PERMISSION_33_WITH_STORAGE =
+ "$APK_DIRECTORY/CtsMediaPermissionApp33WithStorage.apk"
+ const val APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE =
+ "$APK_DIRECTORY/CtsUsePermissionAppImplicitUserSelectStorage.apk"
+ const val APP_APK_PATH_STORAGE_33 = "$APK_DIRECTORY/CtsUsePermissionAppStorage33.apk"
+ const val APP_APK_PATH_OTHER_APP = "$APK_DIRECTORY/CtsDifferentPkgNameApp.apk"
+ const val APP_PACKAGE_NAME = "android.permissionui.cts.usepermission"
+ const val OTHER_APP_PACKAGE_NAME = "android.permissionui.cts.usepermissionother"
+ const val TEST_INSTALLER_PACKAGE_NAME = "android.permissionui.cts"
+
+ const val ALLOW_ALL_BUTTON =
+ "com.android.permissioncontroller:id/permission_allow_all_button"
+ const val SELECT_BUTTON =
+ "com.android.permissioncontroller:id/permission_allow_selected_button"
+ const val DONT_SELECT_MORE_BUTTON =
+ "com.android.permissioncontroller:id/permission_dont_allow_more_selected_button"
+ const val ALLOW_BUTTON = "com.android.permissioncontroller:id/permission_allow_button"
+ const val ALLOW_FOREGROUND_BUTTON =
+ "com.android.permissioncontroller:id/permission_allow_foreground_only_button"
+ const val DENY_BUTTON = "com.android.permissioncontroller:id/permission_deny_button"
+ const val DENY_AND_DONT_ASK_AGAIN_BUTTON =
+ "com.android.permissioncontroller:id/permission_deny_and_dont_ask_again_button"
+ const val NO_UPGRADE_BUTTON =
+ "com.android.permissioncontroller:id/permission_no_upgrade_button"
+ const val NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON =
+ "com.android.permissioncontroller:" +
+ "id/permission_no_upgrade_and_dont_ask_again_button"
+
+ const val ALLOW_ALWAYS_RADIO_BUTTON =
+ "com.android.permissioncontroller:id/allow_always_radio_button"
+ const val ALLOW_RADIO_BUTTON = "com.android.permissioncontroller:id/allow_radio_button"
+ const val ALLOW_FOREGROUND_RADIO_BUTTON =
+ "com.android.permissioncontroller:id/allow_foreground_only_radio_button"
+ const val ASK_RADIO_BUTTON = "com.android.permissioncontroller:id/ask_radio_button"
+ const val DENY_RADIO_BUTTON = "com.android.permissioncontroller:id/deny_radio_button"
+ const val SELECT_RADIO_BUTTON = "com.android.permissioncontroller:id/select_radio_button"
+ const val EDIT_PHOTOS_BUTTON = "com.android.permissioncontroller:id/edit_selected_button"
+
+ const val NOTIF_TEXT = "permgrouprequest_notifications"
+ const val ALLOW_BUTTON_TEXT = "grant_dialog_button_allow"
+ const val ALLOW_ALL_FILES_BUTTON_TEXT = "app_permission_button_allow_all_files"
+ const val ALLOW_FOREGROUND_BUTTON_TEXT = "grant_dialog_button_allow_foreground"
+ const val ALLOW_FOREGROUND_PREFERENCE_TEXT = "permission_access_only_foreground"
+ const val ASK_BUTTON_TEXT = "app_permission_button_ask"
+ const val ALLOW_ONE_TIME_BUTTON_TEXT = "grant_dialog_button_allow_one_time"
+ const val DENY_BUTTON_TEXT = "grant_dialog_button_deny"
+ const val DENY_ANYWAY_BUTTON_TEXT = "grant_dialog_button_deny_anyway"
+ const val DENY_AND_DONT_ASK_AGAIN_BUTTON_TEXT =
+ "grant_dialog_button_deny_and_dont_ask_again"
+ const val NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON_TEXT = "grant_dialog_button_no_upgrade"
+ const val ALERT_DIALOG_MESSAGE = "android:id/message"
+ const val ALERT_DIALOG_OK_BUTTON = "android:id/button1"
+ const val APP_PERMISSION_RATIONALE_CONTAINER_VIEW =
+ "com.android.permissioncontroller:id/app_permission_rationale_container"
+ const val APP_PERMISSION_RATIONALE_CONTENT_VIEW =
+ "com.android.permissioncontroller:id/app_permission_rationale_content"
+ const val GRANT_DIALOG_PERMISSION_RATIONALE_CONTAINER_VIEW =
+ "com.android.permissioncontroller:id/permission_rationale_container"
+ const val PERMISSION_RATIONALE_ACTIVITY_TITLE_VIEW =
+ "com.android.permissioncontroller:id/permission_rationale_title"
+ const val DATA_SHARING_SOURCE_TITLE_ID =
+ "com.android.permissioncontroller:id/data_sharing_source_title"
+ const val DATA_SHARING_SOURCE_MESSAGE_ID =
+ "com.android.permissioncontroller:id/data_sharing_source_message"
+ const val PURPOSE_TITLE_ID = "com.android.permissioncontroller:id/purpose_title"
+ const val PURPOSE_MESSAGE_ID = "com.android.permissioncontroller:id/purpose_message"
+ const val LEARN_MORE_TITLE_ID = "com.android.permissioncontroller:id/learn_more_title"
+ const val LEARN_MORE_MESSAGE_ID = "com.android.permissioncontroller:id/learn_more_message"
+ const val PERMISSION_RATIONALE_SETTINGS_SECTION =
+ "com.android.permissioncontroller:id/settings_section"
+ const val SETTINGS_TITLE_ID = "com.android.permissioncontroller:id/settings_title"
+ const val SETTINGS_MESSAGE_ID = "com.android.permissioncontroller:id/settings_message"
+
+ const val REQUEST_LOCATION_MESSAGE = "permgrouprequest_location"
+
+ const val DATA_SHARING_UPDATES = "Data sharing updates for location"
+ const val DATA_SHARING_UPDATES_SUBTITLE =
+ "These apps have changed the way they may share your location data. They may not" +
+ " have shared it before, or may now share it for advertising or marketing" +
+ " purposes."
+ const val DATA_SHARING_NO_UPDATES_MESSAGE = "No updates at this time"
+ const val UPDATES_IN_LAST_30_DAYS = "Updated within 30 days"
+ const val DATA_SHARING_UPDATES_FOOTER_MESSAGE =
+ "The developers of these apps provided info about their data sharing practices" +
+ " to an app store. They may update it over time.\n\nData sharing" +
+ " practices may vary based on your app version, use, region, and age."
+ const val LEARN_ABOUT_DATA_SHARING = "Learn about data sharing"
+ const val LOCATION_PERMISSION = "Location permission"
+ const val APP_PACKAGE_NAME_SUBSTRING = "android.permissionui"
+ const val NOW_SHARED_WITH_THIRD_PARTIES =
+ "Your location data is now shared with third " + "parties"
+ const val NOW_SHARED_WITH_THIRD_PARTIES_FOR_ADS =
+ "Your location data is now shared with " + "third parties for advertising or marketing"
+ const val PROPERTY_DATA_SHARING_UPDATE_PERIOD_MILLIS = "data_sharing_update_period_millis"
+ const val PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP =
+ "max_safety_labels_persisted_per_app"
+
+ // The highest SDK for which the system will show a "low SDK" warning when launching the app
+ const val MAX_SDK_FOR_SDK_WARNING = 27
+ const val MIN_SDK_FOR_RUNTIME_PERMS = 23
+
+ val TEST_INSTALLER_ACTIVITY_COMPONENT_NAME =
+ ComponentName(context, TestInstallerActivity::class.java)
+
+ val MEDIA_PERMISSIONS: Set<String> =
+ mutableSetOf(
+ Manifest.permission.ACCESS_MEDIA_LOCATION,
+ Manifest.permission.READ_MEDIA_AUDIO,
+ Manifest.permission.READ_MEDIA_IMAGES,
+ Manifest.permission.READ_MEDIA_VIDEO,
+ )
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ add(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
+ }
+ }
+ .toSet()
+
+ val STORAGE_AND_MEDIA_PERMISSIONS =
+ MEDIA_PERMISSIONS.plus(Manifest.permission.READ_EXTERNAL_STORAGE)
+ .plus(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+
+ @JvmStatic protected val PICKER_ENABLED_SETTING = "photo_picker_prompt_enabled"
+
+ @JvmStatic
+ protected fun isPhotoPickerPermissionPromptEnabled(): Boolean {
+ return SdkLevel.isAtLeastU() &&
+ !isTv &&
+ !isAutomotive &&
+ !isWatch &&
+ callWithShellPermissionIdentity {
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PICKER_ENABLED_SETTING,
+ true
+ )
+ }
+ }
+ }
+
+ enum class PermissionState {
+ ALLOWED,
+ DENIED,
+ DENIED_WITH_PREJUDICE
+ }
+
+ private val platformResources = context.createPackageContext("android", 0).resources
+ private val permissionToLabelResNameMap =
+ mapOf(
+ // Contacts
+ android.Manifest.permission.READ_CONTACTS to "@android:string/permgrouplab_contacts",
+ android.Manifest.permission.WRITE_CONTACTS to "@android:string/permgrouplab_contacts",
+ // Calendar
+ android.Manifest.permission.READ_CALENDAR to "@android:string/permgrouplab_calendar",
+ android.Manifest.permission.WRITE_CALENDAR to "@android:string/permgrouplab_calendar",
+ // SMS
+ android.Manifest.permission.SEND_SMS to "@android:string/permgrouplab_sms",
+ android.Manifest.permission.RECEIVE_SMS to "@android:string/permgrouplab_sms",
+ android.Manifest.permission.READ_SMS to "@android:string/permgrouplab_sms",
+ android.Manifest.permission.RECEIVE_WAP_PUSH to "@android:string/permgrouplab_sms",
+ android.Manifest.permission.RECEIVE_MMS to "@android:string/permgrouplab_sms",
+ "android.permission.READ_CELL_BROADCASTS" to "@android:string/permgrouplab_sms",
+ // Storage
+ android.Manifest.permission.READ_EXTERNAL_STORAGE to
+ "@android:string/permgrouplab_storage",
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE to
+ "@android:string/permgrouplab_storage",
+ // Location
+ android.Manifest.permission.ACCESS_FINE_LOCATION to
+ "@android:string/permgrouplab_location",
+ android.Manifest.permission.ACCESS_COARSE_LOCATION to
+ "@android:string/permgrouplab_location",
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to
+ "@android:string/permgrouplab_location",
+ // Phone
+ android.Manifest.permission.READ_PHONE_STATE to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.CALL_PHONE to "@android:string/permgrouplab_phone",
+ "android.permission.ACCESS_IMS_CALL_SERVICE" to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.READ_CALL_LOG to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.WRITE_CALL_LOG to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.ADD_VOICEMAIL to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.USE_SIP to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.PROCESS_OUTGOING_CALLS to
+ "@android:string/permgrouplab_phone",
+ // Microphone
+ android.Manifest.permission.RECORD_AUDIO to "@android:string/permgrouplab_microphone",
+ // Camera
+ android.Manifest.permission.CAMERA to "@android:string/permgrouplab_camera",
+ // Body sensors
+ android.Manifest.permission.BODY_SENSORS to "@android:string/permgrouplab_sensors",
+ android.Manifest.permission.BODY_SENSORS_BACKGROUND to
+ "@android:string/permgrouplab_sensors",
+ // Bluetooth
+ android.Manifest.permission.BLUETOOTH_CONNECT to
+ "@android:string/permgrouplab_nearby_devices",
+ android.Manifest.permission.BLUETOOTH_SCAN to
+ "@android:string/permgrouplab_nearby_devices",
+ // Aural
+ android.Manifest.permission.READ_MEDIA_AUDIO to
+ "@android:string/permgrouplab_readMediaAural",
+ // Visual
+ android.Manifest.permission.READ_MEDIA_IMAGES to
+ "@android:string/permgrouplab_readMediaVisual",
+ android.Manifest.permission.READ_MEDIA_VIDEO to
+ "@android:string/permgrouplab_readMediaVisual"
+ )
+
+ @Before
+ @After
+ fun uninstallApp() {
+ uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false)
+ }
+
+ override fun installPackage(
+ apkPath: String,
+ reinstall: Boolean,
+ grantRuntimePermissions: Boolean,
+ expectSuccess: Boolean,
+ installSource: String?
+ ) {
+ installPackage(
+ apkPath,
+ reinstall,
+ grantRuntimePermissions,
+ expectSuccess,
+ installSource,
+ false
+ )
+ }
+
+ fun installPackage(
+ apkPath: String,
+ reinstall: Boolean = false,
+ grantRuntimePermissions: Boolean = false,
+ expectSuccess: Boolean = true,
+ installSource: String? = null,
+ skipClearLowSdkDialog: Boolean = false
+ ) {
+ super.installPackage(
+ apkPath,
+ reinstall,
+ grantRuntimePermissions,
+ expectSuccess,
+ installSource
+ )
+
+ val targetSdk = getTargetSdk()
+ // If the targetSDK is high enough, the low sdk warning won't show. If the SDK is
+ // below runtime permissions, the dialog will be delayed by the permission review screen.
+ // If success is not expected, don't bother trying
+ if (
+ targetSdk > MAX_SDK_FOR_SDK_WARNING ||
+ targetSdk < MIN_SDK_FOR_RUNTIME_PERMS ||
+ !expectSuccess ||
+ skipClearLowSdkDialog
+ ) {
+ return
+ }
+
+ val finishOnCreateIntent =
+ Intent().apply {
+ component =
+ ComponentName(APP_PACKAGE_NAME, "$APP_PACKAGE_NAME.FinishOnCreateActivity")
+ flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK
+ }
+
+ // Check if an activity resolves for the test app. If it doesn't, then our test app doesn't
+ // have the usual set of activities, and likely won't be opened, and thus, won't show the
+ // dialog
+ callWithShellPermissionIdentity {
+ context.packageManager.resolveActivity(finishOnCreateIntent, PackageManager.MATCH_ALL)
+ }
+ ?: return
+
+ // Start the test app, and expect the targetSDK warning dialog
+ context.startActivity(finishOnCreateIntent)
+ clearTargetSdkWarning()
+ // Kill the test app, so that the next time we launch, we don't see the app warning dialog
+ killTestApp()
+ }
+
+ protected fun clearTargetSdkWarning(timeoutMillis: Long = TIMEOUT_MILLIS) {
+ if (SdkLevel.isAtLeastV()) {
+ // In V and above, the target SDK dialog can be disabled via system property
+ return
+ }
+
+ waitFindObjectOrNull(By.res("android:id/button1"), timeoutMillis)?.let {
+ try {
+ it.click()
+ } catch (e: StaleObjectException) {
+ // Click sometimes fails with StaleObjectException (b/280430717).
+ e.printStackTrace()
+ }
+ }
+ }
+
+ protected fun killTestApp() {
+ pressBack()
+ pressBack()
+ runWithShellPermissionIdentity {
+ val am = context.getSystemService(ActivityManager::class.java)!!
+ am.forceStopPackage(APP_PACKAGE_NAME)
+ }
+ waitForIdle()
+ }
+
+ protected fun clickPermissionReviewContinue() {
+ if (isAutomotive || isWatch) {
+ clickAndWaitForWindowTransition(
+ By.text(getPermissionControllerString("review_button_continue")),
+ TIMEOUT_MILLIS * 2
+ )
+ } else {
+ clickAndWaitForWindowTransition(
+ By.res("com.android.permissioncontroller:id/continue_button")
+ )
+ }
+ }
+
+ protected fun clickPermissionReviewContinueAndClearSdkWarning() {
+ clickPermissionReviewContinue()
+ clearTargetSdkWarning()
+ }
+
+ protected fun installPackageWithInstallSourceAndEmptyMetadata(apkName: String) {
+ installPackageViaSession(apkName, AppMetadata.createEmptyAppMetadata())
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadata(apkName: String) {
+ installPackageViaSession(apkName, AppMetadata.createDefaultAppMetadata())
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadataFromStore(apkName: String) {
+ installPackageViaSession(
+ apkName,
+ AppMetadata.createDefaultAppMetadata(),
+ PACKAGE_SOURCE_STORE
+ )
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadataFromLocalFile(apkName: String) {
+ installPackageViaSession(
+ apkName,
+ AppMetadata.createDefaultAppMetadata(),
+ PACKAGE_SOURCE_LOCAL_FILE
+ )
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadataFromDownloadedFile(apkName: String) {
+ installPackageViaSession(
+ apkName,
+ AppMetadata.createDefaultAppMetadata(),
+ PACKAGE_SOURCE_DOWNLOADED_FILE
+ )
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadataFromOther(apkName: String) {
+ installPackageViaSession(
+ apkName,
+ AppMetadata.createDefaultAppMetadata(),
+ PACKAGE_SOURCE_OTHER
+ )
+ }
+
+ protected fun installPackageWithInstallSourceAndNoMetadata(apkName: String) {
+ installPackageViaSession(apkName)
+ }
+
+ protected fun installPackageWithInstallSourceAndInvalidMetadata(apkName: String) {
+ installPackageViaSession(apkName, AppMetadata.createInvalidAppMetadata())
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadataWithoutTopLevelVersion(
+ apkName: String
+ ) {
+ installPackageViaSession(
+ apkName,
+ AppMetadata.createInvalidAppMetadataWithoutTopLevelVersion()
+ )
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadataWithInvalidTopLevelVersion(
+ apkName: String
+ ) {
+ installPackageViaSession(
+ apkName,
+ AppMetadata.createInvalidAppMetadataWithInvalidTopLevelVersion()
+ )
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadataWithoutSafetyLabelVersion(
+ apkName: String
+ ) {
+ installPackageViaSession(
+ apkName,
+ AppMetadata.createInvalidAppMetadataWithoutSafetyLabelVersion()
+ )
+ }
+
+ protected fun installPackageWithInstallSourceAndMetadataWithInvalidSafetyLabelVersion(
+ apkName: String
+ ) {
+ installPackageViaSession(
+ apkName,
+ AppMetadata.createInvalidAppMetadataWithInvalidSafetyLabelVersion()
+ )
+ }
+
+ protected fun installPackageWithoutInstallSource(apkName: String) {
+ // TODO(b/257293222): Update/remove when hooking up PackageManager APIs
+ installPackage(apkName)
+ }
+
+ protected fun assertPermissionRationaleActivityTitleIsVisible(expected: Boolean) {
+ findView(By.res(PERMISSION_RATIONALE_ACTIVITY_TITLE_VIEW), expected = expected)
+ }
+
+ protected fun assertPermissionRationaleActivityDataSharingSourceSectionVisible(
+ expected: Boolean
+ ) {
+ findView(By.res(DATA_SHARING_SOURCE_TITLE_ID), expected = expected)
+ findView(By.res(DATA_SHARING_SOURCE_MESSAGE_ID), expected = expected)
+ }
+
+ protected fun assertPermissionRationaleActivityPurposeSectionVisible(expected: Boolean) {
+ findView(By.res(PURPOSE_TITLE_ID), expected = expected)
+ findView(By.res(PURPOSE_MESSAGE_ID), expected = expected)
+ }
+
+ protected fun assertPermissionRationaleActivityLearnMoreSectionVisible(expected: Boolean) {
+ findView(By.res(LEARN_MORE_TITLE_ID), expected = expected)
+ findView(By.res(LEARN_MORE_MESSAGE_ID), expected = expected)
+ }
+
+ protected fun assertPermissionRationaleActivitySettingsSectionVisible(expected: Boolean) {
+ findView(By.res(PERMISSION_RATIONALE_SETTINGS_SECTION), expected = expected)
+ findView(By.res(SETTINGS_TITLE_ID), expected = expected)
+ findView(By.res(SETTINGS_MESSAGE_ID), expected = expected)
+ }
+
+ protected fun assertPermissionRationaleDialogIsVisible(
+ expected: Boolean,
+ showSettingsSection: Boolean = true
+ ) {
+ assertPermissionRationaleActivityTitleIsVisible(expected)
+ assertPermissionRationaleActivityDataSharingSourceSectionVisible(expected)
+ assertPermissionRationaleActivityPurposeSectionVisible(expected)
+ assertPermissionRationaleActivityLearnMoreSectionVisible(expected)
+ if (expected) {
+ assertPermissionRationaleActivitySettingsSectionVisible(showSettingsSection)
+ }
+ }
+
+ protected fun assertPermissionRationaleContainerOnGrantDialogIsVisible(expected: Boolean) {
+ findView(By.res(GRANT_DIALOG_PERMISSION_RATIONALE_CONTAINER_VIEW), expected = expected)
+ }
+
+ protected fun clickPermissionReviewCancel() {
+ if (isAutomotive || isWatch) {
+ clickAndWaitForWindowTransition(
+ By.text(getPermissionControllerString("review_button_cancel"))
+ )
+ } else {
+ clickAndWaitForWindowTransition(
+ By.res("com.android.permissioncontroller:id/cancel_button")
+ )
+ }
+ }
+
+ protected fun approvePermissionReview() {
+ startAppActivityAndAssertResultCode(Activity.RESULT_OK) {
+ clickPermissionReviewContinueAndClearSdkWarning()
+ }
+ }
+
+ protected fun cancelPermissionReview() {
+ startAppActivityAndAssertResultCode(Activity.RESULT_CANCELED) {
+ clickPermissionReviewCancel()
+ }
+ }
+
+ protected fun assertAppDoesNotNeedPermissionReview() {
+ startAppActivityAndAssertResultCode(Activity.RESULT_OK) {}
+ }
+
+ protected inline fun startAppActivityAndAssertResultCode(
+ expectedResultCode: Int,
+ block: () -> Unit
+ ) {
+ val future =
+ startActivityForFuture(
+ Intent().apply {
+ component =
+ ComponentName(APP_PACKAGE_NAME, "$APP_PACKAGE_NAME.FinishOnCreateActivity")
+ }
+ )
+ block()
+ assertEquals(
+ expectedResultCode,
+ future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS).resultCode
+ )
+ }
+
+ protected inline fun requestAppPermissionsForNoResult(
+ vararg permissions: String?,
+ crossinline block: () -> Unit
+ ) {
+ // Request the permissions
+ doAndWaitForWindowTransition {
+ context.startActivity(
+ Intent().apply {
+ component =
+ ComponentName(
+ APP_PACKAGE_NAME,
+ "$APP_PACKAGE_NAME.RequestPermissionsActivity"
+ )
+ putExtra("$APP_PACKAGE_NAME.PERMISSIONS", permissions)
+ addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)
+ }
+ )
+ }
+ // Perform the post-request action
+ block()
+ }
+
+ protected inline fun requestAppPermissions(
+ vararg permissions: String?,
+ askTwice: Boolean = false,
+ waitForWindowTransition: Boolean = true,
+ crossinline block: () -> Unit
+ ): Instrumentation.ActivityResult {
+ // Request the permissions
+ lateinit var future: CompletableFuture<Instrumentation.ActivityResult>
+ doAndWaitForWindowTransition {
+ future =
+ startActivityForFuture(
+ Intent().apply {
+ component =
+ ComponentName(
+ APP_PACKAGE_NAME,
+ "$APP_PACKAGE_NAME.RequestPermissionsActivity"
+ )
+ putExtra("$APP_PACKAGE_NAME.PERMISSIONS", permissions)
+ putExtra("$APP_PACKAGE_NAME.ASK_TWICE", askTwice)
+ }
+ )
+ }
+
+ // Notification permission prompt is shown first, so get it out of the way
+ clickNotificationPermissionRequestAllowButtonIfAvailable()
+ // Perform the post-request action
+ if (waitForWindowTransition) {
+ doAndWaitForWindowTransition { block() }
+ } else {
+ block()
+ }
+ return future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ }
+
+ protected inline fun requestAppPermissionsAndAssertResult(
+ permissions: Array<out String?>,
+ permissionAndExpectedGrantResults: Array<out Pair<String?, Boolean>>,
+ askTwice: Boolean = false,
+ waitForWindowTransition: Boolean = !isWatch,
+ crossinline block: () -> Unit
+ ) {
+ val result =
+ requestAppPermissions(
+ *permissions,
+ askTwice = askTwice,
+ waitForWindowTransition = waitForWindowTransition,
+ block = block
+ )
+ assertEquals(
+ "Permission request result had unexpected resultCode:",
+ Activity.RESULT_OK,
+ result.resultCode
+ )
+
+ val responseSize: Int =
+ result.resultData!!.getStringArrayExtra("$APP_PACKAGE_NAME.PERMISSIONS")!!.size
+ assertEquals(
+ "Permission request result had unexpected number of grant results:",
+ responseSize,
+ result.resultData!!.getIntArrayExtra("$APP_PACKAGE_NAME.GRANT_RESULTS")!!.size
+ )
+
+ // Note that the behavior around requesting `null` permissions changed in the platform
+ // in Android U. Currently, null permissions are ignored and left out of the result set.
+ assertTrue(
+ "Permission request result had fewer permissions than request",
+ permissions.size >= responseSize
+ )
+ assertEquals(
+ "Permission request result had unexpected grant results:",
+ permissionAndExpectedGrantResults.filter { it.first != null }.toList(),
+ result.resultData!!
+ .getStringArrayExtra("$APP_PACKAGE_NAME.PERMISSIONS")!!
+ .filterNotNull()
+ .zip(
+ result.resultData!!.getIntArrayExtra("$APP_PACKAGE_NAME.GRANT_RESULTS")!!.map {
+ it == PackageManager.PERMISSION_GRANTED
+ }
+ )
+ )
+
+ permissionAndExpectedGrantResults.forEach {
+ it.first?.let { permission -> assertAppHasPermission(permission, it.second) }
+ }
+ }
+
+ protected inline fun requestAppPermissionsAndAssertResult(
+ vararg permissionAndExpectedGrantResults: Pair<String?, Boolean>,
+ askTwice: Boolean = false,
+ waitForWindowTransition: Boolean = !isWatch,
+ crossinline block: () -> Unit
+ ) {
+ requestAppPermissionsAndAssertResult(
+ permissionAndExpectedGrantResults.map { it.first }.toTypedArray(),
+ permissionAndExpectedGrantResults,
+ askTwice,
+ waitForWindowTransition,
+ block
+ )
+ }
+
+ // Perform the requested action, then wait both for the action to complete, and for at least
+ // one window transition to occur since the moment the action begins executing.
+ protected inline fun doAndWaitForWindowTransition(crossinline block: () -> Unit) {
+ val timeoutOccurred =
+ !uiDevice.performActionAndWait(
+ { block() },
+ Until.newWindow(),
+ NEW_WINDOW_TIMEOUT_MILLIS
+ )
+
+ if (timeoutOccurred) {
+ throw RuntimeException("Timed out waiting for window transition.")
+ }
+ }
+
+ protected fun findPermissionRequestAllowButton(timeoutMillis: Long = 20000) {
+ if (isAutomotive || isWatch) {
+ waitFindObject(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)), timeoutMillis)
+ } else {
+ waitFindObject(By.res(ALLOW_BUTTON), timeoutMillis)
+ }
+ }
+
+ protected fun clickPermissionRequestAllowButton(timeoutMillis: Long = 20000) {
+ if (isAutomotive || isWatch) {
+ click(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)), timeoutMillis)
+ } else {
+ click(By.res(ALLOW_BUTTON), timeoutMillis)
+ }
+ }
+
+ protected fun clickPermissionRequestAllowAllButton(timeoutMillis: Long = 20000) {
+ click(By.res(ALLOW_ALL_BUTTON), timeoutMillis)
+ }
+
+ /**
+ * Only for use in tests that are not testing the notification permission popup, on T devices
+ */
+ protected fun clickNotificationPermissionRequestAllowButtonIfAvailable() {
+ if (!SdkLevel.isAtLeastT()) {
+ return
+ }
+
+ if (
+ waitFindObjectOrNull(
+ By.text(getPermissionControllerString(NOTIF_TEXT, APP_PACKAGE_NAME)),
+ 1000
+ ) != null
+ ) {
+ if (isAutomotive) {
+ click(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)))
+ } else {
+ click(By.res(ALLOW_BUTTON))
+ }
+ }
+ }
+
+ protected fun clickPermissionRequestSettingsLinkAndAllowAlways() {
+ clickPermissionRequestSettingsLink()
+ eventually({ clickAllowAlwaysInSettings() }, TIMEOUT_MILLIS * 2)
+ pressBack()
+ }
+
+ protected fun clickAllowAlwaysInSettings() {
+ if (isAutomotive || isTv || isWatch) {
+ click(By.text(getPermissionControllerString("app_permission_button_allow_always")))
+ } else {
+ click(By.res("com.android.permissioncontroller:id/allow_always_radio_button"))
+ }
+ }
+
+ protected fun clickAllowForegroundInSettings() {
+ click(By.res(ALLOW_FOREGROUND_RADIO_BUTTON))
+ }
+
+ protected fun clicksDenyInSettings() {
+ if (isAutomotive || isWatch) {
+ click(By.text(getPermissionControllerString("app_permission_button_deny")))
+ } else {
+ click(By.res("com.android.permissioncontroller:id/deny_radio_button"))
+ }
+ }
+
+ protected fun findPermissionRequestAllowForegroundButton(timeoutMillis: Long = 20000) {
+ if (isAutomotive || isWatch) {
+ waitFindObject(
+ By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT)),
+ timeoutMillis
+ )
+ } else {
+ waitFindObject(By.res(ALLOW_FOREGROUND_BUTTON), timeoutMillis)
+ }
+ }
+
+ protected fun clickPermissionRequestAllowForegroundButton(timeoutMillis: Long = 10_000) {
+ if (isAutomotive || isWatch) {
+ click(
+ By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT)),
+ timeoutMillis
+ )
+ } else {
+ click(By.res(ALLOW_FOREGROUND_BUTTON), timeoutMillis)
+ }
+ }
+
+ protected fun clickPermissionRequestDenyButton() {
+ if (isAutomotive || isWatch || isTv) {
+ click(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)))
+ } else {
+ click(By.res(DENY_BUTTON))
+ }
+ }
+
+ protected fun clickPermissionRequestSettingsLinkAndDeny() {
+ clickPermissionRequestSettingsLink()
+ eventually({ clicksDenyInSettings() }, TIMEOUT_MILLIS * 2)
+ pressBack()
+ }
+
+ protected fun clickPermissionRequestSettingsLink() {
+ eventually {
+ // UiObject2 doesn't expose CharSequence.
+ val node =
+ if (isAutomotive) {
+ // Should match "Allow in settings." (location) and "go to settings." (body
+ // sensors)
+ uiAutomation.rootInActiveWindow
+ .findAccessibilityNodeInfosByText(" settings.")[0]
+ } else {
+ uiAutomation.rootInActiveWindow
+ .findAccessibilityNodeInfosByViewId(
+ "com.android.permissioncontroller:id/detail_message"
+ )[0]
+ }
+ if (!node.isVisibleToUser) {
+ scrollToBottom()
+ }
+ assertTrue(node.isVisibleToUser)
+ val text = node.text as Spanned
+ val clickableSpan = text.getSpans(0, text.length, ClickableSpan::class.java)[0]
+ // We could pass in null here in Java, but we need an instance in Kotlin.
+ doAndWaitForWindowTransition { clickableSpan.onClick(View(context)) }
+ }
+ }
+
+ protected fun clickPermissionRequestDenyAndDontAskAgainButton() {
+ if (isAutomotive) {
+ click(By.text(getPermissionControllerString(DENY_AND_DONT_ASK_AGAIN_BUTTON_TEXT)))
+ } else if (isWatch) {
+ click(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)))
+ } else {
+ click(By.res(DENY_AND_DONT_ASK_AGAIN_BUTTON))
+ }
+ }
+
+ // Only used in TV and Watch form factors
+ protected fun clickPermissionRequestDontAskAgainButton() {
+ if (isWatch) {
+ click(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)))
+ } else {
+ click(
+ By.res("com.android.permissioncontroller:id/permission_deny_dont_ask_again_button")
+ )
+ }
+ }
+
+ protected fun clickPermissionRequestNoUpgradeAndDontAskAgainButton() {
+ if (isAutomotive) {
+ click(By.text(getPermissionControllerString(NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON_TEXT)))
+ } else {
+ click(By.res(NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON))
+ }
+ }
+
+ protected fun clickPermissionRationaleContentInAppPermission() {
+ clickAndWaitForWindowTransition(By.res(APP_PERMISSION_RATIONALE_CONTENT_VIEW))
+ }
+
+ protected fun clickPermissionRationaleViewInGrantDialog() {
+ clickAndWaitForWindowTransition(By.res(GRANT_DIALOG_PERMISSION_RATIONALE_CONTAINER_VIEW))
+ }
+
+ protected fun grantAppPermissionsByUi(vararg permissions: String) {
+ setAppPermissionState(*permissions, state = PermissionState.ALLOWED, isLegacyApp = false)
+ }
+
+ protected fun grantRuntimePermissions(vararg permissions: String) {
+ for (permission in permissions) {
+ uiAutomation.grantRuntimePermission(APP_PACKAGE_NAME, permission)
+ }
+ }
+
+ protected fun revokeAppPermissionsByUi(
+ vararg permissions: String,
+ isLegacyApp: Boolean = false
+ ) {
+ setAppPermissionState(
+ *permissions,
+ state = PermissionState.DENIED,
+ isLegacyApp = isLegacyApp
+ )
+ }
+
+ private fun navigateToAppPermissionSettings() {
+ if (isTv) {
+ // Dismiss DeprecatedTargetSdkVersionDialog, if present
+ if (waitFindObjectOrNull(By.text(APP_PACKAGE_NAME), 1000L) != null) {
+ pressBack()
+ }
+ pressHome()
+ } else {
+ pressBack()
+ pressBack()
+ pressBack()
+ }
+
+ // Try multiple times as the AppInfo page might have read stale data
+ eventually(
+ {
+ try {
+ // Open the app details settings
+ doAndWaitForWindowTransition {
+ context.startActivity(
+ Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
+ data = Uri.fromParts("package", APP_PACKAGE_NAME, null)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ }
+ )
+ }
+ if (isTv) {
+ pressDPadDown()
+ pressDPadDown()
+ pressDPadDown()
+ pressDPadDown()
+ }
+ // Open the permissions UI
+ clickAndWaitForWindowTransition(byTextRes(R.string.permissions).enabled(true))
+ } catch (e: Exception) {
+ pressBack()
+ throw e
+ }
+ },
+ TIMEOUT_MILLIS
+ )
+ }
+
+ private fun getTargetSdk(packageName: String = APP_PACKAGE_NAME): Int {
+ return callWithShellPermissionIdentity {
+ try {
+ context.packageManager.getApplicationInfo(packageName, 0).targetSdkVersion
+ } catch (e: PackageManager.NameNotFoundException) {
+ -1
+ }
+ }
+ }
+
+ protected fun navigateToIndividualPermissionSetting(
+ permission: String,
+ manuallyNavigate: Boolean = false
+ ) {
+ val useLegacyNavigation = isWatch || isAutomotive || manuallyNavigate
+ if (useLegacyNavigation) {
+ navigateToAppPermissionSettings()
+ val permissionLabel = getPermissionLabel(permission)
+ if (isWatch) {
+ clickAndWaitForWindowTransition(By.text(permissionLabel), 40_000)
+ } else {
+ clickPermissionControllerUi(By.text(permissionLabel))
+ }
+ return
+ }
+ doAndWaitForWindowTransition {
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSION).apply {
+ putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME)
+ putExtra(Intent.EXTRA_PERMISSION_NAME, permission)
+ putExtra(Intent.EXTRA_USER, Process.myUserHandle())
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ }
+ )
+ }
+ }
+ }
+
+ /** Starts activity with intent [ACTION_REVIEW_APP_DATA_SHARING_UPDATES]. */
+ fun startAppDataSharingUpdatesActivity() {
+ doAndWaitForWindowTransition {
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(ACTION_REVIEW_APP_DATA_SHARING_UPDATES).apply {
+ addFlags(FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
+ }
+ }
+ }
+
+ private fun setAppPermissionState(
+ vararg permissions: String,
+ state: PermissionState,
+ isLegacyApp: Boolean,
+ manuallyNavigate: Boolean = false,
+ ) {
+ val useLegacyNavigation = isWatch || isAutomotive || manuallyNavigate
+ if (useLegacyNavigation) {
+ navigateToAppPermissionSettings()
+ }
+
+ val navigatedGroupLabels = mutableSetOf<String>()
+ for (permission in permissions) {
+ // Find the permission screen
+ val permissionLabel = getPermissionLabel(permission)
+ if (navigatedGroupLabels.contains(getPermissionLabel(permission))) {
+ continue
+ }
+ navigatedGroupLabels.add(permissionLabel)
+ if (useLegacyNavigation) {
+ if (isWatch) {
+ click(By.text(permissionLabel), 40_000)
+ } else if (isAutomotive) {
+ clickPermissionControllerUi(permissionLabel)
+ } else {
+ clickPermissionControllerUi(By.text(permissionLabel))
+ }
+ } else {
+ doAndWaitForWindowTransition {
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSION).apply {
+ putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME)
+ putExtra(Intent.EXTRA_PERMISSION_NAME, permission)
+ putExtra(Intent.EXTRA_USER, Process.myUserHandle())
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ }
+ )
+ }
+ }
+ }
+
+ val wasGranted =
+ if (isAutomotive) {
+ // Automotive doesn't support one time permissions, and thus
+ // won't show an "Ask every time" message
+ !waitFindObject(
+ By.text(getPermissionControllerString("app_permission_button_deny"))
+ )
+ .isChecked
+ } else if (isTv || isWatch) {
+ !(waitFindObject(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)))
+ .isChecked ||
+ (!isLegacyApp &&
+ hasAskButton(permission) &&
+ waitFindObject(By.text(getPermissionControllerString(ASK_BUTTON_TEXT)))
+ .isChecked))
+ } else {
+ !(waitFindObject(By.res(DENY_RADIO_BUTTON)).isChecked ||
+ (!isLegacyApp &&
+ hasAskButton(permission) &&
+ waitFindObject(By.res(ASK_RADIO_BUTTON)).isChecked))
+ }
+ var alreadyChecked = false
+ val button =
+ waitFindObject(
+ if (isAutomotive) {
+ // Automotive doesn't support one time permissions, and thus
+ // won't show an "Ask every time" message
+ when (state) {
+ PermissionState.ALLOWED ->
+ if (showsForegroundOnlyButton(permission)) {
+ By.text(
+ getPermissionControllerString(
+ "app_permission_button_allow_foreground"
+ )
+ )
+ } else {
+ By.text(
+ getPermissionControllerString("app_permission_button_allow")
+ )
+ }
+ PermissionState.DENIED ->
+ By.text(getPermissionControllerString("app_permission_button_deny"))
+ PermissionState.DENIED_WITH_PREJUDICE ->
+ By.text(getPermissionControllerString("app_permission_button_deny"))
+ }
+ } else if (isTv || isWatch) {
+ when (state) {
+ PermissionState.ALLOWED ->
+ if (showsForegroundOnlyButton(permission)) {
+ By.text(
+ getPermissionControllerString(
+ ALLOW_FOREGROUND_PREFERENCE_TEXT
+ )
+ )
+ } else {
+ byAnyText(
+ getPermissionControllerResString(ALLOW_BUTTON_TEXT),
+ getPermissionControllerResString(
+ ALLOW_ALL_FILES_BUTTON_TEXT
+ )
+ )
+ }
+ PermissionState.DENIED ->
+ if (!isLegacyApp && hasAskButton(permission)) {
+ By.text(getPermissionControllerString(ASK_BUTTON_TEXT))
+ } else {
+ By.text(getPermissionControllerString(DENY_BUTTON_TEXT))
+ }
+ PermissionState.DENIED_WITH_PREJUDICE ->
+ By.text(getPermissionControllerString(DENY_BUTTON_TEXT))
+ }
+ } else {
+ when (state) {
+ PermissionState.ALLOWED ->
+ if (showsForegroundOnlyButton(permission)) {
+ By.res(ALLOW_FOREGROUND_RADIO_BUTTON)
+ } else if (showsAlwaysButton(permission)) {
+ By.res(ALLOW_ALWAYS_RADIO_BUTTON)
+ } else {
+ By.res(ALLOW_RADIO_BUTTON)
+ }
+ PermissionState.DENIED ->
+ if (!isLegacyApp && hasAskButton(permission)) {
+ By.res(ASK_RADIO_BUTTON)
+ } else {
+ By.res(DENY_RADIO_BUTTON)
+ }
+ PermissionState.DENIED_WITH_PREJUDICE -> By.res(DENY_RADIO_BUTTON)
+ }
+ }
+ )
+ alreadyChecked = button.isChecked
+ if (!alreadyChecked) {
+ button.click()
+ }
+
+ val shouldShowStorageWarning =
+ SdkLevel.isAtLeastT() &&
+ getTargetSdk() <= Build.VERSION_CODES.S_V2 &&
+ permission in MEDIA_PERMISSIONS
+ if (shouldShowStorageWarning) {
+ if (isWatch) {
+ click(
+ By.desc(
+ getPermissionControllerString("media_confirm_dialog_positive_button")
+ )
+ )
+ } else {
+ click(By.res(ALERT_DIALOG_OK_BUTTON))
+ }
+ } else if (!alreadyChecked && isLegacyApp && wasGranted) {
+ if (!isTv) {
+ // Wait for alert dialog to popup, then scroll to the bottom of it
+ if (isWatch) {
+ waitFindObject(
+ By.text(getPermissionControllerString("old_sdk_deny_warning"))
+ )
+ } else {
+ waitFindObject(By.res(ALERT_DIALOG_MESSAGE))
+ }
+ scrollToBottom()
+ }
+
+ // Due to the limited real estate, Wear uses buttons with icons instead of text
+ // for dialogs
+ if (isWatch) {
+ click(By.desc(getPermissionControllerString("ok")))
+ } else {
+ val resources =
+ context
+ .createPackageContext(packageManager.permissionControllerPackageName, 0)
+ .resources
+ val confirmTextRes =
+ resources.getIdentifier(
+ "com.android.permissioncontroller:string/grant_dialog_button_deny_anyway",
+ null,
+ null
+ )
+
+ val confirmText = resources.getString(confirmTextRes)
+ click(byTextStartsWithCaseInsensitive(confirmText))
+ }
+ }
+ pressBack()
+ }
+ pressBack()
+ pressBack()
+ }
+
+ private fun getPermissionLabel(permission: String): String {
+ val labelResName = permissionToLabelResNameMap[permission]
+ assertNotNull("Unknown permission $permission", labelResName)
+ val labelRes = platformResources.getIdentifier(labelResName, null, null)
+ return platformResources.getString(labelRes)
+ }
+
+ private fun hasAskButton(permission: String): Boolean =
+ when (permission) {
+ android.Manifest.permission.CAMERA,
+ android.Manifest.permission.RECORD_AUDIO,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION -> true
+ else -> false
+ }
+ private fun showsAllowPhotosButton(permission: String): Boolean {
+ if (!isPhotoPickerPermissionPromptEnabled()) {
+ return false
+ }
+ return when (permission) {
+ Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
+ Manifest.permission.READ_MEDIA_IMAGES,
+ Manifest.permission.READ_MEDIA_VIDEO -> true
+ else -> false
+ }
+ }
+
+ private fun showsForegroundOnlyButton(permission: String): Boolean =
+ when (permission) {
+ android.Manifest.permission.CAMERA,
+ android.Manifest.permission.RECORD_AUDIO -> true
+ else -> false
+ }
+
+ private fun showsAlwaysButton(permission: String): Boolean =
+ when (permission) {
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION -> true
+ else -> false
+ }
+
+ private fun scrollToBottom() {
+ val scrollable =
+ UiScrollable(UiSelector().scrollable(true)).apply {
+ if (isWatch) {
+ swipeDeadZonePercentage = 0.1
+ } else {
+ swipeDeadZonePercentage = 0.25
+ }
+ }
+ waitForIdle()
+ if (scrollable.exists()) {
+ try {
+ scrollable.flingToEnd(10)
+ } catch (e: UiObjectNotFoundException) {
+ // flingToEnd() sometimes still fails despite waitForIdle() and the exists() check
+ // (b/246984354).
+ e.printStackTrace()
+ }
+ }
+ }
+
+ private fun byTextRes(textRes: Int): BySelector = By.text(context.getString(textRes))
+
+ private fun byTextStartsWithCaseInsensitive(prefix: String): BySelector =
+ By.text(Pattern.compile("(?i)^${Pattern.quote(prefix)}.*$"))
+
+ protected fun assertAppHasPermission(permissionName: String, expectPermission: Boolean) {
+ val checkPermissionResult = packageManager.checkPermission(permissionName, APP_PACKAGE_NAME)
+ assertTrue(
+ "Invalid permission check result: $checkPermissionResult",
+ checkPermissionResult == PackageManager.PERMISSION_GRANTED ||
+ checkPermissionResult == PackageManager.PERMISSION_DENIED
+ )
+ if (!expectPermission && checkPermissionResult == PackageManager.PERMISSION_GRANTED) {
+ Assert.fail(
+ "Unexpected permission check result for $permissionName: " +
+ "expected -1 (PERMISSION_DENIED) but was 0 (PERMISSION_GRANTED)"
+ )
+ }
+ if (expectPermission && checkPermissionResult == PackageManager.PERMISSION_DENIED) {
+ Assert.fail(
+ "Unexpected permission check result for $permissionName: " +
+ "expected 0 (PERMISSION_GRANTED) but was -1 (PERMISSION_DENIED)"
+ )
+ }
+ }
+
+ protected fun assertAppHasCalendarAccess(expectAccess: Boolean) {
+ val future =
+ startActivityForFuture(
+ Intent().apply {
+ component =
+ ComponentName(
+ APP_PACKAGE_NAME,
+ "$APP_PACKAGE_NAME.CheckCalendarAccessActivity"
+ )
+ }
+ )
+ clickNotificationPermissionRequestAllowButtonIfAvailable()
+ val result = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ assertEquals(Activity.RESULT_OK, result.resultCode)
+ assertTrue(result.resultData!!.hasExtra("$APP_PACKAGE_NAME.HAS_ACCESS"))
+ assertEquals(
+ expectAccess,
+ result.resultData!!.getBooleanExtra("$APP_PACKAGE_NAME.HAS_ACCESS", false)
+ )
+ }
+
+ protected fun assertPermissionFlags(permName: String, vararg flags: Pair<Int, Boolean>) {
+ val user = Process.myUserHandle()
+ SystemUtil.runWithShellPermissionIdentity {
+ val currFlags = packageManager.getPermissionFlags(permName, APP_PACKAGE_NAME, user)
+ for ((flag, set) in flags) {
+ assertEquals("flag $flag: ", set, currFlags and flag != 0)
+ }
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt
new file mode 100644
index 000000000..47fe17bac
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permissionui.cts
+
+import android.Manifest
+import android.app.Instrumentation
+import android.app.UiAutomation
+import android.app.compat.CompatChanges
+import android.content.AttributionSource
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.hardware.camera2.CameraManager
+import android.os.Build
+import android.os.Process
+import android.os.SystemClock
+import android.os.SystemProperties
+import android.permission.PermissionManager
+import android.platform.test.annotations.AsbSecurityTest
+import android.provider.DeviceConfig
+import android.provider.Settings
+import android.safetycenter.SafetyCenterManager
+import android.server.wm.WindowManagerStateHelper
+import androidx.annotation.RequiresApi
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.StaleObjectException
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.UiSelector
+import com.android.compatibility.common.util.CddTest
+import com.android.compatibility.common.util.DisableAnimationRule
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.UiAutomatorUtils2
+import com.android.modules.utils.build.SdkLevel
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
+import java.util.regex.Pattern
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+private const val APK_PATH =
+ "/data/local/tmp/cts-permissionui/CtsAppThatAccessesMicAndCameraPermission.apk"
+private const val APP_LABEL = "CtsCameraMicAccess"
+private const val APP_PKG = "android.permissionui.cts.appthataccessescameraandmic"
+private const val SHELL_PKG = "com.android.shell"
+private const val USE_CAMERA = "use_camera"
+private const val USE_MICROPHONE = "use_microphone"
+private const val USE_HOTWORD = "use_hotword"
+private const val FINISH_EARLY = "finish_early"
+private const val USE_INTENT_ACTION = "test.action.USE_CAMERA_OR_MIC"
+private const val PRIVACY_CHIP_ID = "com.android.systemui:id/privacy_chip"
+private const val PRIVACY_ITEM_ID = "com.android.systemui:id/privacy_item"
+private const val INDICATORS_FLAG = "camera_mic_icons_enabled"
+private const val PERMISSION_INDICATORS_NOT_PRESENT = 162547999L
+private const val IDLE_TIMEOUT_MILLIS: Long = 1000
+private const val UNEXPECTED_TIMEOUT_MILLIS = 1000L
+private const val TIMEOUT_MILLIS: Long = 20000
+private const val TV_MIC_INDICATOR_WINDOW_TITLE = "MicrophoneCaptureIndicator"
+private const val MIC_LABEL_NAME = "microphone_toggle_label_qs"
+private const val CAMERA_LABEL_NAME = "camera_toggle_label_qs"
+private val HOTWORD_DETECTION_SERVICE_REQUIRED =
+ SystemProperties.getBoolean("ro.hotword.detection_service_required", false)
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+@FlakyTest
+class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context: Context = instrumentation.context
+ private val uiAutomation: UiAutomation = instrumentation.uiAutomation
+ private val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+ private val packageManager: PackageManager = context.packageManager
+ private val permissionManager: PermissionManager =
+ context.getSystemService(PermissionManager::class.java)!!
+
+ private val isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ private val isCar = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ private val safetyCenterMicLabel = getPermissionControllerString(MIC_LABEL_NAME)
+ private val safetyCenterCameraLabel = getPermissionControllerString(CAMERA_LABEL_NAME)
+ private val originalCameraLabel =
+ packageManager
+ .getPermissionGroupInfo(Manifest.permission_group.CAMERA, 0)
+ .loadLabel(packageManager)
+ .toString()
+ private val originalMicLabel =
+ packageManager
+ .getPermissionGroupInfo(Manifest.permission_group.MICROPHONE, 0)
+ .loadLabel(packageManager)
+ .toString()
+ private val cameraLabel = originalCameraLabel.lowercase()
+ private val micLabel = originalMicLabel.lowercase()
+ private var wasEnabled = false
+ private var isScreenOn = false
+ private var screenTimeoutBeforeTest: Long = 0L
+ private lateinit var carMicPrivacyChipId: String
+ private lateinit var carCameraPrivacyChipId: String
+
+ @get:Rule val disableAnimationRule = DisableAnimationRule()
+
+ constructor() : super()
+
+ companion object {
+ private const val AUTO_MIC_INDICATOR_DISMISSAL_TIMEOUT_MS = 30_000L
+ const val SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
+ const val DELAY_MILLIS = 3000L
+ }
+
+ private val safetyCenterEnabled = callWithShellPermissionIdentity {
+ DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SAFETY_CENTER_ENABLED,
+ false.toString()
+ )!!
+ }
+
+ private fun uninstall() {
+ val output = runShellCommand("pm uninstall $APP_PKG").trim()
+ assertEquals("Success", output)
+ }
+
+ private fun install() {
+ val output = runShellCommandOrThrow("pm install -g $APK_PATH").trim()
+ assertEquals("Success", output)
+ }
+
+ @Before
+ fun setUp() {
+ runWithShellPermissionIdentity {
+ screenTimeoutBeforeTest =
+ Settings.System.getLong(context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT)
+ Settings.System.putLong(
+ context.contentResolver,
+ Settings.System.SCREEN_OFF_TIMEOUT,
+ 1800000L
+ )
+ }
+
+ if (!isScreenOn) {
+ uiDevice.wakeUp()
+ runShellCommand(instrumentation, "wm dismiss-keyguard")
+ Thread.sleep(DELAY_MILLIS)
+ isScreenOn = true
+ }
+ uiDevice.findObject(By.text("Close"))?.click()
+ wasEnabled = setIndicatorsEnabledStateIfNeeded(true)
+ // If the change Id is not present, then isChangeEnabled will return true. To bypass this,
+ // the change is set to "false" if present.
+ assumeFalse(
+ "feature not present on this device",
+ callWithShellPermissionIdentity {
+ CompatChanges.isChangeEnabled(PERMISSION_INDICATORS_NOT_PRESENT, Process.SYSTEM_UID)
+ }
+ )
+ install()
+ }
+
+ private fun setIndicatorsEnabledStateIfNeeded(shouldBeEnabled: Boolean): Boolean {
+ var currentlyEnabled = false
+ runWithShellPermissionIdentity {
+ currentlyEnabled =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, INDICATORS_FLAG, true)
+ if (currentlyEnabled != shouldBeEnabled) {
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ INDICATORS_FLAG,
+ shouldBeEnabled.toString(),
+ false
+ )
+ }
+ }
+ return currentlyEnabled
+ }
+
+ @After
+ fun tearDown() {
+ uninstall()
+ if (isCar) {
+ // Deselect the indicator since it persists otherwise
+ pressBack()
+ }
+ eventually(
+ { assertIndicatorsShown(false, false, false) },
+ AUTO_MIC_INDICATOR_DISMISSAL_TIMEOUT_MS
+ )
+ if (!wasEnabled) {
+ setIndicatorsEnabledStateIfNeeded(false)
+ }
+ runWithShellPermissionIdentity {
+ Settings.System.putLong(
+ context.contentResolver,
+ Settings.System.SCREEN_OFF_TIMEOUT,
+ screenTimeoutBeforeTest
+ )
+ }
+ changeSafetyCenterFlag(safetyCenterEnabled)
+ if (!isTv) {
+ pressBack()
+ pressBack()
+ }
+ pressHome()
+ pressHome()
+ }
+
+ private fun openApp(
+ useMic: Boolean,
+ useCamera: Boolean,
+ useHotword: Boolean,
+ finishEarly: Boolean = false
+ ) {
+ context.startActivity(
+ Intent(USE_INTENT_ACTION).apply {
+ putExtra(USE_CAMERA, useCamera)
+ putExtra(USE_MICROPHONE, useMic)
+ putExtra(USE_HOTWORD, useHotword)
+ putExtra(FINISH_EARLY, finishEarly)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
+ }
+
+ @Test
+ @CddTest(requirement = "9.8.2/H-5-1,T-5-1,A-2-1")
+ fun testCameraIndicator() {
+ // If camera is not available skip the test
+ assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY))
+ val manager = context.getSystemService(CameraManager::class.java)!!
+ assumeTrue(manager.cameraIdList.isNotEmpty())
+ changeSafetyCenterFlag(false.toString())
+ testCameraAndMicIndicator(useMic = false, useCamera = true)
+ }
+
+ @Test
+ @CddTest(requirement = "9.8.2/H-4-1,T-4-1,A-1-1")
+ fun testMicIndicator() {
+ changeSafetyCenterFlag(false.toString())
+ testCameraAndMicIndicator(useMic = true, useCamera = false)
+ }
+
+ // TODO b/269687722: remove once mainline presubmit uses a more recent S build
+ @Test
+ @AsbSecurityTest(cveBugId = [258672042])
+ fun testMicIndicatorWithManualFinishOpStillShows() {
+ changeSafetyCenterFlag(false.toString())
+ testCameraAndMicIndicator(useMic = true, useCamera = false, finishEarly = true)
+ }
+
+ @Test
+ @CddTest(requirement = "9.8.2/H-4-1,T-4-1,A-1-1")
+ fun testHotwordIndicatorBehavior() {
+ changeSafetyCenterFlag(false.toString())
+ testCameraAndMicIndicator(useMic = false, useCamera = false, useHotword = true)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ fun testChainUsageWithOtherUsage() {
+ // TV has only the mic icon
+ assumeFalse(isTv)
+ // Car has separate panels for mic and camera for now.
+ // TODO(b/218788634): enable this test for car once the new camera indicator is implemented.
+ assumeFalse(isCar)
+ // If camera is not available skip the test
+ assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY))
+ changeSafetyCenterFlag(false.toString())
+ testCameraAndMicIndicator(useMic = false, useCamera = true, chainUsage = true)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ fun testSafetyCenterCameraIndicator() {
+ assumeFalse(isTv)
+ assumeFalse(isCar)
+ val manager = context.getSystemService(CameraManager::class.java)!!
+ assumeTrue(manager.cameraIdList.isNotEmpty())
+ changeSafetyCenterFlag(true.toString())
+ assumeSafetyCenterEnabled()
+ testCameraAndMicIndicator(useMic = false, useCamera = true, safetyCenterEnabled = true)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ fun testSafetyCenterMicIndicator() {
+ assumeFalse(isTv)
+ assumeFalse(isCar)
+ changeSafetyCenterFlag(true.toString())
+ assumeSafetyCenterEnabled()
+ testCameraAndMicIndicator(useMic = true, useCamera = false, safetyCenterEnabled = true)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ fun testSafetyCenterHotwordIndicatorBehavior() {
+ assumeFalse(isTv)
+ assumeFalse(isCar)
+ assumeTrue(HOTWORD_DETECTION_SERVICE_REQUIRED)
+ changeSafetyCenterFlag(true.toString())
+ assumeSafetyCenterEnabled()
+ testCameraAndMicIndicator(
+ useMic = false,
+ useCamera = false,
+ useHotword = true,
+ safetyCenterEnabled = true
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ fun testSafetyCenterChainUsageWithOtherUsage() {
+ assumeFalse(isTv)
+ assumeFalse(isCar)
+ changeSafetyCenterFlag(true.toString())
+ assumeSafetyCenterEnabled()
+ testCameraAndMicIndicator(
+ useMic = false,
+ useCamera = true,
+ chainUsage = true,
+ safetyCenterEnabled = true
+ )
+ }
+
+ private fun testCameraAndMicIndicator(
+ useMic: Boolean,
+ useCamera: Boolean,
+ useHotword: Boolean = false,
+ chainUsage: Boolean = false,
+ safetyCenterEnabled: Boolean = false,
+ finishEarly: Boolean = false
+ ) {
+ // If camera is not available skip the test
+ if (useCamera) {
+ assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY))
+ }
+ var chainAttribution: AttributionSource? = null
+ openApp(useMic, useCamera, useHotword, finishEarly)
+ try {
+ eventually {
+ val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
+ assertTrue("View with text $APP_LABEL not found", appView.exists())
+ }
+ if (chainUsage) {
+ chainAttribution = createChainAttribution()
+ runWithShellPermissionIdentity {
+ val ret =
+ permissionManager.checkPermissionForStartDataDelivery(
+ Manifest.permission.RECORD_AUDIO,
+ chainAttribution!!,
+ ""
+ )
+ assertEquals(PermissionManager.PERMISSION_GRANTED, ret)
+ }
+ }
+
+ assertIndicatorsShown(useMic, useCamera, useHotword, chainUsage, safetyCenterEnabled)
+
+ if (finishEarly) {
+ // Assert that the indicator doesn't go away
+ val indicatorGoneException: Exception? =
+ try {
+ eventually { assertIndicatorsShown(false, false, false) }
+ null
+ } catch (e: Exception) {
+ e
+ }
+ assertNotNull("Expected the indicator to be present", indicatorGoneException)
+ }
+ } finally {
+ if (chainAttribution != null) {
+ runWithShellPermissionIdentity {
+ permissionManager.finishDataDelivery(
+ Manifest.permission.RECORD_AUDIO,
+ chainAttribution
+ )
+ }
+ }
+ }
+ }
+
+ private fun assertIndicatorsShown(
+ useMic: Boolean,
+ useCamera: Boolean,
+ useHotword: Boolean = false,
+ chainUsage: Boolean = false,
+ safetyCenterEnabled: Boolean = false,
+ ) {
+ if (isTv) {
+ assertTvIndicatorsShown(useMic, useCamera, useHotword)
+ } else if (isCar) {
+ assertCarIndicatorsShown(useMic, useCamera, useHotword, chainUsage)
+ } else {
+ uiDevice.openQuickSettings()
+ val micInUse =
+ if (SdkLevel.isAtLeastU() && HOTWORD_DETECTION_SERVICE_REQUIRED) {
+ useMic || useHotword
+ } else {
+ useMic
+ }
+ assertPrivacyChipAndIndicatorsPresent(
+ micInUse,
+ useCamera,
+ chainUsage,
+ safetyCenterEnabled
+ )
+ uiDevice.pressBack()
+ }
+ }
+
+ private fun assertTvIndicatorsShown(useMic: Boolean, useCamera: Boolean, useHotword: Boolean) {
+ if (useMic || useHotword || (!useMic && !useCamera && !useHotword)) {
+ eventually {
+ val found =
+ WindowManagerStateHelper().waitFor(
+ "Waiting for the mic indicator window to come up"
+ ) {
+ it.containsWindow(TV_MIC_INDICATOR_WINDOW_TITLE) &&
+ it.isWindowVisible(TV_MIC_INDICATOR_WINDOW_TITLE)
+ }
+ if (useMic) {
+ assertTrue("Did not find chip", found)
+ } else {
+ assertFalse("Found chip, but did not expect to", found)
+ }
+ }
+ }
+ if (useCamera) {
+ // There is no camera indicator on TVs.
+ }
+ }
+
+ private fun assertCarIndicatorsShown(
+ useMic: Boolean,
+ useCamera: Boolean,
+ useHotword: Boolean,
+ chainUsage: Boolean
+ ) {
+ eventually {
+ // Ensure the privacy chip is present (or not)
+ carMicPrivacyChipId = context.getString(R.string.car_mic_privacy_chip_id)
+ carCameraPrivacyChipId = context.getString(R.string.car_camera_privacy_chip_id)
+ var micPrivacyChip = uiDevice.findObject(By.res(carMicPrivacyChipId))
+ var cameraPrivacyChip = uiDevice.findObject(By.res(carCameraPrivacyChipId))
+ if (useMic) {
+ assertNotNull("Did not find mic chip", micPrivacyChip)
+ // Click to chip to show the panel.
+ micPrivacyChip.click()
+ } else if (useCamera) {
+ assertNotNull("Did not find camera chip", cameraPrivacyChip)
+ // Click to chip to show the panel.
+ cameraPrivacyChip.click()
+ } else {
+ assertNull("Found mic chip, but did not expect to", micPrivacyChip)
+ assertNull("Found camera chip, but did not expect to", cameraPrivacyChip)
+ }
+ }
+
+ eventually {
+ if (chainUsage) {
+ // Not applicable for car
+ assertChainMicAndOtherCameraUsed(false)
+ return@eventually
+ }
+ if (useMic) {
+ // There should be a mic privacy panel after mic privacy chip is clicked
+ val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel))
+ assertTrue("View with text $micLabel not found", micLabelView.exists())
+ val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
+ assertTrue("View with text $APP_LABEL not found", appView.exists())
+ } else if (useCamera) {
+ // There should be a camera privacy panel after camera privacy chip is clicked
+ val cameraLabelView = uiDevice.findObject(UiSelector().textContains(cameraLabel))
+ assertTrue("View with text $cameraLabel not found", cameraLabelView.exists())
+ val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
+ assertTrue("View with text $APP_LABEL not found", appView.exists())
+ } else {
+ // There should be no privacy panel when using hot word
+ val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel))
+ assertFalse(
+ "View with text $micLabel found, but did not expect to",
+ micLabelView.exists()
+ )
+ val cameraLabelView = uiDevice.findObject(UiSelector().textContains(cameraLabel))
+ assertFalse(
+ "View with text $cameraLabel found, but did not expect to",
+ cameraLabelView.exists()
+ )
+ val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
+ assertFalse(
+ "View with text $APP_LABEL found, but did not expect to",
+ appView.exists()
+ )
+ }
+ }
+ }
+
+ private fun assertPrivacyChipAndIndicatorsPresent(
+ useMic: Boolean,
+ useCamera: Boolean,
+ chainUsage: Boolean,
+ safetyCenterEnabled: Boolean = false
+ ) {
+ // Ensure the privacy chip is present
+ if (useCamera || useMic) {
+ eventually {
+ val privacyChip = UiAutomatorUtils2.waitFindObjectOrNull(By.res(PRIVACY_CHIP_ID))
+ assertNotNull("view with id $PRIVACY_CHIP_ID not found", privacyChip)
+ privacyChip.click()
+ }
+ } else {
+ UiAutomatorUtils2.waitUntilObjectGone(By.res(PRIVACY_CHIP_ID))
+ return
+ }
+
+ eventually {
+ if (chainUsage) {
+ assertChainMicAndOtherCameraUsed(safetyCenterEnabled)
+ return@eventually
+ }
+ if (useMic) {
+ if (safetyCenterEnabled) {
+ assertSafetyCenterMicViewNotNull()
+ } else {
+ val iconView = waitFindObject(By.descContains(micLabel))
+ assertNotNull("View with description '$micLabel' not found", iconView)
+ }
+ }
+ if (useCamera) {
+ if (safetyCenterEnabled) {
+ assertSafetyCenterCameraViewNotNull()
+ } else {
+ val iconView = waitFindObject(By.descContains(cameraLabel))
+ assertNotNull("View with description '$cameraLabel' not found", iconView)
+ }
+ }
+ var appView = waitFindObject(By.textContains(APP_LABEL))
+ assertNotNull("View with text $APP_LABEL not found", appView)
+ }
+ uiDevice.pressBack()
+ }
+
+ private fun createChainAttribution(): AttributionSource? {
+ var attrSource: AttributionSource? = null
+ runWithShellPermissionIdentity {
+ try {
+ val appUid = packageManager.getPackageUid(APP_PKG, 0)
+ val childAttribution = AttributionSource(appUid, APP_PKG, null)
+ val attribution =
+ AttributionSource(
+ Process.myUid(),
+ context.packageName,
+ null,
+ null,
+ permissionManager.registerAttributionSource(childAttribution)
+ )
+ attrSource = permissionManager.registerAttributionSource(attribution)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Assert.fail("Expected to find a UID for $APP_LABEL")
+ }
+ }
+ return attrSource
+ }
+
+ private fun assertChainMicAndOtherCameraUsed(safetyCenterEnabled: Boolean) {
+ val shellLabel =
+ try {
+ context.packageManager
+ .getApplicationInfo(SHELL_PKG, 0)
+ .loadLabel(context.packageManager)
+ .toString()
+ } catch (e: PackageManager.NameNotFoundException) {
+ "Did not find shell package"
+ }
+
+ if (safetyCenterEnabled) {
+ assertSafetyCenterMicViewNotNull()
+ assertSafetyCenterCameraViewNotNull()
+ var shellView = waitFindObject(By.textContains(shellLabel))
+ assertNotNull("View with text $shellLabel not found", shellView)
+ } else {
+ val usageViews = uiDevice.findObjects(By.res(PRIVACY_ITEM_ID))
+ assertEquals("Expected two usage views", 2, usageViews.size)
+ val appViews = uiDevice.findObjects(By.textContains(APP_LABEL))
+ assertEquals("Expected two $APP_LABEL view", 2, appViews.size)
+ val shellView = uiDevice.findObjects(By.textContains(shellLabel))
+ assertEquals("Expected only one shell view", 1, shellView.size)
+ }
+ }
+
+ private fun pressBack() {
+ uiDevice.pressBack()
+ }
+
+ private fun pressHome() {
+ uiDevice.pressHome()
+ }
+
+ private fun changeSafetyCenterFlag(safetyCenterEnabled: String) {
+ runWithShellPermissionIdentity {
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SAFETY_CENTER_ENABLED,
+ safetyCenterEnabled,
+ false
+ )
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private fun assumeSafetyCenterEnabled() {
+ val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
+ val isSafetyCenterEnabled: Boolean =
+ runWithShellPermissionIdentity<Boolean> { safetyCenterManager.isSafetyCenterEnabled }
+ assumeTrue(isSafetyCenterEnabled)
+ }
+
+ protected fun waitFindObject(selector: BySelector): UiObject2? {
+ return findObjectWithRetry({ t -> UiAutomatorUtils2.waitFindObject(selector, t) })
+ }
+
+ private fun findObjectWithRetry(
+ automatorMethod: (timeoutMillis: Long) -> UiObject2?,
+ timeoutMillis: Long = TIMEOUT_MILLIS
+ ): UiObject2? {
+ val startTime = SystemClock.elapsedRealtime()
+ return try {
+ automatorMethod(timeoutMillis)
+ } catch (e: StaleObjectException) {
+ val remainingTime = timeoutMillis - (SystemClock.elapsedRealtime() - startTime)
+ if (remainingTime <= 0) {
+ throw e
+ }
+ automatorMethod(remainingTime)
+ }
+ }
+
+ private fun getPermissionControllerString(resourceName: String): String {
+ val permissionControllerPkg = context.packageManager.permissionControllerPackageName
+ try {
+ val permissionControllerContext =
+ context.createPackageContext(permissionControllerPkg, 0)
+ val resourceId =
+ permissionControllerContext.resources.getIdentifier(
+ resourceName,
+ "string",
+ "com.android.permissioncontroller"
+ )
+ return permissionControllerContext.getString(resourceId)
+ } catch (e: PackageManager.NameNotFoundException) {
+ throw RuntimeException(e)
+ }
+ }
+
+ private fun assertSafetyCenterMicViewNotNull() {
+ val micView = waitFindObject(byOneOfText(originalMicLabel, safetyCenterMicLabel))
+ assertNotNull(
+ "View with text '$originalMicLabel' or '$safetyCenterMicLabel' not found",
+ micView
+ )
+ }
+
+ private fun assertSafetyCenterCameraViewNotNull() {
+ val cameraView = waitFindObject(byOneOfText(originalCameraLabel, safetyCenterCameraLabel))
+ assertNotNull(
+ "View with text '$originalCameraLabel' or '$safetyCenterCameraLabel' not found",
+ cameraView
+ )
+ }
+
+ private fun byOneOfText(vararg textValues: String) =
+ By.text(Pattern.compile(textValues.joinToString(separator = "|") { Pattern.quote(it) }))
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/LocationAccuracyTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/LocationAccuracyTest.kt
new file mode 100644
index 000000000..176010cf5
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/LocationAccuracyTest.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
+import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import androidx.test.filters.FlakyTest
+import androidx.test.uiautomator.By
+import com.android.modules.utils.build.SdkLevel
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+
+@FlakyTest
+class LocationAccuracyTest : BaseUsePermissionTest() {
+
+ companion object {
+ private const val LOCATION_ACCURACY_PRECISE_RADIO_BUTTON =
+ "com.android.permissioncontroller:id/permission_location_accuracy_radio_fine"
+ private const val LOCATION_ACCURACY_COARSE_RADIO_BUTTON =
+ "com.android.permissioncontroller:id/permission_location_accuracy_radio_coarse"
+ private const val LOCATION_ACCURACY_PRECISE_ONLY_VIEW =
+ "com.android.permissioncontroller:id/permission_location_accuracy_fine_only"
+ private const val LOCATION_ACCURACY_COARSE_ONLY_VIEW =
+ "com.android.permissioncontroller:id/permission_location_accuracy_coarse_only"
+ }
+
+ @Before
+ fun setup() {
+ assumeTrue("Location Accuracy is only available on S+", SdkLevel.isAtLeastS())
+ assumeFalse(isAutomotive)
+ assumeFalse(isTv)
+ assumeFalse(isWatch)
+ }
+
+ @Test
+ fun testCoarsePermissionIsGranted() {
+ installPackage(APP_APK_PATH_31)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_BACKGROUND_LOCATION, false)
+
+ requestAppPermissionsAndAssertResult(
+ ACCESS_FINE_LOCATION to false,
+ ACCESS_COARSE_LOCATION to true
+ ) {
+ clickCoarseLocationRadioButton()
+ clickPreciseLocationRadioButton()
+ clickCoarseLocationRadioButton()
+ clickPermissionRequestAllowForegroundButton()
+ }
+ }
+
+ @Test
+ fun testPrecisePermissionIsGranted() {
+ installPackage(APP_APK_PATH_31)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_BACKGROUND_LOCATION, false)
+
+ requestAppPermissionsAndAssertResult(
+ ACCESS_FINE_LOCATION to true,
+ ACCESS_COARSE_LOCATION to true
+ ) {
+ clickPreciseLocationRadioButton()
+ clickCoarseLocationRadioButton()
+ clickPreciseLocationRadioButton()
+ clickPermissionRequestAllowForegroundButton()
+ }
+ }
+
+ @Test
+ fun testPermissionUpgradeFlow() {
+ installPackage(APP_APK_PATH_31)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_BACKGROUND_LOCATION, false)
+
+ requestAppPermissionsAndAssertResult(
+ ACCESS_FINE_LOCATION to false,
+ ACCESS_COARSE_LOCATION to true
+ ) {
+ clickCoarseLocationRadioButton()
+ clickPreciseLocationRadioButton()
+ clickCoarseLocationRadioButton()
+ clickPermissionRequestAllowForegroundButton()
+ }
+
+ // now request again to change to precise location
+ requestAppPermissionsAndAssertResult(
+ ACCESS_FINE_LOCATION to true,
+ ACCESS_COARSE_LOCATION to true
+ ) {
+ clickPreciseLocationOnlyView()
+ clickPermissionRequestAllowForegroundButton()
+ }
+ }
+
+ @Test
+ fun testCoarseRequestAndGrant() {
+ installPackage(APP_APK_PATH_31)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_BACKGROUND_LOCATION, false)
+
+ requestAppPermissionsAndAssertResult(ACCESS_COARSE_LOCATION to true) {
+ clickCoarseLocationOnlyView()
+ clickPermissionRequestAllowForegroundButton()
+ }
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(ACCESS_BACKGROUND_LOCATION, false)
+ }
+
+ @Test
+ fun testPreSAppsAutograntFineIfCoarseGranted() {
+ installPackage(APP_APK_PATH_30)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ requestAppPermissionsAndAssertResult(ACCESS_COARSE_LOCATION to true) {
+ clickPermissionRequestAllowForegroundButton()
+ }
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ requestAppPermissionsAndAssertResult(
+ ACCESS_FINE_LOCATION to true,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ private fun clickPreciseLocationRadioButton() {
+ click(By.res(LOCATION_ACCURACY_PRECISE_RADIO_BUTTON))
+ }
+
+ private fun clickCoarseLocationRadioButton() {
+ click(By.res(LOCATION_ACCURACY_COARSE_RADIO_BUTTON))
+ }
+
+ private fun clickPreciseLocationOnlyView() {
+ click(By.res(LOCATION_ACCURACY_PRECISE_ONLY_VIEW))
+ }
+
+ private fun clickCoarseLocationOnlyView() {
+ click(By.res(LOCATION_ACCURACY_COARSE_ONLY_VIEW))
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/LocationProviderInterceptDialogTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/LocationProviderInterceptDialogTest.kt
new file mode 100644
index 000000000..e7920edfd
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/LocationProviderInterceptDialogTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.Activity
+import android.app.AppOpsManager
+import android.content.ComponentName
+import android.content.Intent
+import android.location.LocationManager
+import android.os.Build
+import android.permission.cts.MtsIgnore
+import android.permission.cts.PermissionUtils
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.AppOpsUtils
+import com.android.compatibility.common.util.CddTest
+import com.android.compatibility.common.util.SystemUtil
+import java.util.concurrent.TimeUnit
+import org.junit.Assert
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+
+private const val EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME"
+private const val ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS"
+
+/**
+ * Tests that LocationProviderInterceptDialog (a warning dialog) shows when attempting to view the
+ * location permission for location a service provider app (e.g., usually GMS, but we use a custom
+ * app in this test).
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+@FlakyTest
+@CddTest(requirement = "9.1/C-0-1")
+class LocationProviderInterceptDialogTest : BaseUsePermissionTest() {
+ @Before
+ fun setup() {
+ assumeFalse(isAutomotive)
+ assumeFalse(isTv)
+ assumeFalse(isWatch)
+ installPackage(MIC_LOCATION_PROVIDER_APP_APK_PATH, grantRuntimePermissions = true)
+ AppOpsUtils.setOpMode(
+ MIC_LOCATION_PROVIDER_APP_PACKAGE_NAME,
+ AppOpsManager.OPSTR_MOCK_LOCATION,
+ AppOpsManager.MODE_ALLOWED
+ )
+ enableMicrophoneAppAsLocationProvider()
+ }
+
+ @Test
+ @Ignore("b/288471744")
+ @MtsIgnore(bugId = 288471744)
+ fun clickLocationPermission_showDialog_clickOk() {
+ openPermissionScreenForApp()
+ clickAndWaitForWindowTransition(By.text("Location"))
+ findView(By.textContains("Location access can be modified from location settings"), true)
+ click(By.res(OK_BUTTON_RES))
+ }
+
+ @Test
+ @Ignore("b/288471744")
+ @MtsIgnore(bugId = 288471744)
+ fun clickLocationPermission_showDialog_clickLocationAccess() {
+ openPermissionScreenForApp()
+ clickAndWaitForWindowTransition(By.text("Location"))
+ findView(By.textContains("Location access can be modified from location settings"), true)
+ clickAndWaitForWindowTransition(By.res(LOCATION_ACCESS_BUTTON_RES))
+ findView(By.res(USE_LOCATION_LABEL_ID), true)
+ }
+
+ @Test
+ @Ignore("b/288471744")
+ @MtsIgnore(bugId = 288471744)
+ fun checkRestrictedPermissions() {
+ context.sendBroadcast(
+ Intent(PermissionTapjackingTest.ACTION_SHOW_OVERLAY)
+ .putExtra("package", MIC_LOCATION_PROVIDER_APP_PACKAGE_NAME)
+ .putExtra("permission", "android.permission.BACKGROUND_CAMERA")
+ )
+ }
+
+ private fun openPermissionScreenForApp() {
+ restartPermissionController()
+ doAndWaitForWindowTransition {
+ SystemUtil.runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(ACTION_MANAGE_APP_PERMISSIONS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ putExtra(EXTRA_PACKAGE_NAME, MIC_LOCATION_PROVIDER_APP_PACKAGE_NAME)
+ }
+ )
+ }
+ }
+ }
+
+ private fun restartPermissionController() {
+ PermissionUtils.clearAppState(permissionControllerPackageName)
+ }
+
+ private fun enableMicrophoneAppAsLocationProvider() {
+ val locationManager = context.getSystemService(LocationManager::class.java)!!
+ val future =
+ startActivityForFuture(
+ Intent().apply {
+ component =
+ ComponentName(
+ MIC_LOCATION_PROVIDER_APP_PACKAGE_NAME,
+ "$MIC_LOCATION_PROVIDER_APP_PACKAGE_NAME.AddLocationProviderActivity"
+ )
+ }
+ )
+ val result = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ Assert.assertEquals(Activity.RESULT_OK, result.resultCode)
+ Assert.assertTrue(
+ SystemUtil.callWithShellPermissionIdentity {
+ locationManager.isProviderPackage(MIC_LOCATION_PROVIDER_APP_PACKAGE_NAME)
+ }
+ )
+ }
+
+ companion object {
+ private const val USE_LOCATION_LABEL_ID = "com.android.settings:id/switch_text"
+ private const val MIC_LOCATION_PROVIDER_APP_APK_PATH =
+ "$APK_DIRECTORY/CtsAccessMicrophoneAppLocationProvider.apk"
+ private const val MIC_LOCATION_PROVIDER_APP_PACKAGE_NAME =
+ "android.permissionui.cts.accessmicrophoneapplocationprovider"
+ private const val OK_BUTTON_RES = "android:id/button2"
+ private const val LOCATION_ACCESS_BUTTON_RES = "android:id/button1"
+ private val permissionControllerPackageName =
+ context.packageManager.permissionControllerPackageName
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionTest.kt
new file mode 100644
index 000000000..d41c7454f
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionTest.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest
+import android.os.Build
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.util.CddTest
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.Assume
+import org.junit.Test
+
+/**
+ * Tests media storage supergroup behavior. I.e., on a T+ platform, for legacy (targetSdk<T) apps,
+ * the storage permission groups (STORAGE, AURAL, and VISUAL) form a supergroup, which effectively
+ * treats them as one group and therefore their permission state must always be equal.
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+@CddTest(requirement = "9.1/C-0-1")
+@FlakyTest
+class MediaPermissionTest : BaseUsePermissionTest() {
+ private fun assertStorageAndMediaPermissionState(state: Boolean) {
+ for (permission in STORAGE_AND_MEDIA_PERMISSIONS) {
+ assertAppHasPermission(permission, state)
+ }
+ }
+
+ @Test
+ fun testWhenRESIsGrantedFromGrantDialogThenShouldGrantAllPermissions() {
+ installPackage(APP_APK_PATH_23)
+ requestAppPermissionsAndAssertResult(Manifest.permission.READ_EXTERNAL_STORAGE to true) {
+ clickPermissionRequestAllowButton()
+ }
+ assertStorageAndMediaPermissionState(true)
+ }
+
+ @Test
+ fun testWhenRESIsGrantedManuallyThenShouldGrantAllPermissions() {
+ installPackage(APP_APK_PATH_23)
+ grantAppPermissionsByUi(Manifest.permission.READ_EXTERNAL_STORAGE)
+ assertStorageAndMediaPermissionState(true)
+ }
+
+ @Test
+ fun testWhenAuralIsGrantedManuallyThenShouldGrantAllPermissions() {
+ installPackage(APP_APK_PATH_23)
+ grantAppPermissionsByUi(Manifest.permission.READ_MEDIA_AUDIO)
+ assertStorageAndMediaPermissionState(true)
+ }
+
+ @Test
+ fun testWhenVisualIsGrantedManuallyThenShouldGrantAllPermissions() {
+ installPackage(APP_APK_PATH_23)
+ grantAppPermissionsByUi(Manifest.permission.READ_MEDIA_VIDEO)
+ assertStorageAndMediaPermissionState(true)
+ }
+
+ @Test
+ fun testWhenRESIsDeniedFromGrantDialogThenShouldDenyAllPermissions() {
+ installPackage(APP_APK_PATH_23)
+ requestAppPermissionsAndAssertResult(Manifest.permission.READ_EXTERNAL_STORAGE to false) {
+ clickPermissionRequestDenyButton()
+ }
+ assertStorageAndMediaPermissionState(false)
+ }
+
+ @Test
+ fun testWhenRESIsDeniedManuallyThenShouldDenyAllPermissions() {
+ installPackage(APP_APK_PATH_23)
+ grantAppPermissionsByUi(Manifest.permission.READ_EXTERNAL_STORAGE)
+ assertStorageAndMediaPermissionState(true)
+ revokeAppPermissionsByUi(Manifest.permission.READ_EXTERNAL_STORAGE)
+ assertStorageAndMediaPermissionState(false)
+ }
+
+ @Test
+ fun testWhenAuralIsDeniedManuallyThenShouldDenyAllPermissions() {
+ installPackage(APP_APK_PATH_23)
+ grantAppPermissionsByUi(Manifest.permission.READ_MEDIA_AUDIO)
+ revokeAppPermissionsByUi(Manifest.permission.READ_MEDIA_AUDIO)
+ assertStorageAndMediaPermissionState(false)
+ }
+
+ @Test
+ fun testWhenVisualIsDeniedManuallyThenShouldDenyAllPermissions() {
+ // TODO: Re-enable after b/239249703 is fixed
+ Assume.assumeFalse("skip on TV due to flaky", isTv)
+ installPackage(APP_APK_PATH_23)
+ grantAppPermissionsByUi(Manifest.permission.READ_MEDIA_VIDEO)
+ revokeAppPermissionsByUi(Manifest.permission.READ_MEDIA_VIDEO)
+ assertStorageAndMediaPermissionState(false)
+ }
+
+ @Test
+ fun testWhenA33AppRequestsStorageThenNoDialogAndNoGrant() {
+ installPackage(APP_APK_PATH_MEDIA_PERMISSION_33_WITH_STORAGE)
+ requestAppPermissions(
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ waitForWindowTransition = false
+ ) {}
+ assertStorageAndMediaPermissionState(false)
+ }
+
+ @Test
+ fun testWhenA33AppRequestsAuralThenDialogAndGrant() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissions(Manifest.permission.READ_MEDIA_AUDIO) {
+ clickPermissionRequestAllowButton()
+ }
+ assertAppHasPermission(Manifest.permission.READ_EXTERNAL_STORAGE, false)
+ assertAppHasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, false)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_AUDIO, true)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_VIDEO, false)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_IMAGES, false)
+ }
+
+ @Test
+ fun testWhenA33AppRequestsVisualThenDialogAndGrant() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissions(
+ Manifest.permission.READ_MEDIA_VIDEO,
+ Manifest.permission.READ_MEDIA_IMAGES
+ ) {
+ if (isPhotoPickerPermissionPromptEnabled()) {
+ clickPermissionRequestAllowAllButton()
+ } else {
+ clickPermissionRequestAllowButton()
+ }
+ }
+ assertAppHasPermission(Manifest.permission.READ_EXTERNAL_STORAGE, false)
+ assertAppHasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, false)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_AUDIO, false)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_VIDEO, true)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_IMAGES, true)
+ }
+
+ @Test
+ fun testWhenA30AppRequestsStorageWhenMediaPermsHaveRWRFlag() {
+ installPackage(APP_APK_PATH_30)
+
+ requestAppPermissionsAndAssertResult(Manifest.permission.READ_EXTERNAL_STORAGE to true) {
+ clickPermissionRequestAllowButton()
+ }
+
+ fun setRevokeWhenRequested(permission: String) =
+ SystemUtil.runShellCommandOrThrow(
+ "pm set-permission-flags android.permissionui.cts.usepermission " +
+ permission +
+ " revoke-when-requested"
+ )
+ setRevokeWhenRequested("android.permission.READ_MEDIA_AUDIO")
+ setRevokeWhenRequested("android.permission.READ_MEDIA_VIDEO")
+ setRevokeWhenRequested("android.permission.READ_MEDIA_IMAGES")
+
+ requestAppPermissionsAndAssertResult(
+ Manifest.permission.READ_EXTERNAL_STORAGE to true,
+ waitForWindowTransition = false
+ ) {
+ // No dialog should appear
+ }
+
+ assertAppHasPermission(Manifest.permission.READ_EXTERNAL_STORAGE, true)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_AUDIO, true)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_VIDEO, true)
+ assertAppHasPermission(Manifest.permission.READ_MEDIA_IMAGES, true)
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionUpgradeTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionUpgradeTest.kt
new file mode 100644
index 000000000..40c09ea8c
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionUpgradeTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.READ_EXTERNAL_STORAGE
+import android.Manifest.permission.READ_MEDIA_AUDIO
+import android.Manifest.permission.READ_MEDIA_IMAGES
+import android.Manifest.permission.READ_MEDIA_VIDEO
+import android.os.Build
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.util.CddTest
+import org.junit.Test
+
+/** Tests media storage permission behavior upon app upgrade. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+@CddTest(requirement = "9.1/C-0-1")
+@FlakyTest
+class MediaPermissionUpgradeTest : BaseUsePermissionTest() {
+ @Test
+ fun testAfterUpgradeToTiramisuThenNoGrantDialogShownForMediaPerms() {
+ // Install 32
+ installPackage(APP_APK_PATH_32)
+
+ // Request STORAGE, and click allow
+ requestAppPermissionsAndAssertResult(
+ READ_EXTERNAL_STORAGE to true,
+ waitForWindowTransition = !isWatch
+ ) {
+ clickPermissionRequestAllowButton()
+ }
+
+ // Upgrade 32 -> 33
+ installPackage(APP_APK_PATH_LATEST, reinstall = true)
+
+ // Request READ_MEDIA_*
+ requestAppPermissionsAndAssertResult(
+ READ_MEDIA_AUDIO to true,
+ READ_MEDIA_VIDEO to true,
+ READ_MEDIA_IMAGES to true,
+ waitForWindowTransition = false
+ ) {
+ // Don't click any grant dialog buttons because no grant dialog should appear
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/NoPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/NoPermissionTest.kt
new file mode 100644
index 000000000..a5d428812
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/NoPermissionTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.Activity
+import androidx.test.filters.FlakyTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.modules.utils.build.SdkLevel
+import org.junit.Assume
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@FlakyTest
+class NoPermissionTest : BaseUsePermissionTest() {
+ @Test
+ fun testStartActivity22() {
+ Assume.assumeFalse(SdkLevel.isAtLeastT())
+ installPackage(APP_APK_PATH_22_NONE)
+
+ startAppActivityAndAssertResultCode(Activity.RESULT_OK) {}
+
+ clearTargetSdkWarning()
+ }
+
+ @Test
+ fun testStartActivityLatest() {
+ installPackage(APP_APK_PATH_LATEST_NONE)
+
+ startAppActivityAndAssertResultCode(Activity.RESULT_OK) {}
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/NotificationPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/NotificationPermissionTest.kt
new file mode 100644
index 000000000..9b72d1706
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/NotificationPermissionTest.kt
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.POST_NOTIFICATIONS
+import android.Manifest.permission.RECORD_AUDIO
+import android.app.ActivityOptions
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Context.RECEIVER_EXPORTED
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
+import android.os.Build
+import android.os.UserHandle
+import android.provider.Settings
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import java.util.concurrent.CountDownLatch
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+
+const val EXTRA_CREATE_CHANNELS = "extra_create"
+const val EXTRA_REQUEST_OTHER_PERMISSIONS = "extra_request_permissions"
+const val EXTRA_REQUEST_NOTIF_PERMISSION = "extra_request_notif_permission"
+const val EXTRA_START_SECOND_ACTIVITY = "extra_start_second_activity"
+const val EXTRA_START_SECOND_APP = "extra_start_second_app"
+const val ACTIVITY_LABEL = "CreateNotif"
+const val SECOND_ACTIVITY_LABEL = "EmptyActivity"
+const val ALLOW = "to send you"
+const val INTENT_ACTION = "usepermission.createchannels.MAIN"
+const val BROADCAST_ACTION = "usepermission.createchannels.BROADCAST"
+const val NOTIFICATION_PERMISSION_ENABLED = "notification_permission_enabled"
+const val EXPECTED_TIMEOUT_MS = 2000L
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+@FlakyTest
+class NotificationPermissionTest : BaseUsePermissionTest() {
+
+ private val cr = callWithShellPermissionIdentity {
+ context.createContextAsUser(UserHandle.SYSTEM, 0).contentResolver
+ }
+ private var previousEnableState = -1
+ private var countDown: CountDownLatch = CountDownLatch(1)
+ private var allowedGroups = listOf<String>()
+ private val receiver: BroadcastReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ allowedGroups =
+ intent?.getStringArrayListExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS
+ )
+ ?: emptyList()
+ countDown.countDown()
+ }
+ }
+
+ @Before
+ fun setLatchAndEnablePermission() {
+ // b/220968160: Notification permission is not enabled on TV devices.
+ assumeFalse(isTv)
+ runWithShellPermissionIdentity {
+ previousEnableState = Settings.Secure.getInt(cr, NOTIFICATION_PERMISSION_ENABLED, 0)
+ Settings.Secure.putInt(cr, NOTIFICATION_PERMISSION_ENABLED, 1)
+ }
+ countDown = CountDownLatch(1)
+ allowedGroups = listOf()
+ context.registerReceiver(receiver, IntentFilter(BROADCAST_ACTION), RECEIVER_EXPORTED)
+ }
+
+ @After
+ fun resetPermissionAndRemoveReceiver() {
+ if (previousEnableState >= 0) {
+ runWithShellPermissionIdentity {
+ Settings.Secure.putInt(cr, NOTIFICATION_PERMISSION_ENABLED, previousEnableState)
+ }
+ context.unregisterReceiver(receiver)
+ }
+ }
+
+ @Test
+ fun notificationPermissionAddedForLegacyApp() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ runWithShellPermissionIdentity {
+ Assert.assertTrue(
+ "SDK < 32 apps should have POST_NOTIFICATIONS added implicitly",
+ context.packageManager
+ .getPackageInfo(APP_PACKAGE_NAME, PackageManager.GET_PERMISSIONS)
+ .requestedPermissions!!
+ .contains(POST_NOTIFICATIONS)
+ )
+ }
+ }
+
+ @Test
+ fun notificationPermissionIsNotImplicitlyAddedTo33Apps() {
+ installPackage(APP_APK_PATH_LATEST_NONE, expectSuccess = true)
+ runWithShellPermissionIdentity {
+ val requestedPerms =
+ context.packageManager
+ .getPackageInfo(APP_PACKAGE_NAME, PackageManager.GET_PERMISSIONS)
+ .requestedPermissions
+ Assert.assertTrue(
+ "SDK >= 33 apps should NOT have POST_NOTIFICATIONS added implicitly",
+ requestedPerms == null || !requestedPerms.contains(POST_NOTIFICATIONS)
+ )
+ }
+ }
+
+ @Test
+ fun notificationPromptShowsForLegacyAppAfterCreatingNotificationChannels() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp()
+ clickPermissionRequestAllowButton()
+ }
+
+ @Test
+ fun notificationPromptShowsForLegacyAppWithNotificationChannelsOnStart() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ // create channels, then leave the app
+ launchApp()
+ killTestApp()
+ launchApp()
+ waitFindObject(By.textContains(ALLOW))
+ clickPermissionRequestAllowButton()
+ }
+
+ @Test
+ fun notificationPromptDoesNotShowForLegacyAppWithNoNotificationChannels_onLaunch() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(createChannels = false)
+ assertDialogNotShowing()
+ }
+ @Test
+ fun notificationPromptDoesNotShowForNonLauncherIntentCategoryLaunches_onChannelCreate() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(launcherCategory = false)
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptDoesNotShowForNonLauncherIntentCategoryLaunches_onLaunch() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ // create channels, then leave the app
+ launchApp()
+ killTestApp()
+ launchApp(launcherCategory = false)
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptDoesNotShowForNonMainIntentActionLaunches_onLaunch() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ // create channels, then leave the app
+ launchApp()
+ killTestApp()
+ launchApp(intentAction = INTENT_ACTION)
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptDoesNotShowForNonMainIntentActionLaunches_onChannelCreate() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(intentAction = INTENT_ACTION)
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptShowsIfActivityOptionSet() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ // create channels, then leave the app
+ launchApp()
+ killTestApp()
+ launchApp(intentAction = INTENT_ACTION, isEligibleForPromptOption = true)
+ clickPermissionRequestAllowButton()
+ }
+
+ @Test
+ fun notificationPromptShownForSubsequentStartsIfTaskStartWasLauncher() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(startSecondActivity = true)
+ if (isAutomotive || isWatch) {
+ waitFindObject(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)))
+ } else {
+ waitFindObject(By.res(ALLOW_BUTTON))
+ }
+ pressBack()
+ clickPermissionRequestAllowButton()
+ }
+
+ @Test
+ fun notificationPromptNotShownForSubsequentStartsIfTaskStartWasNotLauncher() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(intentAction = INTENT_ACTION, startSecondActivity = true)
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptShownForChannelCreateInSecondActivityIfTaskStartWasLauncher() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(startSecondActivity = true, createChannels = false)
+ clickPermissionRequestAllowButton()
+ }
+
+ @Test
+ fun notificationPromptNotShownForChannelCreateInSecondActivityIfTaskStartWasntLauncher() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(intentAction = INTENT_ACTION, startSecondActivity = true, createChannels = false)
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptNotShownForSubsequentStartsIfSubsequentIsDifferentPkg() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ installPackage(APP_APK_PATH_OTHER_APP, expectSuccess = true)
+ // perform a launcher start, then start a secondary app
+ launchApp(startSecondaryAppAndCreateChannelsAfterSecondStart = true)
+ try {
+ // Watch does not have app bar
+ if (!isWatch) {
+ waitFindObject(By.textContains(SECOND_ACTIVITY_LABEL))
+ }
+ assertDialogNotShowing()
+ } finally {
+ uninstallPackage(OTHER_APP_PACKAGE_NAME)
+ }
+ }
+
+ @Test
+ fun notificationGrantedOnLegacyGrant() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp()
+ clickPermissionRequestAllowButton()
+ assertAppPermissionGrantedState(POST_NOTIFICATIONS, granted = true)
+ }
+
+ @Test
+ fun nonSystemServerPackageCannotShowPromptForOtherPackage() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ runWithShellPermissionIdentity {
+ val grantPermission = Intent(PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER)
+ grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME)
+ grantPermission.putExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES,
+ arrayOf(POST_NOTIFICATIONS)
+ )
+ grantPermission.setPackage(context.packageManager.permissionControllerPackageName)
+ grantPermission.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ context.startActivity(grantPermission)
+ }
+ try {
+ clickPermissionRequestAllowButton(timeoutMillis = EXPECTED_TIMEOUT_MS)
+ Assert.fail("Expected not to find permission request dialog")
+ } catch (expected: RuntimeException) {
+ // Do nothing
+ }
+ }
+
+ @Test
+ fun mergeAppPermissionRequestIntoNotificationAndVerifyResult() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp()
+ findPermissionRequestAllowButton()
+ // Notification dialog is showing, trigger RECORD_AUDIO check, and wait until it has been
+ // requested
+ val intent = createIntent(requestPermissions = true, intentAction = BROADCAST_ACTION)
+ context.sendBroadcast(intent)
+ countDown.await()
+ Thread.sleep(1000)
+ // reset countDownLatch
+ countDown = CountDownLatch(1)
+
+ clickPermissionRequestAllowButton()
+ assertAppPermissionGrantedState(POST_NOTIFICATIONS, granted = true)
+ clickPermissionRequestAllowForegroundButton()
+ assertAppPermissionGrantedState(RECORD_AUDIO, granted = true)
+ countDown.await()
+ // Result should contain only the microphone request
+ Assert.assertEquals(listOf(RECORD_AUDIO), allowedGroups)
+ }
+
+ @Test
+ fun mergeNotificationRequestIntoAppPermissionRequestAndVerifyResult() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(createChannels = false, requestPermissions = true)
+ findPermissionRequestAllowForegroundButton()
+ // Microphone dialog is showing, trigger Notification check, and wait until it has been
+ // requested
+ val intent = createIntent(createChannels = true, intentAction = BROADCAST_ACTION)
+ context.sendBroadcast(intent)
+ countDown.await()
+ Thread.sleep(1000)
+ // reset countDownLatch
+ countDown = CountDownLatch(1)
+
+ clickPermissionRequestAllowForegroundButton()
+ assertAppPermissionGrantedState(RECORD_AUDIO, granted = true)
+ clickPermissionRequestAllowButton()
+ assertAppPermissionGrantedState(POST_NOTIFICATIONS, granted = true)
+ countDown.await()
+ // Result should contain only the microphone request
+ Assert.assertEquals(listOf(RECORD_AUDIO), allowedGroups)
+ }
+
+ @Test
+ fun legacyAppCannotExplicitlyRequestNotifications() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(createChannels = false, requestNotificationPermission = true)
+ try {
+ clickPermissionRequestAllowButton(timeoutMillis = EXPECTED_TIMEOUT_MS)
+ Assert.fail("Expected not to find permission request dialog")
+ } catch (expected: RuntimeException) {
+ // Do nothing
+ }
+ }
+
+ private fun assertAppPermissionGrantedState(permission: String, granted: Boolean) {
+ SystemUtil.eventually {
+ runWithShellPermissionIdentity {
+ Assert.assertEquals(
+ "Expected $permission to be granted",
+ context.packageManager.checkPermission(permission, APP_PACKAGE_NAME),
+ PERMISSION_GRANTED
+ )
+ }
+ }
+ }
+
+ private fun createIntent(
+ createChannels: Boolean = true,
+ requestNotificationPermission: Boolean = false,
+ requestPermissions: Boolean = false,
+ launcherCategory: Boolean = true,
+ intentAction: String = Intent.ACTION_MAIN,
+ startSecondActivity: Boolean = false,
+ startSecondaryAppAndCreateChannelsAfterSecondStart: Boolean = false
+ ): Intent {
+ val intent =
+ if (intentAction == Intent.ACTION_MAIN && launcherCategory) {
+ packageManager.getLaunchIntentForPackage(APP_PACKAGE_NAME)!!
+ } else {
+ Intent(intentAction)
+ }
+
+ intent.`package` = APP_PACKAGE_NAME
+ intent.putExtra(EXTRA_CREATE_CHANNELS, createChannels)
+ intent.putExtra(EXTRA_REQUEST_OTHER_PERMISSIONS, requestPermissions)
+ intent.putExtra(EXTRA_REQUEST_NOTIF_PERMISSION, requestNotificationPermission)
+ intent.putExtra(EXTRA_START_SECOND_ACTIVITY, startSecondActivity)
+ intent.putExtra(EXTRA_START_SECOND_APP, startSecondaryAppAndCreateChannelsAfterSecondStart)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ return intent
+ }
+
+ private fun launchApp(
+ createChannels: Boolean = true,
+ requestNotificationPermission: Boolean = false,
+ requestPermissions: Boolean = false,
+ launcherCategory: Boolean = true,
+ intentAction: String = Intent.ACTION_MAIN,
+ isEligibleForPromptOption: Boolean = false,
+ startSecondActivity: Boolean = false,
+ startSecondaryAppAndCreateChannelsAfterSecondStart: Boolean = false
+ ) {
+ val intent =
+ createIntent(
+ createChannels,
+ requestNotificationPermission,
+ requestPermissions,
+ launcherCategory,
+ intentAction,
+ startSecondActivity,
+ startSecondaryAppAndCreateChannelsAfterSecondStart
+ )
+
+ val options = ActivityOptions.makeBasic()
+ options.isEligibleForLegacyPermissionPrompt = isEligibleForPromptOption
+ doAndWaitForWindowTransition { context.startActivity(intent, options.toBundle()) }
+
+ // Watch does not have app bar
+ if (!isWatch) {
+ waitFindObject(By.textContains(ACTIVITY_LABEL))
+ }
+ }
+
+ private fun assertDialogNotShowing(timeoutMillis: Long = EXPECTED_TIMEOUT_MS) {
+ try {
+ clickPermissionRequestAllowButton(timeoutMillis)
+ Assert.fail("Expected not to find permission request dialog")
+ } catch (expected: RuntimeException) {
+ // Do nothing
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt
new file mode 100644
index 000000000..495648b55
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest
+import android.content.Intent
+import android.os.Build
+import android.permission.PermissionManager
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.Assert.assertNull
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+@FlakyTest
+class PermissionDecisionsTest : BaseUsePermissionTest() {
+
+ companion object {
+ const val ASSERT_ABSENT_SELECTOR_TIMEOUT_MS = 500L
+ }
+
+ // Permission decisions has only been implemented on Auto
+ @Before
+ fun assumeAuto() {
+ assumeTrue(isAutomotive)
+ }
+
+ @Test
+ fun testAcceptPermissionDialogShowsDecisionWithGrantedAccess() {
+ installPackage(APP_APK_PATH_30_WITH_BACKGROUND)
+ requestAppPermissionsAndAssertResult(Manifest.permission.ACCESS_FINE_LOCATION to true) {
+ clickPermissionRequestAllowForegroundButton()
+ }
+
+ openPermissionDecisions()
+ waitFindObject(
+ By.hasChild(By.text("You gave $APP_PACKAGE_NAME access to location"))
+ .hasChild(By.text("Today"))
+ )
+ }
+
+ @Test
+ fun testDenyPermissionDialogShowsDecisionWithDeniedAccess() {
+ installPackage(APP_APK_PATH_30_WITH_BACKGROUND)
+ requestAppPermissionsAndAssertResult(Manifest.permission.ACCESS_FINE_LOCATION to false) {
+ clickPermissionRequestDenyButton()
+ }
+
+ openPermissionDecisions()
+ waitFindObject(
+ By.hasChild(By.text("You denied $APP_PACKAGE_NAME access to location"))
+ .hasChild(By.text("Today"))
+ )
+ }
+
+ @Test
+ fun testAppUninstallRemovesDecision() {
+ installPackage(APP_APK_PATH_30_WITH_BACKGROUND)
+ requestAppPermissionsAndAssertResult(Manifest.permission.ACCESS_FINE_LOCATION to false) {
+ clickPermissionRequestDenyButton()
+ }
+ uninstallApp()
+
+ openPermissionDecisions()
+ assertNull(
+ waitFindObjectOrNull(
+ By.hasChild(By.text("You denied $APP_PACKAGE_NAME access to location"))
+ .hasChild(By.text("Today")),
+ ASSERT_ABSENT_SELECTOR_TIMEOUT_MS
+ )
+ )
+ }
+
+ @Test
+ fun testClickOnDecisionAndChangeAccessUpdatesDecision() {
+ installPackage(APP_APK_PATH_30_WITH_BACKGROUND)
+ requestAppPermissionsAndAssertResult(Manifest.permission.ACCESS_FINE_LOCATION to true) {
+ clickPermissionRequestAllowForegroundButton()
+ }
+
+ openPermissionDecisions()
+
+ waitFindObject(
+ By.hasChild(By.text("You gave $APP_PACKAGE_NAME access to location"))
+ .hasChild(By.text("Today"))
+ )
+ .click()
+
+ waitFindObject(By.text(APP_PACKAGE_NAME))
+ waitFindObject(By.text("Location access for this app"))
+
+ // change the permission on the app permission screen and verify that updates the decision
+ // page
+ waitFindObject(By.text("Don’t allow")).click()
+ pressBack()
+ waitFindObject(
+ By.hasChild(By.text("You denied $APP_PACKAGE_NAME access to location"))
+ .hasChild(By.text("Today"))
+ )
+ }
+
+ private fun openPermissionDecisions() {
+ doAndWaitForWindowTransition {
+ SystemUtil.runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(PermissionManager.ACTION_REVIEW_PERMISSION_DECISIONS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
+ }
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionGroupTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionGroupTest.kt
new file mode 100644
index 000000000..b27d9ea69
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionGroupTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import androidx.test.filters.FlakyTest
+import org.junit.Test
+
+/** Runtime permission behavior tests for permission groups. */
+@FlakyTest
+class PermissionGroupTest : BaseUsePermissionTest() {
+ @Test
+ fun testRuntimeGroupGrantExpansion23() {
+ installPackage(APP_APK_PATH_23)
+ testRuntimeGroupGrantExpansion(true)
+ }
+
+ @Test
+ fun testRuntimeGroupGrantExpansion25() {
+ installPackage(APP_APK_PATH_25)
+ testRuntimeGroupGrantExpansion(true)
+ }
+
+ @Test
+ fun testRuntimeGroupGrantExpansion26() {
+ installPackage(APP_APK_PATH_26)
+ testRuntimeGroupGrantExpansion(false)
+ }
+
+ @Test
+ fun testRuntimeGroupGrantExpansion30() {
+ installPackage(APP_APK_PATH_30)
+ testRuntimeGroupGrantExpansion(false)
+ }
+
+ @Test
+ fun testPartiallyGrantedGroupExpansion() {
+ installPackage(APP_APK_PATH_30)
+
+ // Start out without permission
+ assertAppHasPermission(android.Manifest.permission.RECEIVE_SMS, false)
+ assertAppHasPermission(android.Manifest.permission.SEND_SMS, false)
+
+ // Grant only RECEIVE_SMS
+ uiAutomation.grantRuntimePermission(
+ APP_PACKAGE_NAME,
+ android.Manifest.permission.RECEIVE_SMS
+ )
+ assertAppHasPermission(android.Manifest.permission.RECEIVE_SMS, true)
+
+ // Request both permissions, and expect that SEND_SMS is granted
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.RECEIVE_SMS to true,
+ android.Manifest.permission.SEND_SMS to true,
+ waitForWindowTransition = false
+ ) {}
+
+ assertAppHasPermission(android.Manifest.permission.SEND_SMS, true)
+ }
+
+ private fun testRuntimeGroupGrantExpansion(expectExpansion: Boolean) {
+ // Start out without permission
+ assertAppHasPermission(android.Manifest.permission.RECEIVE_SMS, false)
+ assertAppHasPermission(android.Manifest.permission.SEND_SMS, false)
+
+ // Request only one permission from the 'SMS' permission group at runtime,
+ // but two from this group are <uses-permission> in the manifest
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.RECEIVE_SMS to true,
+ waitForWindowTransition = !isWatch
+ ) {
+ clickPermissionRequestAllowButton()
+ }
+
+ assertAppHasPermission(android.Manifest.permission.SEND_SMS, expectExpansion)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/BrowserRoleUiBehavior.java b/tests/cts/permissionui/src/android/permissionui/cts/PermissionNoOpGtsTest.kt
index 018b0db41..1ca319a30 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/BrowserRoleUiBehavior.java
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionNoOpGtsTest.kt
@@ -14,24 +14,16 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.ui.behavior;
+package android.permissionui.cts
-import android.content.Context;
-import android.os.UserHandle;
+import com.android.compatibility.common.util.CtsDownstreamingTest
+import org.junit.Test
-import androidx.annotation.NonNull;
+// NoOp test class so that at least one GTS test passes on all platforms.
+// b/235606392 for reference. Will be removed once we move all downstreaming
+// CtsPermissionUiTestCases to GTS.
+@CtsDownstreamingTest
+class PermissionNoOpGtsTest {
-import com.android.permissioncontroller.R;
-import com.android.role.controller.model.Role;
-
-/***
- * Class for UI behavior of Browser role
- */
-public class BrowserRoleUiBehavior implements RoleUiBehavior {
-
- @Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return context.getResources().getBoolean(R.bool.config_showBrowserRole);
- }
+ @Test fun shouldAlwaysPass() {}
}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionPolicyTest25.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionPolicyTest25.kt
new file mode 100644
index 000000000..3d03b669a
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionPolicyTest25.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.Activity
+import android.content.ComponentName
+import android.content.Intent
+import androidx.test.filters.FlakyTest
+import java.util.concurrent.TimeUnit
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+
+/** Tests for the platform permission policy around apps targeting API 25. */
+@FlakyTest
+class PermissionPolicyTest25 : BasePermissionTest() {
+ companion object {
+ const val APP_APK_PATH_25 = "$APK_DIRECTORY/CtsPermissionPolicyApp25.apk"
+ const val APP_PACKAGE_NAME = "android.permissionui.cts.permissionpolicy"
+ }
+
+ @Before
+ fun installApp25() {
+ uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false)
+ installPackage(APP_APK_PATH_25)
+ }
+
+ @After
+ fun uninstallApp() {
+ uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false)
+ }
+
+ @Test
+ fun testNoProtectionFlagsAddedToNonSignatureProtectionPermissions() {
+ val future =
+ startActivityForFuture(
+ Intent().apply {
+ component =
+ ComponentName(
+ APP_PACKAGE_NAME,
+ "$APP_PACKAGE_NAME.TestProtectionFlagsActivity"
+ )
+ }
+ )
+ val result = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ assertEquals(Activity.RESULT_OK, result.resultCode)
+ assertEquals("", result.resultData!!.getStringExtra("$APP_PACKAGE_NAME.ERROR_MESSAGE"))
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationalePermissionGrantDialogTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationalePermissionGrantDialogTest.kt
new file mode 100644
index 000000000..73faaa7f6
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationalePermissionGrantDialogTest.kt
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.Manifest.permission.CAMERA
+import android.os.Build
+import android.provider.DeviceConfig
+import android.safetylabel.SafetyLabelConstants.PERMISSION_RATIONALE_ENABLED
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule
+import com.android.modules.utils.build.SdkLevel
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+/**
+ * Permission rationale in Grant Permission Dialog tests. Permission rationale is only available on
+ * U+
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@FlakyTest
+class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() {
+
+ @get:Rule
+ val deviceConfigPermissionRationaleEnabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PERMISSION_RATIONALE_ENABLED,
+ true.toString()
+ )
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue("Permission rationale is only available on U+", SdkLevel.isAtLeastU())
+ Assume.assumeFalse(isAutomotive)
+ Assume.assumeFalse(isTv)
+ Assume.assumeFalse(isWatch)
+ }
+
+ @Test
+ fun requestLocationPerm_flagDisabled_noPermissionRationale() {
+ setDeviceConfigPrivacyProperty(PERMISSION_RATIONALE_ENABLED, false.toString())
+ installPackageWithInstallSourceAndMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_apkHasNoInstallSource_noPermissionRationale() {
+ installPackageWithoutInstallSource(APP_APK_PATH_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_noAppMetadata_noPermissionRationale() {
+ installPackageWithInstallSourceAndNoMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_nullAppMetadata_noPermissionRationale() {
+ installPackageWithInstallSourceAndNoMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_emptyAppMetadata_noPermissionRationale() {
+ installPackageWithInstallSourceAndEmptyMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_invalidAppMetadata_noPermissionRationale() {
+ installPackageWithInstallSourceAndInvalidMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_invalidAppMetadataWithoutTopLevelVersion_noPermissionRationale() {
+ installPackageWithInstallSourceAndMetadataWithoutTopLevelVersion(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_invalidAppMetadataWithInvalidTopLevelVersion_noPermissionRationale() {
+ installPackageWithInstallSourceAndMetadataWithInvalidTopLevelVersion(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_invalidAppMetadataWithoutSafetyLabelVersion_noPermissionRationale() {
+ installPackageWithInstallSourceAndMetadataWithoutSafetyLabelVersion(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_invalidAppMetadataWithInvalidSafetyLabelVersion_noPermissionRationale() {
+ installPackageWithInstallSourceAndMetadataWithInvalidSafetyLabelVersion(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestCameraPerm_noPermissionRationale() {
+ installPackageWithInstallSourceAndMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(CAMERA, false)
+
+ requestAppPermissionsForNoResult(CAMERA) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestCoarseLocationPerm_hasPermissionRationale_packageSourceUnspecified() {
+ installPackageWithInstallSourceAndMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(true)
+ }
+ }
+
+ @Test
+ fun requestCoarseLocationPerm_hasPermissionRationale_packageSourceStore() {
+ installPackageWithInstallSourceAndMetadataFromStore(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(true)
+ }
+ }
+
+ @Test
+ fun requestCoarseLocationPerm_hasPermissionRationale_packageSourceLocalFile() {
+ installPackageWithInstallSourceAndMetadataFromLocalFile(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestCoarseLocationPerm_hasPermissionRationale_packageSourceDownloadedFile() {
+ installPackageWithInstallSourceAndMetadataFromDownloadedFile(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestCoarseLocationPerm_hasPermissionRationale_packageSourceOther() {
+ installPackageWithInstallSourceAndMetadataFromOther(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestFineLocationPerm_hasPermissionRationale() {
+ installPackageWithInstallSourceAndMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(true)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_clicksPermissionRationale_startsPermissionRationaleActivity() {
+ installPackageWithInstallSourceAndMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {
+ clickPermissionRationaleViewInGrantDialog()
+ assertPermissionRationaleDialogIsVisible(true)
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ @Test
+ fun requestLocationPerm_clicksPermissionRationale_startsPermissionRationaleActivity_comesBack() {
+ installPackageWithInstallSourceAndMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {
+ clickPermissionRationaleViewInGrantDialog()
+ assertPermissionRationaleDialogIsVisible(true)
+ pressBack()
+ assertPermissionRationaleDialogIsVisible(false)
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(true)
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationaleTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationaleTest.kt
new file mode 100644
index 000000000..e20fdeffd
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationaleTest.kt
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest
+import android.app.ActivityManager
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.provider.DeviceConfig
+import android.safetylabel.SafetyLabelConstants.PERMISSION_RATIONALE_ENABLED
+import android.text.Spanned
+import android.text.style.ClickableSpan
+import android.util.Log
+import android.view.View
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule
+import com.android.compatibility.common.util.SystemUtil
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.modules.utils.build.SdkLevel
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+/** Permission rationale activity tests. Permission rationale is only available on U+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@FlakyTest
+class PermissionRationaleTest : BaseUsePermissionTest() {
+
+ private var activityManager: ActivityManager? = null
+
+ @get:Rule
+ val deviceConfigPermissionRationaleEnabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PERMISSION_RATIONALE_ENABLED,
+ true.toString()
+ )
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue("Permission rationale is only available on U+", SdkLevel.isAtLeastU())
+ Assume.assumeFalse(isAutomotive)
+ Assume.assumeFalse(isTv)
+ Assume.assumeFalse(isWatch)
+
+ activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
+
+ enableComponent(TEST_INSTALLER_ACTIVITY_COMPONENT_NAME)
+
+ installPackageWithInstallSourceAndMetadata(APP_APK_NAME_31)
+
+ assertAppHasPermission(Manifest.permission.ACCESS_FINE_LOCATION, false)
+ }
+
+ @After
+ fun disableTestInstallerActivity() {
+ disableComponent(TEST_INSTALLER_ACTIVITY_COMPONENT_NAME)
+ }
+
+ @Test
+ fun startsPermissionRationaleActivity_failedByNullMetadata() {
+ installPackageWithInstallSourceAndNoMetadata(APP_APK_NAME_31)
+ navigateToPermissionRationaleActivity_failedShowPermissionRationaleContainer()
+ }
+
+ @Test
+ fun startsPermissionRationaleActivity_failedByEmptyMetadata() {
+ installPackageWithInstallSourceAndEmptyMetadata(APP_APK_NAME_31)
+ navigateToPermissionRationaleActivity_failedShowPermissionRationaleContainer()
+ }
+
+ @Test
+ fun startsPermissionRationaleActivity_failedByNoTopLevelVersion() {
+ installPackageWithInstallSourceAndMetadataWithoutTopLevelVersion(APP_APK_NAME_31)
+ navigateToPermissionRationaleActivity_failedShowPermissionRationaleContainer()
+ }
+
+ @Test
+ fun startsPermissionRationaleActivity_failedByInvalidTopLevelVersion() {
+ installPackageWithInstallSourceAndMetadataWithInvalidTopLevelVersion(APP_APK_NAME_31)
+ navigateToPermissionRationaleActivity_failedShowPermissionRationaleContainer()
+ }
+
+ @Test
+ fun startsPermissionRationaleActivity_failedByNoSafetyLabelVersion() {
+ installPackageWithInstallSourceAndMetadataWithoutSafetyLabelVersion(APP_APK_NAME_31)
+ navigateToPermissionRationaleActivity_failedShowPermissionRationaleContainer()
+ }
+
+ @Test
+ fun startsPermissionRationaleActivity_failedByInvalidSafetyLabelVersion() {
+ installPackageWithInstallSourceAndMetadataWithInvalidSafetyLabelVersion(APP_APK_NAME_31)
+ navigateToPermissionRationaleActivity_failedShowPermissionRationaleContainer()
+ }
+
+ @Test
+ fun startsPermissionRationaleActivity() {
+ navigateToPermissionRationaleActivity()
+
+ assertPermissionRationaleDialogIsVisible(true)
+ }
+
+ @Test
+ fun linksToInstallSource() {
+ navigateToPermissionRationaleActivity()
+
+ assertPermissionRationaleDialogIsVisible(true)
+
+ clickInstallSourceLink()
+
+ eventually {
+ assertStoreLinkClickSuccessful(installerPackageName = TEST_INSTALLER_PACKAGE_NAME)
+ }
+ }
+
+ @Ignore("b/282063206")
+ @Test
+ fun clickLinkToHelpCenter_opensHelpCenter() {
+ Assume.assumeFalse(getPermissionControllerResString(HELP_CENTER_URL_ID).isNullOrEmpty())
+
+ navigateToPermissionRationaleActivity()
+
+ assertPermissionRationaleActivityTitleIsVisible(true)
+ assertHelpCenterLinkAvailable(true)
+
+ clickHelpCenterLink()
+
+ eventually({ assertHelpCenterLinkClickSuccessful() }, NEW_WINDOW_TIMEOUT_MILLIS)
+ }
+
+ @Test
+ fun noHelpCenterLinkAvailable_noHelpCenterClickAction() {
+ Assume.assumeTrue(getPermissionControllerResString(HELP_CENTER_URL_ID).isNullOrEmpty())
+
+ navigateToPermissionRationaleActivity()
+
+ assertPermissionRationaleActivityTitleIsVisible(true)
+ assertHelpCenterLinkAvailable(false)
+ }
+
+ @Test
+ fun linksToSettings_noOp_dialogsNotClosed() {
+ navigateToPermissionRationaleActivity()
+
+ assertPermissionRationaleDialogIsVisible(true)
+
+ clicksSettings_doesNothing_leaves()
+
+ eventually { assertPermissionRationaleDialogIsVisible(true) }
+ }
+
+ @Test
+ fun linksToSettings_grants_dialogsClose() {
+ navigateToPermissionRationaleActivity()
+
+ assertPermissionRationaleDialogIsVisible(true)
+
+ clicksSettings_allowsForeground_leaves()
+
+ // Setting, Permission rationale and Grant dialog should be dismissed
+ eventually {
+ assertPermissionSettingsVisible(false)
+ assertPermissionRationaleDialogIsVisible(false)
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+
+ assertAppHasPermission(Manifest.permission.ACCESS_FINE_LOCATION, true)
+ }
+
+ @Test
+ fun linksToSettings_denies_dialogsClose() {
+ navigateToPermissionRationaleActivity()
+
+ assertPermissionRationaleDialogIsVisible(true)
+
+ clicksSettings_denies_leaves()
+
+ // Setting, Permission rationale and Grant dialog should be dismissed
+ eventually {
+ assertPermissionSettingsVisible(false)
+ assertPermissionRationaleDialogIsVisible(false)
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+
+ assertAppHasPermission(Manifest.permission.ACCESS_FINE_LOCATION, false)
+ }
+
+ private fun navigateToPermissionRationaleActivity_failedShowPermissionRationaleContainer() {
+ requestAppPermissionsForNoResult(Manifest.permission.ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(false)
+ }
+ }
+
+ private fun navigateToPermissionRationaleActivity() {
+ requestAppPermissionsForNoResult(Manifest.permission.ACCESS_FINE_LOCATION) {
+ assertPermissionRationaleContainerOnGrantDialogIsVisible(true)
+ clickPermissionRationaleViewInGrantDialog()
+ }
+ }
+
+ private fun clickInstallSourceLink() {
+ findView(By.res(DATA_SHARING_SOURCE_MESSAGE_ID), true)
+
+ eventually {
+ // UiObject2 doesn't expose CharSequence.
+ val node =
+ uiAutomation.rootInActiveWindow
+ .findAccessibilityNodeInfosByViewId(DATA_SHARING_SOURCE_MESSAGE_ID)[0]
+ assertTrue(node.isVisibleToUser)
+ val text = node.text as Spanned
+ val clickableSpan = text.getSpans(0, text.length, ClickableSpan::class.java)[0]
+ // We could pass in null here in Java, but we need an instance in Kotlin.
+ doAndWaitForWindowTransition { clickableSpan.onClick(View(context)) }
+ }
+ }
+
+ private fun clickHelpCenterLink() {
+ findView(By.res(LEARN_MORE_MESSAGE_ID), true)
+
+ eventually {
+ // UiObject2 doesn't expose CharSequence.
+ val node =
+ uiAutomation.rootInActiveWindow
+ .findAccessibilityNodeInfosByViewId(LEARN_MORE_MESSAGE_ID)[0]
+ assertTrue(node.isVisibleToUser)
+ val text = node.text as Spanned
+ val clickableSpan = text.getSpans(0, text.length, ClickableSpan::class.java)[0]
+ // We could pass in null here in Java, but we need an instance in Kotlin.
+ doAndWaitForWindowTransition { clickableSpan.onClick(View(context)) }
+ }
+ }
+
+ private fun clickSettingsLink() {
+ findView(By.res(SETTINGS_MESSAGE_ID), true)
+
+ eventually {
+ // UiObject2 doesn't expose CharSequence.
+ val node =
+ uiAutomation.rootInActiveWindow
+ .findAccessibilityNodeInfosByViewId(SETTINGS_MESSAGE_ID)[0]
+ assertTrue(node.isVisibleToUser)
+ val text = node.text as Spanned
+ val clickableSpan = text.getSpans(0, text.length, ClickableSpan::class.java)[0]
+ // We could pass in null here in Java, but we need an instance in Kotlin.
+ doAndWaitForWindowTransition { clickableSpan.onClick(View(context)) }
+ }
+ }
+
+ private fun clicksSettings_doesNothing_leaves() {
+ clickSettingsLink()
+ eventually { assertPermissionSettingsVisible(true) }
+ pressBack()
+ }
+
+ private fun clicksSettings_allowsForeground_leaves() {
+ clickSettingsLink()
+ eventually { clickAllowForegroundInSettings() }
+ pressBack()
+ }
+
+ private fun clicksSettings_denies_leaves() {
+ clickSettingsLink()
+ eventually { clicksDenyInSettings() }
+ pressBack()
+ }
+
+ private fun assertHelpCenterLinkAvailable(expected: Boolean) {
+ // Message should always be visible
+ findView(By.res(LEARN_MORE_MESSAGE_ID), true)
+
+ // Verify the link is (or isn't) in message
+ eventually {
+ // UiObject2 doesn't expose CharSequence.
+ val node =
+ uiAutomation.rootInActiveWindow
+ .findAccessibilityNodeInfosByViewId(LEARN_MORE_MESSAGE_ID)[0]
+ assertTrue(node.isVisibleToUser)
+ val text = node.text as Spanned
+ val clickableSpans = text.getSpans(0, text.length, ClickableSpan::class.java)
+
+ if (expected) {
+ assertFalse("Expected help center link, but none found", clickableSpans.isEmpty())
+ } else {
+ assertTrue("Expected no links, but found one", clickableSpans.isEmpty())
+ }
+ }
+ }
+
+ private fun assertPermissionSettingsVisible(expected: Boolean) {
+ findView(By.res(DENY_RADIO_BUTTON), expected = expected)
+ }
+
+ private fun assertStoreLinkClickSuccessful(
+ installerPackageName: String,
+ packageName: String? = null
+ ) {
+ SystemUtil.runWithShellPermissionIdentity {
+ val runningTasks = activityManager!!.getRunningTasks(1)
+
+ assertFalse("Expected runningTasks to not be empty", runningTasks.isEmpty())
+
+ val taskInfo = runningTasks[0]
+ val observedIntentAction = taskInfo.baseIntent.action
+ val observedPackageName = taskInfo.baseIntent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)
+ val observedInstallerPackageName = taskInfo.topActivity?.packageName
+
+ assertEquals(
+ "Unexpected intent action",
+ Intent.ACTION_SHOW_APP_INFO,
+ observedIntentAction
+ )
+ assertEquals(
+ "Unexpected installer package name",
+ installerPackageName,
+ observedInstallerPackageName
+ )
+ assertEquals("Unexpected package name", packageName, observedPackageName)
+ }
+ }
+
+ private fun assertHelpCenterLinkClickSuccessful() {
+ SystemUtil.runWithShellPermissionIdentity {
+ val runningTasks = activityManager!!.getRunningTasks(5)
+
+ Log.v(TAG, "# running tasks: ${runningTasks.size}")
+ assertFalse("Expected runningTasks to not be empty", runningTasks.isEmpty())
+
+ runningTasks.forEachIndexed { index, runningTaskInfo ->
+ Log.v(TAG, "task $index ${runningTaskInfo.baseIntent}")
+ }
+
+ val taskInfo = runningTasks[0]
+ val observedIntentAction = taskInfo.baseIntent.action
+ val observedIntentDataString = taskInfo.baseIntent.dataString
+ val observedIntentScheme: String? = taskInfo.baseIntent.scheme
+
+ Log.v(TAG, "task base intent: ${taskInfo.baseIntent}")
+ assertEquals("Unexpected intent action", Intent.ACTION_VIEW, observedIntentAction)
+
+ val expectedUrl = getPermissionControllerResString(HELP_CENTER_URL_ID)!!
+ assertFalse(observedIntentDataString.isNullOrEmpty())
+ assertTrue(observedIntentDataString?.startsWith(expectedUrl) ?: false)
+
+ assertFalse(observedIntentScheme.isNullOrEmpty())
+ assertEquals("https", observedIntentScheme)
+ }
+ }
+
+ companion object {
+ private val TAG = PermissionRationaleTest::class.java.simpleName
+
+ private const val DATA_SHARING_SOURCE_MESSAGE_ID =
+ "com.android.permissioncontroller:id/data_sharing_source_message"
+ private const val LEARN_MORE_MESSAGE_ID =
+ "com.android.permissioncontroller:id/learn_more_message"
+ private const val SETTINGS_MESSAGE_ID =
+ "com.android.permissioncontroller:id/settings_message"
+
+ private const val HELP_CENTER_URL_ID = "data_sharing_help_center_link"
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt
new file mode 100644
index 000000000..a75f08916
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTapjackingTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.content.ComponentName
+import android.content.Intent
+import androidx.test.filters.FlakyTest
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil
+import java.lang.Exception
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+
+/** Tests permission review screen can't be tapjacked */
+@FlakyTest
+class PermissionReviewTapjackingTest : BaseUsePermissionTest() {
+
+ companion object {
+ const val HELPER_APP_OVERLAY = "$APK_DIRECTORY/CtsHelperAppOverlay.apk"
+ private const val HELPER_PACKAGE_NAME = "android.permissionui.cts.helper.overlay"
+ }
+
+ @Before
+ fun installApp22AndApprovePermissionReview() {
+ assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
+ installPackage(APP_APK_PATH_22)
+ installPackage(HELPER_APP_OVERLAY)
+
+ SystemUtil.runShellCommandOrThrow(
+ "appops set $HELPER_PACKAGE_NAME android:system_alert_window allow"
+ )
+ }
+
+ @After
+ fun uninstallPackages() {
+ SystemUtil.runShellCommandOrThrow("pm uninstall $APP_PACKAGE_NAME")
+ SystemUtil.runShellCommandOrThrow("pm uninstall $HELPER_PACKAGE_NAME")
+ }
+
+ @Test
+ fun testOverlaysAreHidden() {
+ context.startActivity(
+ Intent()
+ .setComponent(
+ ComponentName(HELPER_PACKAGE_NAME, "$HELPER_PACKAGE_NAME.OverlayActivity")
+ )
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ )
+ findOverlay()
+
+ context.startActivity(
+ Intent()
+ .setComponent(
+ ComponentName(APP_PACKAGE_NAME, "$APP_PACKAGE_NAME.FinishOnCreateActivity")
+ )
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ )
+
+ if (isWatch) {
+ waitFindObject(
+ By.text(getPermissionControllerString("review_button_cancel")),
+ TIMEOUT_MILLIS * 2
+ )
+ } else {
+ waitFindObject(By.res("com.android.permissioncontroller:id/permissions_message"))
+ }
+
+ try {
+ findOverlay()
+ Assert.fail("Overlay was displayed")
+ } catch (e: Exception) {
+ // expected
+ }
+
+ pressHome()
+ findOverlay()
+ }
+
+ private fun findOverlay() = waitFindObject(By.text("Find me!"))
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTest.kt
new file mode 100644
index 000000000..5ca23fea2
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionReviewTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.Activity
+import android.content.ComponentName
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.os.ResultReceiver
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.rule.ActivityTestRule
+import androidx.test.runner.AndroidJUnit4
+import androidx.test.uiautomator.By
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@FlakyTest
+class PermissionReviewTest : BaseUsePermissionTest() {
+
+ @Before
+ fun assumeNotIndividuallyControlled() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+ }
+
+ @Before
+ fun installApp22CalendarOnly() {
+ installPackage(APP_APK_PATH_22_CALENDAR_ONLY)
+ }
+
+ @get:Rule val activityRule = ActivityTestRule(StartForFutureActivity::class.java, false, false)
+
+ @Test
+ fun testDenyCalendarDuringReview() {
+ startAppActivityAndAssertResultCode(Activity.RESULT_OK) {
+ // Deny
+ clickPermissionControllerUi(By.text("Calendar"))
+ // Confirm deny
+ click(By.res("android:id/button1"))
+
+ clickPermissionReviewContinue()
+ }
+
+ clearTargetSdkWarning()
+ assertAppHasCalendarAccess(false)
+ }
+
+ @Test
+ fun testDenyGrantCalendarDuringReview() {
+ startAppActivityAndAssertResultCode(Activity.RESULT_OK) {
+ // Deny
+ clickPermissionControllerUi(By.text("Calendar"))
+ // Confirm deny
+ click(By.res("android:id/button1"))
+
+ // Grant
+ clickPermissionControllerUi(By.text("Calendar"))
+
+ clickPermissionReviewContinue()
+ }
+
+ clearTargetSdkWarning()
+ assertAppHasCalendarAccess(true)
+ }
+
+ @Test
+ fun testDenyGrantDenyCalendarDuringReview() {
+ startAppActivityAndAssertResultCode(Activity.RESULT_OK) {
+ // Deny
+ clickPermissionControllerUi(By.text("Calendar"))
+
+ // Confirm deny
+ click(By.res("android:id/button1"))
+
+ // Grant
+ clickPermissionControllerUi(By.text("Calendar"))
+
+ // Deny
+ clickPermissionControllerUi(By.text("Calendar"))
+
+ clickPermissionReviewContinue()
+ }
+
+ clearTargetSdkWarning()
+ assertAppHasCalendarAccess(false)
+ }
+
+ @Test
+ fun testCancelReview() {
+ // Start APK_22_ONLY_CALENDAR, but cancel review
+ cancelPermissionReview()
+
+ // Start APK_22_ONLY_CALENDAR again, now approve review
+ approvePermissionReview()
+
+ assertAppDoesNotNeedPermissionReview()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "TIRAMISU")
+ fun testNotificationPermissionAddedToReview() {
+ startAppActivityAndAssertResultCode(Activity.RESULT_CANCELED) {
+ waitFindObject(By.text("Notifications"), 5000L)
+ clickPermissionReviewCancel()
+ }
+ }
+
+ @Test
+ fun testReviewPermissionWhenServiceIsBound() {
+ val results = LinkedBlockingQueue<Int>()
+ // We are starting a activity instead of the service directly, because
+ // the service comes from a different app than the CTS tests.
+ // This app will be considered idle on devices that have idling enabled (automotive),
+ // and the service wouldn't be allowed to be started without the activity.
+ activityRule
+ .launchActivity(null)
+ .startActivity(
+ Intent().apply {
+ component =
+ ComponentName(
+ APP_PACKAGE_NAME,
+ "$APP_PACKAGE_NAME.StartCheckPermissionServiceActivity"
+ )
+ putExtra(
+ "$APP_PACKAGE_NAME.RESULT",
+ object : ResultReceiver(Handler(Looper.getMainLooper())) {
+ override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
+ results.offer(resultCode)
+ }
+ }
+ )
+ putExtra(
+ "$APP_PACKAGE_NAME.PERMISSION",
+ android.Manifest.permission.READ_CALENDAR
+ )
+ }
+ )
+
+ // Service is not started before permission are reviewed
+ assertNull(results.poll(UNEXPECTED_TIMEOUT_MILLIS.toLong(), TimeUnit.MILLISECONDS))
+
+ clickPermissionReviewContinueAndClearSdkWarning()
+
+ // Service should be started after permission review
+ assertEquals(
+ PackageManager.PERMISSION_GRANTED,
+ results.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ )
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt
new file mode 100644
index 000000000..927b9833b
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.os.Build
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+
+/** Runtime permission behavior tests for permission splits. */
+@FlakyTest
+class PermissionSplitTest : BaseUsePermissionTest() {
+ @Before
+ fun assumeNotTv() {
+ assumeFalse(isTv)
+ }
+
+ @Test
+ fun testPermissionSplit28() {
+ installPackage(APP_APK_PATH_28)
+ testLocationPermissionSplit(true)
+ }
+
+ @Test
+ fun testPermissionNotSplit29() {
+ installPackage(APP_APK_PATH_29)
+ testLocationPermissionSplit(false)
+ }
+
+ @Test
+ fun testPermissionNotSplit30() {
+ installPackage(APP_APK_PATH_30)
+ testLocationPermissionSplit(false)
+ }
+
+ @Test
+ fun testPermissionNotSplitLatest() {
+ installPackage(APP_APK_PATH_LATEST)
+ testLocationPermissionSplit(false)
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ @Test
+ fun testBodySensorSplit() {
+ installPackage(APP_APK_PATH_31)
+ testBodySensorPermissionSplit(true)
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ @Test
+ fun testBodySensorSplit32() {
+ installPackage(APP_APK_PATH_32)
+ testBodySensorPermissionSplit(true)
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ @Test
+ fun testBodySensorNonSplit() {
+ installPackage(APP_APK_PATH_LATEST)
+ testBodySensorPermissionSplit(false)
+ }
+
+ private fun testLocationPermissionSplit(expectSplit: Boolean) {
+ assertAppHasPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, false)
+
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to true,
+ waitForWindowTransition = false
+ ) {
+ if (expectSplit) {
+ clickPermissionRequestSettingsLinkAndAllowAlways()
+ } else {
+ doAndWaitForWindowTransition { clickPermissionRequestAllowForegroundButton() }
+ }
+ }
+
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, expectSplit)
+ }
+
+ private fun testBodySensorPermissionSplit(expectSplit: Boolean) {
+ assertAppHasPermission(android.Manifest.permission.BODY_SENSORS, false)
+ assertAppHasPermission(android.Manifest.permission.BODY_SENSORS_BACKGROUND, false)
+
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.BODY_SENSORS to true,
+ waitForWindowTransition = false
+ ) {
+ if (expectSplit) {
+ clickPermissionRequestSettingsLinkAndAllowAlways()
+ } else {
+ doAndWaitForWindowTransition { clickPermissionRequestAllowForegroundButton() }
+ }
+ }
+
+ assertAppHasPermission(android.Manifest.permission.BODY_SENSORS_BACKGROUND, expectSplit)
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt
new file mode 100644
index 000000000..b81432369
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.graphics.Point
+import android.os.Build
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+
+/** Tests permissions can't be tapjacked */
+@FlakyTest
+class PermissionTapjackingTest : BaseUsePermissionTest() {
+
+ @Before
+ fun installAppLatest() {
+ installPackage(APP_APK_PATH_WITH_OVERLAY)
+ }
+
+ @Test
+ fun testTapjackGrantDialog_fullOverlay() {
+ // PermissionController for television uses a floating window.
+ assumeFalse(isTv)
+
+ // Automotive split-screen multitasking uses multi-window mode
+ assumeFalse(isAutomotiveSplitscreen)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {}
+
+ val buttonCenter =
+ waitFindObject(By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT)))
+ .visibleCenter
+
+ // Wait for overlay to hide the dialog
+ context.sendBroadcast(Intent(ACTION_SHOW_OVERLAY).putExtra(EXTRA_FULL_OVERLAY, true))
+ waitFindObject(By.res("android.permissionui.cts.usepermission:id/overlay"))
+
+ tryClicking(buttonCenter)
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+ @Test
+ fun testTapjackGrantDialog_partialOverlay() {
+ // PermissionController for television uses a floating window.
+ assumeFalse(isTv)
+
+ // Automotive split-screen multitasking uses multi-window mode
+ assumeFalse(isAutomotiveSplitscreen)
+
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {}
+
+ val foregroundButtonCenter =
+ waitFindObject(By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT)))
+ .visibleCenter
+ val oneTimeButton =
+ waitFindObjectOrNull(By.text(getPermissionControllerString(ALLOW_ONE_TIME_BUTTON_TEXT)))
+ // If one-time button is not available, fallback to deny button
+ val overlayButtonBounds =
+ oneTimeButton?.visibleBounds
+ ?: waitFindObject(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)))
+ .visibleBounds
+
+ // Wait for overlay to hide the dialog
+ context.sendBroadcast(
+ Intent(ACTION_SHOW_OVERLAY)
+ .putExtra(EXTRA_FULL_OVERLAY, false)
+ .putExtra(OVERLAY_LEFT, overlayButtonBounds.left)
+ .putExtra(OVERLAY_TOP, overlayButtonBounds.top)
+ .putExtra(OVERLAY_RIGHT, overlayButtonBounds.right)
+ .putExtra(OVERLAY_BOTTOM, overlayButtonBounds.bottom)
+ )
+ waitFindObject(By.res("android.permissionui.cts.usepermission:id/overlay"))
+
+ tryClicking(foregroundButtonCenter)
+ }
+
+ private fun tryClicking(buttonCenter: Point) {
+ try {
+ // Try to grant the permission, this should fail
+ SystemUtil.eventually(
+ {
+ if (
+ packageManager.checkPermission(ACCESS_FINE_LOCATION, APP_PACKAGE_NAME) ==
+ PackageManager.PERMISSION_DENIED
+ ) {
+ uiDevice.click(buttonCenter.x, buttonCenter.y)
+ Thread.sleep(100)
+ }
+ assertAppHasPermission(ACCESS_FINE_LOCATION, true)
+ },
+ 10000
+ )
+ } catch (e: RuntimeException) {
+ // expected
+ }
+ // Permission should not be granted
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+
+ // Verify that clicking the dialog without the overlay still works
+ context.sendBroadcast(Intent(ACTION_HIDE_OVERLAY))
+ SystemUtil.eventually(
+ {
+ if (
+ packageManager.checkPermission(ACCESS_FINE_LOCATION, APP_PACKAGE_NAME) ==
+ PackageManager.PERMISSION_DENIED
+ ) {
+ uiDevice.click(buttonCenter.x, buttonCenter.y)
+ Thread.sleep(100)
+ }
+ assertAppHasPermission(ACCESS_FINE_LOCATION, true)
+ },
+ 10000
+ )
+ }
+
+ companion object {
+ const val ACTION_SHOW_OVERLAY = "android.permissionui.cts.usepermission.ACTION_SHOW_OVERLAY"
+ const val ACTION_HIDE_OVERLAY = "android.permissionui.cts.usepermission.ACTION_HIDE_OVERLAY"
+
+ const val EXTRA_FULL_OVERLAY = "android.permissionui.cts.usepermission.extra.FULL_OVERLAY"
+
+ const val OVERLAY_LEFT = "android.permissionui.cts.usepermission.extra.OVERLAY_LEFT"
+ const val OVERLAY_TOP = "android.permissionui.cts.usepermission.extra.OVERLAY_TOP"
+ const val OVERLAY_RIGHT = "android.permissionui.cts.usepermission.extra.OVERLAY_RIGHT"
+ const val OVERLAY_BOTTOM = "android.permissionui.cts.usepermission.extra.OVERLAY_BOTTOM"
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest22.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest22.kt
new file mode 100755
index 000000000..b6d5887d6
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest22.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import androidx.test.filters.FlakyTest
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+
+/** Runtime permission behavior tests for apps targeting API 22. */
+@FlakyTest
+class PermissionTest22 : BaseUsePermissionTest() {
+
+ @Before
+ fun installApp22AndApprovePermissionReview() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
+ installPackage(APP_APK_PATH_22)
+ approvePermissionReview()
+ }
+
+ @Test
+ fun testCompatDefault() {
+ // Legacy permission model appears granted
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, true)
+ assertAppHasPermission(android.Manifest.permission.WRITE_CALENDAR, true)
+ assertAppHasCalendarAccess(true)
+ }
+
+ @Test
+ fun testCompatRevoked() {
+ // Revoke the permission
+ revokeAppPermissionsByUi(android.Manifest.permission.WRITE_CALENDAR, isLegacyApp = true)
+
+ // Legacy permission model appears granted
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, true)
+ assertAppHasPermission(android.Manifest.permission.WRITE_CALENDAR, true)
+ // Read/write access should be ignored
+ assertAppHasCalendarAccess(false)
+ }
+
+ @Test
+ fun testNoRuntimePrompt() {
+ // Request the permission and do nothing
+ // Expect the permission is not granted
+ requestAppPermissionsAndAssertResult(
+ arrayOf(android.Manifest.permission.SEND_SMS),
+ emptyArray(),
+ waitForWindowTransition = false
+ ) {}
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest23.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest23.kt
new file mode 100644
index 000000000..01993adc5
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest23.kt
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.content.pm.PackageManager
+import android.permission.cts.MtsIgnore
+import androidx.test.filters.FlakyTest
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+
+/** Runtime permission behavior tests for apps targeting API 23. */
+@FlakyTest
+class PermissionTest23 : BaseUsePermissionTest() {
+ companion object {
+ private const val NON_EXISTENT_PERMISSION = "permission.does.not.exist"
+ private const val INVALID_PERMISSION = "$APP_PACKAGE_NAME.abadname"
+ }
+
+ @Before
+ fun installApp23() {
+ installPackage(APP_APK_PATH_23)
+ }
+
+ @Test
+ fun testDefault() {
+ // New permission model is denied by default
+ assertAppHasAllOrNoPermissions(false)
+ }
+
+ @Test
+ fun testGranted() {
+ grantAppPermissionsByUi(android.Manifest.permission.READ_CALENDAR)
+
+ // Read/write access should be allowed
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, true)
+ assertAppHasPermission(android.Manifest.permission.WRITE_CALENDAR, true)
+ assertAppHasCalendarAccess(true)
+ }
+
+ @Test
+ fun testInteractiveGrant() {
+ // Start out without permission
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, false)
+ assertAppHasPermission(android.Manifest.permission.WRITE_CALENDAR, false)
+ assertAppHasCalendarAccess(false)
+
+ // Go through normal grant flow
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.READ_CALENDAR to true,
+ android.Manifest.permission.WRITE_CALENDAR to true
+ ) {
+ clickPermissionRequestAllowButton()
+ }
+
+ // We should have permission now!
+ assertAppHasCalendarAccess(true)
+ }
+
+ @Test
+ fun testRuntimeGroupGrantSpecificity() {
+ // Start out without permission
+ assertAppHasPermission(android.Manifest.permission.READ_CONTACTS, false)
+ assertAppHasPermission(android.Manifest.permission.WRITE_CONTACTS, false)
+
+ // Request only one permission from the 'contacts' permission group
+ // Expect the permission is granted
+ requestAppPermissionsAndAssertResult(android.Manifest.permission.WRITE_CONTACTS to true) {
+ clickPermissionRequestAllowButton()
+ }
+
+ // Make sure no undeclared as used permissions are granted
+ assertAppHasPermission(android.Manifest.permission.READ_CONTACTS, false)
+ }
+
+ @Test
+ fun testCancelledPermissionRequest() {
+ // Make sure we don't have the permission
+ assertAppHasPermission(android.Manifest.permission.WRITE_CONTACTS, false)
+
+ // Request the permission and cancel the request
+ // Expect the permission is not granted
+ requestAppPermissionsAndAssertResult(android.Manifest.permission.WRITE_CONTACTS to false) {
+ clickPermissionRequestDenyButton()
+ }
+ }
+
+ @Test
+ fun testRequestGrantedPermission() {
+ // Make sure we don't have the permission
+ assertAppHasPermission(android.Manifest.permission.WRITE_CONTACTS, false)
+
+ // Request the permission and allow it
+ // Expect the permission is granted
+ requestAppPermissionsAndAssertResult(android.Manifest.permission.WRITE_CONTACTS to true) {
+ clickPermissionRequestAllowButton()
+ }
+
+ // Request the permission and do nothing
+ // Expect the permission is granted
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.WRITE_CONTACTS to true,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @Test
+ fun testDenialWithPrejudice() {
+ // Make sure we don't have the permission
+ assertAppHasPermission(android.Manifest.permission.WRITE_CONTACTS, false)
+
+ // Request the permission and deny it twice
+ // Expect the permission is not granted
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.WRITE_CONTACTS to false,
+ askTwice = true
+ ) {
+ clickPermissionRequestDenyButton()
+ denyPermissionRequestWithPrejudice()
+ }
+
+ // Request the permission and do nothing
+ // Expect the permission is not granted
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.WRITE_CONTACTS to false,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @FlakyTest
+ @MtsIgnore
+ @Test
+ fun testRevokeAffectsWholeGroup() {
+ // Grant the group
+ grantAppPermissionsByUi(android.Manifest.permission.READ_CALENDAR)
+
+ // Make sure we have the permissions
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, true)
+ assertAppHasPermission(android.Manifest.permission.WRITE_CALENDAR, true)
+
+ // Revoke the group
+ revokeAppPermissionsByUi(android.Manifest.permission.READ_CALENDAR)
+
+ // Make sure we don't have the permissions
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, false)
+ assertAppHasPermission(android.Manifest.permission.WRITE_CALENDAR, false)
+ }
+
+ @Test
+ fun testGrantPreviouslyRevokedWithPrejudiceShowsPrompt() {
+ // Make sure we don't have the permission
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, false)
+
+ // Request the permission and deny it twice
+ // Expect the permission is not granted
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.READ_CALENDAR to false,
+ askTwice = true
+ ) {
+ clickPermissionRequestDenyButton()
+ denyPermissionRequestWithPrejudice()
+ }
+
+ // Clear the denial with prejudice
+ uiAutomation.grantRuntimePermission(
+ APP_PACKAGE_NAME,
+ android.Manifest.permission.READ_CALENDAR
+ )
+ revokeAppPermissionsByUi(android.Manifest.permission.READ_CALENDAR)
+
+ // Make sure we don't have the permission
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, false)
+
+ // Request the permission and allow it
+ // Make sure the permission is granted
+ requestAppPermissionsAndAssertResult(android.Manifest.permission.READ_CALENDAR to true) {
+ clickPermissionRequestAllowButton()
+ }
+ }
+
+ @Test
+ fun testRequestNonRuntimePermission() {
+ // Make sure we don't have the permission
+ assertAppHasPermission(android.Manifest.permission.BIND_PRINT_SERVICE, false)
+
+ // Request the permission and do nothing
+ // Expect the permission is not granted
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.BIND_PRINT_SERVICE to false,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @Test
+ fun testRequestNonExistentPermission() {
+ // Make sure we don't have the permission
+ assertAppHasPermission(NON_EXISTENT_PERMISSION, false)
+
+ // Request the permission and do nothing
+ // Expect the permission is not granted
+ requestAppPermissionsAndAssertResult(
+ NON_EXISTENT_PERMISSION to false,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @Test
+ fun testRequestPermissionFromTwoGroups() {
+ // Make sure we don't have the permissions
+ assertAppHasPermission(android.Manifest.permission.WRITE_CONTACTS, false)
+ assertAppHasPermission(android.Manifest.permission.WRITE_CALENDAR, false)
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, false)
+
+ // Request the permission and allow it
+ // Expect the permission are granted
+ val result =
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.WRITE_CONTACTS to true,
+ android.Manifest.permission.WRITE_CALENDAR to true
+ ) {
+ clickPermissionRequestAllowButton()
+ clickPermissionRequestAllowButton()
+ }
+
+ // In API < N_MR1 all permissions of a group are granted. I.e. the grant was "expanded"
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, true)
+ // Even the contacts group was expanded, the read-calendar permission is not in the
+ // manifest, hence not granted.
+ assertAppHasPermission(android.Manifest.permission.READ_CONTACTS, false)
+ }
+
+ @Test(timeout = 180000)
+ @FlakyTest
+ @MtsIgnore
+ fun testNoResidualPermissionsOnUninstall() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
+ // Grant one permission via UI, and the rest via automation
+ grantAppPermissionsByUi(android.Manifest.permission.WRITE_CALENDAR)
+ grantRuntimePermissions(
+ android.Manifest.permission.WRITE_CONTACTS,
+ android.Manifest.permission.READ_SMS,
+ android.Manifest.permission.CALL_PHONE,
+ android.Manifest.permission.RECORD_AUDIO,
+ android.Manifest.permission.CAMERA,
+ android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.BODY_SENSORS,
+ )
+ uninstallPackage(APP_PACKAGE_NAME)
+ installPackage(APP_APK_PATH_23)
+
+ // Make no permissions are granted after uninstalling and installing the app
+ assertAppHasAllOrNoPermissions(false)
+ }
+
+ @Test
+ fun testNullPermissionRequest() {
+ val permissions: Array<String?> = arrayOf(null)
+ val results: Array<Pair<String?, Boolean>> = arrayOf()
+ // Go through normal grant flow
+ requestAppPermissionsAndAssertResult(
+ permissions,
+ results,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @Test
+ fun testNullAndRealPermission() {
+ // Make sure we don't have the permissions
+ assertAppHasPermission(android.Manifest.permission.WRITE_CONTACTS, false)
+ assertAppHasPermission(android.Manifest.permission.RECORD_AUDIO, false)
+
+ // Request the permission and allow it
+ // Expect the permission are granted
+ requestAppPermissionsAndAssertResult(
+ arrayOf(
+ android.Manifest.permission.WRITE_CONTACTS,
+ null,
+ android.Manifest.permission.RECORD_AUDIO,
+ null
+ ),
+ arrayOf(
+ android.Manifest.permission.WRITE_CONTACTS to true,
+ android.Manifest.permission.RECORD_AUDIO to true
+ )
+ ) {
+ clickPermissionRequestAllowForegroundButton()
+ clickPermissionRequestAllowButton()
+ }
+ }
+
+ @Test
+ fun testInvalidPermission() {
+ // Request the permission and allow it
+ // Expect the permission is not granted
+ requestAppPermissionsAndAssertResult(
+ INVALID_PERMISSION to false,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @Test
+ fun testAskButtonSetsFlags() {
+ Assume.assumeFalse(
+ "other form factors might not support the ask button",
+ isTv || isAutomotive || isWatch
+ )
+
+ grantAppPermissionsByUi(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION)
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, true)
+ assertAppHasPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, true)
+ assertAppHasPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, true)
+
+ revokeAppPermissionsByUi(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION)
+ SystemUtil.runWithShellPermissionIdentity {
+ val perms =
+ listOf(
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_COARSE_LOCATION
+ )
+ for (perm in perms) {
+ var flags = packageManager.getPermissionFlags(perm, APP_PACKAGE_NAME, context.user)
+ Assert.assertEquals(
+ "USER_SET should not be set for $perm",
+ 0,
+ flags and PackageManager.FLAG_PERMISSION_USER_SET
+ )
+ Assert.assertEquals(
+ "USER_FIXED should not be set for $perm",
+ 0,
+ flags and PackageManager.FLAG_PERMISSION_USER_FIXED
+ )
+ Assert.assertEquals(
+ "ONE_TIME should be set for $perm",
+ PackageManager.FLAG_PERMISSION_ONE_TIME,
+ flags and PackageManager.FLAG_PERMISSION_ONE_TIME
+ )
+ }
+ }
+ }
+
+ private fun denyPermissionRequestWithPrejudice() {
+ if (isTv || isWatch) {
+ clickPermissionRequestDontAskAgainButton()
+ } else {
+ clickPermissionRequestDenyAndDontAskAgainButton()
+ }
+ }
+
+ private fun assertAppHasAllOrNoPermissions(expectPermissions: Boolean) {
+ arrayOf(
+ android.Manifest.permission.SEND_SMS,
+ android.Manifest.permission.RECEIVE_SMS,
+ android.Manifest.permission.RECEIVE_WAP_PUSH,
+ android.Manifest.permission.RECEIVE_MMS,
+ android.Manifest.permission.READ_CALENDAR,
+ android.Manifest.permission.WRITE_CALENDAR,
+ android.Manifest.permission.WRITE_CONTACTS,
+ android.Manifest.permission.READ_SMS,
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_CALL_LOG,
+ android.Manifest.permission.WRITE_CALL_LOG,
+ android.Manifest.permission.ADD_VOICEMAIL,
+ android.Manifest.permission.CALL_PHONE,
+ android.Manifest.permission.USE_SIP,
+ android.Manifest.permission.PROCESS_OUTGOING_CALLS,
+ android.Manifest.permission.RECORD_AUDIO,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ android.Manifest.permission.CAMERA,
+ android.Manifest.permission.BODY_SENSORS,
+ android.Manifest.permission.READ_CELL_BROADCASTS,
+ // Split permissions
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION,
+ // Storage permissions
+ android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )
+ .forEach { assertAppHasPermission(it, expectPermissions) }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest29.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest29.kt
new file mode 100644
index 000000000..892cae5c6
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest29.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.permission.cts.MtsIgnore
+import androidx.test.filters.FlakyTest
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.eventually
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+
+/** Runtime permission behavior tests for apps targeting API 29. */
+@FlakyTest
+class PermissionTest29 : BaseUsePermissionTest() {
+ @Before
+ fun assumeNotTv() {
+ assumeFalse(isTv)
+ }
+
+ @Before
+ fun installApp29() {
+ installPackage(APP_APK_PATH_29)
+ }
+
+ @Before
+ fun assertAppHasNoPermissions() {
+ assertAppHasPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, false)
+ }
+
+ @Test
+ fun testRequestOnlyBackgroundNotPossible() {
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to false,
+ waitForWindowTransition = false
+ ) {}
+
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, false)
+ }
+
+ @Test
+ fun testRequestBoth() {
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to true,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to true,
+ waitForWindowTransition = false
+ ) {
+ clickPermissionRequestSettingsLinkAndAllowAlways()
+ }
+ }
+
+ @Test
+ fun testRequestBothInSequence() {
+ // Step 1: request foreground only
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to true
+ ) {
+ clickPermissionRequestAllowForegroundButton()
+ }
+
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, false)
+
+ // Step 2: request background only
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to true,
+ waitForWindowTransition = false
+ ) {
+ clickPermissionRequestSettingsLinkAndAllowAlways()
+ }
+
+ assertAppHasPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, true)
+ }
+
+ @Test
+ fun testRequestBothButGrantInSequence() {
+ // Step 1: grant foreground only
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to true,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to false
+ ) {
+ clickPermissionRequestAllowForegroundButton()
+ }
+
+ // Step 2: grant background
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to true,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to true,
+ waitForWindowTransition = false
+ ) {
+ clickPermissionRequestSettingsLinkAndAllowAlways()
+ }
+ }
+
+ @FlakyTest
+ @MtsIgnore
+ @Test
+ fun testDenyBackgroundWithPrejudice() {
+ // Step 1: deny the first time
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to false,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to false
+ ) {
+ clickPermissionRequestDenyButton()
+ }
+
+ // Step 2: deny with prejudice
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to false,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to false
+ ) {
+ clickPermissionRequestDenyAndDontAskAgainButton()
+ }
+
+ // Step 3: All further requests should be denied automatically
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to false,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to false,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @FlakyTest
+ @MtsIgnore
+ @Test
+ fun testGrantDialogToSettingsNoOp() {
+ // Step 1: Request both, go to settings, do nothing
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to true,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to false,
+ waitForWindowTransition = false
+ ) {
+ openSettingsThenDoNothingThenLeave()
+
+ assertAppHasPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, false)
+
+ doAndWaitForWindowTransition { clickPermissionRequestAllowForegroundButton() }
+ }
+
+ // Step 2: Upgrade foreground to background, go to settings, do nothing
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to true,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to false,
+ waitForWindowTransition = false
+ ) {
+ openSettingsThenDoNothingThenLeave()
+
+ assertAppHasPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, true)
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, false)
+
+ doAndWaitForWindowTransition { clickPermissionRequestNoUpgradeAndDontAskAgainButton() }
+ }
+ }
+
+ private fun openSettingsThenDoNothingThenLeave() {
+ clickPermissionRequestSettingsLink()
+ eventually {
+ pressBack()
+ if (isAutomotive) {
+ waitFindObject(By.textContains("Allow in settings."), 100)
+ } else {
+ waitFindObject(By.res("com.android.permissioncontroller:id/grant_dialog"), 100)
+ }
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun testGrantDialogToSettingsDowngrade() {
+ // Request upgrade, downgrade permission to denied in settings
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.ACCESS_FINE_LOCATION to true,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION to false
+ ) {
+ clickPermissionRequestAllowForegroundButton()
+ }
+
+ requestAppPermissions(
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION,
+ waitForWindowTransition = false
+ ) {
+ clickPermissionRequestSettingsLinkAndDeny()
+ pressBack()
+ }
+
+ assertAppHasPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, false)
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest30.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest30.kt
new file mode 100644
index 000000000..25bdab298
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest30.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
+import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import androidx.test.filters.FlakyTest
+import androidx.test.uiautomator.By
+import org.junit.Assert.assertNull
+import org.junit.Test
+
+/** Runtime permission behavior apps targeting API 30 */
+@FlakyTest
+class PermissionTest30 : BaseUsePermissionTest() {
+
+ @Test
+ fun testCantRequestFgAndBgAtOnce() {
+ // TODO(b/280542662): This delay is a temporary mitigation for an intermittent failure
+ Thread.sleep(500)
+ installPackage(APP_APK_PATH_30_WITH_BACKGROUND)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(ACCESS_BACKGROUND_LOCATION, false)
+
+ requestAppPermissionsAndAssertResult(
+ ACCESS_FINE_LOCATION to false,
+ ACCESS_BACKGROUND_LOCATION to false,
+ waitForWindowTransition = false
+ ) {
+ // Do nothing, should be automatically denied
+ }
+ }
+
+ @Test
+ fun testRequestBothInSequence() {
+ installPackage(APP_APK_PATH_30_WITH_BACKGROUND)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(ACCESS_BACKGROUND_LOCATION, false)
+
+ requestAppPermissionsAndAssertResult(ACCESS_FINE_LOCATION to true) {
+ clickPermissionRequestAllowForegroundButton()
+ }
+
+ requestAppPermissionsAndAssertResult(
+ ACCESS_BACKGROUND_LOCATION to true,
+ waitForWindowTransition = false
+ ) {
+ clickAllowAlwaysInSettings()
+ pressBack()
+ }
+ }
+
+ @Test
+ fun testRequestFgLocationAndNoAccuracyOptions() {
+ installPackage(APP_APK_PATH_30)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+
+ requestAppPermissionsAndAssertResult(
+ ACCESS_FINE_LOCATION to false,
+ ACCESS_COARSE_LOCATION to false
+ ) {
+ // Verify there's no location accuracy options
+ val locationAccuracyOptions =
+ waitFindObjectOrNull(
+ By.res("com.android.permissioncontroller:id/permission_location_accuracy"),
+ 1000L
+ )
+ assertNull(
+ "For apps targetSDK < 31, location permission dialog shouldn't show " +
+ "accuracy options. Please update the system with " +
+ "the latest (at least Oct, 2021) mainline modules.",
+ locationAccuracyOptions
+ )
+ // Close dialog
+ clickPermissionRequestDenyButton()
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest30WithBluetooth.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest30WithBluetooth.kt
new file mode 100644
index 000000000..493aa60fb
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTest30WithBluetooth.kt
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.Manifest.permission.BLUETOOTH_SCAN
+import android.app.AppOpsManager
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothManager
+import android.bluetooth.cts.BTAdapterUtils
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
+import android.location.LocationManager
+import android.os.Build
+import android.os.Process
+import android.os.UserHandle
+import android.util.Log
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertTrue
+import junit.framework.AssertionFailedError
+import org.junit.After
+import org.junit.Assert.assertNotEquals
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+
+private const val LOG_TAG = "PermissionTest30WithBluetooth"
+
+/** Runtime Bluetooth-permission behavior of apps targeting API 30 */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+@FlakyTest
+class PermissionTest30WithBluetooth : BaseUsePermissionTest() {
+
+ private val TEST_APP_AUTHORITY =
+ "android.permissionui.cts.usepermission.AccessBluetoothOnCommand"
+ private val TEST_APP_PKG = "android.permissionui.cts.usepermission"
+ private lateinit var bluetoothAdapter: BluetoothAdapter
+ private var bluetoothAdapterWasEnabled: Boolean = false
+ private val locationManager = context.getSystemService(LocationManager::class.java)!!
+ private var locationWasEnabled: Boolean = false
+
+ private enum class BluetoothScanResult {
+ UNKNOWN,
+ ERROR,
+ EXCEPTION,
+ EMPTY,
+ FILTERED,
+ FULL
+ }
+
+ @Before
+ fun installApp() {
+ installPackage(APP_APK_PATH_30_WITH_BLUETOOTH)
+ }
+
+ private fun reinstallApp() {
+ installPackage(APP_APK_PATH_30_WITH_BLUETOOTH, reinstall = true)
+ }
+
+ @Before
+ fun enableBluetooth() {
+ assumeTrue(supportsBluetooth())
+ bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
+ bluetoothAdapterWasEnabled = bluetoothAdapter.isEnabled()
+ runWithShellPermissionIdentity {
+ assertTrue(BTAdapterUtils.enableAdapter(bluetoothAdapter, context))
+ }
+ enableTestMode()
+ }
+
+ @Before
+ fun enableLocation() {
+ val userHandle: UserHandle = Process.myUserHandle()
+ locationWasEnabled = locationManager.isLocationEnabledForUser(userHandle)
+ if (!locationWasEnabled) {
+ runWithShellPermissionIdentity {
+ locationManager.setLocationEnabledForUser(true, userHandle)
+ }
+ }
+ }
+
+ @After
+ fun disableLocation() {
+ val userHandle: UserHandle = Process.myUserHandle()
+
+ if (!locationWasEnabled) {
+ runWithShellPermissionIdentity {
+ locationManager.setLocationEnabledForUser(false, userHandle)
+ }
+ }
+ }
+
+ @After
+ fun disableBluetooth() {
+ assumeTrue(supportsBluetooth())
+ disableTestMode()
+ if (!bluetoothAdapterWasEnabled) {
+ runWithShellPermissionIdentity {
+ assertTrue(BTAdapterUtils.disableAdapter(bluetoothAdapter, context))
+ }
+ }
+ }
+
+ // TODO:(b/220030722) Remove verbose logging (after test is stabilized)
+ @Test
+ fun testGivenBluetoothIsDeniedWhenScanIsAttemptedThenThenGetEmptyScanResult() {
+ assumeTrue(supportsBluetoothLe())
+
+ assertTrue(
+ "Please enable location to run this test. Bluetooth scanning " +
+ "requires location to be enabled.",
+ locationManager.isLocationEnabled()
+ )
+ assertBluetoothRevokedCompatState(revoked = false)
+
+ Log.v(
+ LOG_TAG,
+ "Testing for: Given {BLUETOOTH_SCAN, !BLUETOOTH_SCAN.COMPAT_REVOKE, " +
+ "!ACCESS_*_LOCATION}, expect EMPTY"
+ )
+ assertEquals(BluetoothScanResult.EMPTY, scanForBluetoothDevices())
+
+ Log.v(
+ LOG_TAG,
+ "Testing for: Given {BLUETOOTH_SCAN, !BLUETOOTH_SCAN.COMPAT_REVOKE, " +
+ "ACCESS_*_LOCATION}, expect FULL"
+ )
+ uiAutomation.grantRuntimePermission(TEST_APP_PKG, ACCESS_FINE_LOCATION)
+ uiAutomation.grantRuntimePermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION)
+ setAppOp(context.packageName, AppOpsManager.OPSTR_FINE_LOCATION, AppOpsManager.MODE_ALLOWED)
+ assertEquals(BluetoothScanResult.FULL, scanForBluetoothDevices())
+
+ Log.v(
+ LOG_TAG,
+ "Testing for: Given {BLUETOOTH_SCAN, BLUETOOTH_SCAN.COMPAT_REVOKE, " +
+ "ACCESS_*_LOCATION}, expect ERROR"
+ )
+ revokeAppPermissionsByUi(BLUETOOTH_SCAN, isLegacyApp = true)
+ assertBluetoothRevokedCompatState(revoked = true)
+ val res = scanForBluetoothDevices()
+ if (res != BluetoothScanResult.ERROR && res != BluetoothScanResult.EMPTY) {
+ throw AssertionFailedError("Expected to be EMPTY or ERROR, but was $res")
+ }
+ }
+
+ private fun setAppOp(packageName: String, appOp: String, appOpMode: Int) {
+ runWithShellPermissionIdentity {
+ context
+ .getSystemService(AppOpsManager::class.java)!!
+ .setUidMode(appOp, packageManager.getPackageUid(packageName, 0), appOpMode)
+ }
+ }
+
+ @Test
+ fun testRevokedCompatPersistsOnReinstall() {
+ assertBluetoothRevokedCompatState(revoked = false)
+ revokeAppPermissionsByUi(BLUETOOTH_SCAN, isLegacyApp = true)
+ assertBluetoothRevokedCompatState(revoked = true)
+ reinstallApp()
+ assertBluetoothRevokedCompatState(revoked = true)
+ installApp()
+ assertBluetoothRevokedCompatState(revoked = true)
+ }
+
+ private fun assertBluetoothRevokedCompatState(revoked: Boolean = true) {
+ runWithShellPermissionIdentity {
+ val flag =
+ context.packageManager.getPermissionFlags(
+ BLUETOOTH_SCAN,
+ TEST_APP_PKG,
+ Process.myUserHandle()
+ ) and FLAG_PERMISSION_REVOKED_COMPAT
+ if (revoked) {
+ assertNotEquals(0, flag)
+ } else {
+ assertEquals(0, flag)
+ }
+ }
+ }
+
+ private fun scanForBluetoothDevices(): BluetoothScanResult {
+ val resolver = InstrumentationRegistry.getTargetContext().getContentResolver()
+ val result = resolver.call(TEST_APP_AUTHORITY, "", null, null)
+ return BluetoothScanResult.values()[result!!.getInt(Intent.EXTRA_INDEX)]
+ }
+
+ private fun supportsBluetooth(): Boolean =
+ context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+
+ private fun supportsBluetoothLe(): Boolean =
+ context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
+
+ private fun enableTestMode() =
+ runShellCommandOrThrow(
+ "dumpsys activity service" +
+ " com.android.bluetooth.btservice.AdapterService set-test-mode enabled"
+ )
+
+ private fun disableTestMode() =
+ runShellCommandOrThrow(
+ "dumpsys activity service" +
+ " com.android.bluetooth.btservice.AdapterService set-test-mode disabled"
+ )
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionUpgradeTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionUpgradeTest.kt
new file mode 100644
index 000000000..3948e984f
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionUpgradeTest.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import androidx.test.filters.FlakyTest
+import org.junit.Assume
+import org.junit.Test
+
+/** Runtime permission behavior tests for upgrading apps. */
+@FlakyTest
+class PermissionUpgradeTest : BaseUsePermissionTest() {
+
+ @Test
+ fun testUpgradeKeepsPermissions() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
+ installPackage(APP_APK_PATH_22)
+
+ approvePermissionReview()
+
+ assertAllPermissionsGrantedByDefault()
+
+ installPackage(APP_APK_PATH_23, reinstall = true, skipClearLowSdkDialog = true)
+
+ assertAllPermissionsGrantedOnUpgrade()
+ }
+
+ private fun assertAllPermissionsGrantedByDefault() {
+ arrayOf(
+ android.Manifest.permission.SEND_SMS,
+ android.Manifest.permission.RECEIVE_SMS,
+ // The APK does not request READ_CONTACTS because of other tests
+ android.Manifest.permission.WRITE_CONTACTS,
+ android.Manifest.permission.READ_CALENDAR,
+ android.Manifest.permission.WRITE_CALENDAR,
+ android.Manifest.permission.READ_SMS,
+ android.Manifest.permission.RECEIVE_WAP_PUSH,
+ android.Manifest.permission.RECEIVE_MMS,
+ "android.permission.READ_CELL_BROADCASTS",
+ android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.CALL_PHONE,
+ android.Manifest.permission.READ_CALL_LOG,
+ android.Manifest.permission.WRITE_CALL_LOG,
+ android.Manifest.permission.ADD_VOICEMAIL,
+ android.Manifest.permission.USE_SIP,
+ android.Manifest.permission.PROCESS_OUTGOING_CALLS,
+ android.Manifest.permission.CAMERA,
+ android.Manifest.permission.BODY_SENSORS,
+ // Split permissions
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
+ )
+ .forEach { assertAppHasPermission(it, true) }
+ }
+
+ private fun assertAllPermissionsGrantedOnUpgrade() {
+ assertAppHasAllOrNoPermissions(true)
+ }
+
+ @Test
+ fun testNoDowngradePermissionModel() {
+ installPackage(APP_APK_PATH_23, skipClearLowSdkDialog = true)
+ installPackage(APP_APK_PATH_22, reinstall = true, expectSuccess = false)
+ }
+
+ @Test
+ fun testRevokePropagatedOnUpgradeOldToNewModel() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
+ installPackage(APP_APK_PATH_22)
+
+ approvePermissionReview()
+
+ // Revoke a permission
+ revokeAppPermissionsByUi(android.Manifest.permission.WRITE_CALENDAR, isLegacyApp = true)
+
+ installPackage(APP_APK_PATH_23, reinstall = true, skipClearLowSdkDialog = true)
+
+ assertAppHasPermission(android.Manifest.permission.WRITE_CALENDAR, false)
+ }
+
+ @Test
+ fun testRevokePropagatedOnUpgradeNewToNewModel() {
+ installPackage(APP_APK_PATH_23)
+
+ // Make sure we don't have the permission
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, false)
+ assertAppHasPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, false)
+
+ // Request the permission and allow it
+ // Make sure the permission is granted
+ requestAppPermissionsAndAssertResult(
+ android.Manifest.permission.READ_CALENDAR to true,
+ ) {
+ clickPermissionRequestAllowButton()
+ }
+
+ installPackage(APP_APK_PATH_23, reinstall = true, skipClearLowSdkDialog = true)
+
+ // Make sure the permission is still granted after the upgrade
+ assertAppHasPermission(android.Manifest.permission.READ_CALENDAR, true)
+ // Also make sure one of the not granted permissions is still not granted
+ assertAppHasPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, false)
+ }
+
+ private fun assertAppHasAllOrNoPermissions(expectPermissions: Boolean) {
+ arrayOf(
+ android.Manifest.permission.SEND_SMS,
+ android.Manifest.permission.RECEIVE_SMS,
+ android.Manifest.permission.RECEIVE_WAP_PUSH,
+ android.Manifest.permission.RECEIVE_MMS,
+ android.Manifest.permission.READ_CALENDAR,
+ android.Manifest.permission.WRITE_CALENDAR,
+ android.Manifest.permission.WRITE_CONTACTS,
+ android.Manifest.permission.READ_SMS,
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_CALL_LOG,
+ android.Manifest.permission.WRITE_CALL_LOG,
+ android.Manifest.permission.ADD_VOICEMAIL,
+ android.Manifest.permission.CALL_PHONE,
+ android.Manifest.permission.USE_SIP,
+ android.Manifest.permission.PROCESS_OUTGOING_CALLS,
+ android.Manifest.permission.RECORD_AUDIO,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ android.Manifest.permission.CAMERA,
+ android.Manifest.permission.BODY_SENSORS,
+ android.Manifest.permission.READ_CELL_BROADCASTS,
+ // Split permissions
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION,
+ // Storage permissions
+ android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )
+ .forEach { assertAppHasPermission(it, expectPermissions) }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionUsageInfoTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionUsageInfoTest.kt
new file mode 100644
index 000000000..80e3dfaed
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionUsageInfoTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.content.Intent
+import androidx.test.filters.FlakyTest
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+
+/** Tests permission usage info action. */
+@FlakyTest
+class PermissionUsageInfoTest : BaseUsePermissionTest() {
+ @Before
+ fun assumeHandheld() {
+ assumeFalse(isAutomotive)
+ assumeFalse(isTv)
+ assumeFalse(isWatch)
+ }
+
+ @Before
+ fun installApp() {
+ installPackage(APP_APK_PATH_LATEST)
+ }
+
+ @Test
+ fun testPermissionUsageInfo() {
+ doAndWaitForWindowTransition {
+ runWithShellPermissionIdentity {
+ context.startActivity(
+ Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS).apply {
+ putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
+ }
+ }
+ click(By.res("com.android.permissioncontroller:id/icon"))
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt
new file mode 100644
index 000000000..1f1aba1e7
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission.ACCESS_MEDIA_LOCATION
+import android.Manifest.permission.READ_MEDIA_IMAGES
+import android.Manifest.permission.READ_MEDIA_VIDEO
+import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+import android.app.UiAutomation.ROTATION_FREEZE_270
+import android.app.UiAutomation.ROTATION_UNFREEZE
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME
+import android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
+import android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED
+import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET
+import android.net.Uri
+import android.os.Build
+import android.provider.DeviceConfig
+import android.provider.DeviceConfig.NAMESPACE_PRIVACY
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.UiAutomatorUtils2
+import org.junit.AfterClass
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@FlakyTest
+class PhotoPickerPermissionTest : BaseUsePermissionTest() {
+
+ companion object {
+ private var photoUri: Uri? = null
+ private var videoUri: Uri? = null
+ private var oldEnableState: Boolean = true
+
+ @BeforeClass
+ @JvmStatic
+ fun enablePickerAndAddMedia() {
+ // Initialize media provider package name
+ PhotoPickerUtils.getMediaProviderPkgName(context)
+ oldEnableState = isPhotoPickerPermissionPromptEnabled()
+ runWithShellPermissionIdentity {
+ if (!oldEnableState) {
+ DeviceConfig.setProperty(
+ NAMESPACE_PRIVACY,
+ PICKER_ENABLED_SETTING,
+ true.toString(),
+ false
+ )
+ }
+ photoUri = PhotoPickerUtils.createImage(context)
+ videoUri = PhotoPickerUtils.createVideo(context)
+ }
+ }
+
+ @AfterClass
+ @JvmStatic
+ fun resetPickerAndRemoveMedia() {
+ if (!oldEnableState) {
+ runWithShellPermissionIdentity {
+ DeviceConfig.setProperty(
+ NAMESPACE_PRIVACY,
+ PICKER_ENABLED_SETTING,
+ false.toString(),
+ false
+ )
+ }
+ }
+
+ PhotoPickerUtils.deleteMedia(context, photoUri)
+ PhotoPickerUtils.deleteMedia(context, videoUri)
+ }
+ }
+
+ @Before
+ fun assumeEnabled() {
+ assumeTrue(isPhotoPickerPermissionPromptEnabled())
+ }
+
+ @Test
+ fun testAppWithoutStoragePermsDoesntHaveUserSelectedAdded() {
+ installPackage(APP_APK_PATH_LATEST_NONE)
+ runWithShellPermissionIdentity {
+ val packageInfo =
+ packageManager.getPackageInfo(APP_PACKAGE_NAME, PackageManager.GET_PERMISSIONS)
+ assertNotNull(packageInfo)
+ val permissions = packageInfo.requestedPermissions?.toList() ?: emptyList<String>()
+ assertFalse(
+ "Expected app to not request READ_MEDIA_VISUAL_USER_SELECTED",
+ permissions.contains(READ_MEDIA_VISUAL_USER_SELECTED)
+ )
+ }
+ }
+
+ @Test
+ fun testAppWithStoragePermsHasUserSelectedAdded() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ runWithShellPermissionIdentity {
+ val packageInfo =
+ packageManager.getPackageInfo(APP_PACKAGE_NAME, PackageManager.GET_PERMISSIONS)
+ assertNotNull(packageInfo)
+ val permissions = packageInfo.requestedPermissions?.toList() ?: emptyList<String>()
+ assertTrue(
+ "Expected app to request READ_MEDIA_VISUAL_USER_SELECTED",
+ permissions.contains(READ_MEDIA_VISUAL_USER_SELECTED)
+ )
+ }
+ }
+
+ @Test
+ fun testAppWithUserSelectedPermShowsSelectOption() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ requestAppPermissions(READ_MEDIA_IMAGES) {
+ assertNotNull(waitFindObjectOrNull(By.res(SELECT_BUTTON)))
+ click(By.res(DENY_BUTTON))
+ }
+ }
+
+ @Test
+ fun testNoPhotoSelectionTreatedAsCancel() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ requestAppPermissionsAndAssertResult(
+ arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED),
+ arrayOf(READ_MEDIA_IMAGES to false, READ_MEDIA_VISUAL_USER_SELECTED to false),
+ waitForWindowTransition = false
+ ) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ findImageOrVideo(expected = true)
+ uiDevice.pressBack()
+ }
+ assertPermissionFlags(READ_MEDIA_IMAGES, FLAG_PERMISSION_USER_SET to false)
+ assertPermissionFlags(READ_MEDIA_VISUAL_USER_SELECTED, FLAG_PERMISSION_USER_SET to false)
+ }
+
+ @Test
+ fun testImplicitUserSelectHasOneTimeGrantsWithoutAppOp() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ requestAppPermissionsAndAssertResult(
+ arrayOf(READ_MEDIA_IMAGES),
+ arrayOf(READ_MEDIA_IMAGES to true),
+ waitForWindowTransition = false
+ ) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ clickImageOrVideo()
+ clickAllow()
+ }
+ eventually {
+ // USER_SELECTED should be granted, but not returned in the result
+ assertAppHasPermission(READ_MEDIA_VISUAL_USER_SELECTED, expectPermission = true)
+ assertAppHasPermission(READ_MEDIA_VIDEO, expectPermission = true)
+ assertPermissionFlags(
+ READ_MEDIA_IMAGES,
+ FLAG_PERMISSION_ONE_TIME to true,
+ FLAG_PERMISSION_REVOKED_COMPAT to true
+ )
+ assertPermissionFlags(
+ READ_MEDIA_VIDEO,
+ FLAG_PERMISSION_ONE_TIME to true,
+ FLAG_PERMISSION_REVOKED_COMPAT to true
+ )
+ assertPermissionFlags(
+ READ_MEDIA_VISUAL_USER_SELECTED,
+ FLAG_PERMISSION_ONE_TIME to false,
+ FLAG_PERMISSION_REVOKED_COMPAT to false
+ )
+ }
+ }
+
+ @Test
+ fun testImplicitShowsMorePhotosOnceSet() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ eventually {
+ uiAutomation.grantRuntimePermission(APP_PACKAGE_NAME, READ_MEDIA_VISUAL_USER_SELECTED)
+ assertAppHasPermission(READ_MEDIA_VISUAL_USER_SELECTED, true)
+ }
+
+ requestAppPermissions(READ_MEDIA_IMAGES, waitForWindowTransition = false) {
+ waitFindObject(By.res(DONT_SELECT_MORE_BUTTON))
+ uiDevice.pressBack()
+ }
+ }
+
+ @Test
+ fun testNonImplicitDoesntGrantOtherPermsWhenUserSelected() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissionsAndAssertResult(
+ arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED),
+ arrayOf(READ_MEDIA_IMAGES to false, READ_MEDIA_VISUAL_USER_SELECTED to true),
+ waitForWindowTransition = false
+ ) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ clickImageOrVideo()
+ clickAllow()
+ }
+
+ assertPermissionFlags(READ_MEDIA_IMAGES, FLAG_PERMISSION_USER_SET to true)
+ assertPermissionFlags(READ_MEDIA_VISUAL_USER_SELECTED, FLAG_PERMISSION_USER_SET to true)
+ }
+
+ @Test
+ fun testNonImplicitAutomaticallyShowsPickerWhenUserFixed() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissions(READ_MEDIA_IMAGES, waitForWindowTransition = false) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ clickImageOrVideo()
+ doAndWaitForWindowTransition { clickAllow() }
+ }
+
+ requestAppPermissions(READ_MEDIA_IMAGES, waitForWindowTransition = false) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ clickImageOrVideo()
+ doAndWaitForWindowTransition { clickAllow() }
+ }
+
+ assertPermissionFlags(READ_MEDIA_VISUAL_USER_SELECTED, FLAG_PERMISSION_USER_FIXED to true)
+
+ requestAppPermissions(READ_MEDIA_IMAGES, waitForWindowTransition = false) {
+ findImageOrVideo(expected = true)
+ uiDevice.pressBack()
+ }
+ }
+
+ @Test
+ fun testRequestedPermsFilterMediaType() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissions(READ_MEDIA_IMAGES, waitForWindowTransition = false) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ findImageOrVideo(expected = true)
+ findVideo(expected = false)
+ uiDevice.pressBack()
+ }
+
+ requestAppPermissions(READ_MEDIA_VIDEO, waitForWindowTransition = false) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ findVideo(expected = true)
+ uiDevice.pressBack()
+ }
+ }
+
+ @Test
+ fun testGrantAllPhotosStateSameForImplicitAndNot() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ requestAppPermissionsAndAssertResult(
+ arrayOf(READ_MEDIA_IMAGES),
+ arrayOf(READ_MEDIA_IMAGES to true)
+ ) {
+ click(By.res(ALLOW_ALL_BUTTON))
+ }
+
+ eventually {
+ assertAppHasPermission(READ_MEDIA_VISUAL_USER_SELECTED, expectPermission = true)
+ }
+
+ uninstallPackage(APP_PACKAGE_NAME)
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissionsAndAssertResult(
+ arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED),
+ arrayOf(READ_MEDIA_IMAGES to true, READ_MEDIA_VISUAL_USER_SELECTED to true)
+ ) {
+ click(By.res(ALLOW_ALL_BUTTON))
+ }
+ }
+
+ @Test
+ fun testGrantAllPhotosInSettings() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ navigateToIndividualPermissionSetting(READ_MEDIA_IMAGES)
+ click(By.res(ALLOW_RADIO_BUTTON))
+
+ eventually {
+ assertAppHasPermission(READ_MEDIA_IMAGES, expectPermission = true)
+ assertAppHasPermission(READ_MEDIA_VIDEO, expectPermission = true)
+ assertAppHasPermission(ACCESS_MEDIA_LOCATION, expectPermission = true)
+ assertAppHasPermission(READ_MEDIA_VISUAL_USER_SELECTED, expectPermission = true)
+ }
+ }
+
+ @Test
+ fun testSelectPhotosInSettingsImplicit() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ navigateToIndividualPermissionSetting(READ_MEDIA_IMAGES)
+ click(By.res(SELECT_RADIO_BUTTON))
+
+ eventually {
+ assertAppHasPermission(READ_MEDIA_IMAGES, expectPermission = false)
+ assertAppHasPermission(READ_MEDIA_VIDEO, expectPermission = false)
+ assertAppHasPermission(ACCESS_MEDIA_LOCATION, expectPermission = false)
+ assertAppHasPermission(READ_MEDIA_VISUAL_USER_SELECTED, expectPermission = true)
+ }
+ }
+
+ @Test
+ fun testSelectPhotosInSettingsExplicit() {
+ installPackage(APP_APK_PATH_LATEST)
+ navigateToIndividualPermissionSetting(READ_MEDIA_IMAGES)
+ click(By.res(SELECT_RADIO_BUTTON))
+
+ eventually {
+ assertAppHasPermission(READ_MEDIA_IMAGES, expectPermission = false)
+ assertAppHasPermission(READ_MEDIA_VIDEO, expectPermission = false)
+ assertAppHasPermission(ACCESS_MEDIA_LOCATION, expectPermission = true)
+ assertAppHasPermission(READ_MEDIA_VISUAL_USER_SELECTED, expectPermission = true)
+ }
+ }
+
+ @Test
+ @Throws(PackageManager.NameNotFoundException::class)
+ fun testPre33AppDoesntShowSelect() {
+ installPackage(APP_APK_PATH_30)
+ runWithShellPermissionIdentity {
+ val requestedPerms =
+ packageManager
+ .getPackageInfo(APP_PACKAGE_NAME, PackageManager.GET_PERMISSIONS)
+ .requestedPermissions!!
+ .toList()
+ assertTrue(
+ "Expected package to have USER_SELECTED",
+ requestedPerms.contains(READ_MEDIA_VISUAL_USER_SELECTED)
+ )
+ }
+
+ requestAppPermissions(READ_MEDIA_IMAGES, waitForWindowTransition = false) {
+ findView(By.res(SELECT_BUTTON), expected = false)
+ pressBack()
+ }
+
+ navigateToIndividualPermissionSetting(READ_MEDIA_IMAGES)
+ findView(By.res(SELECT_RADIO_BUTTON), expected = false)
+ }
+
+ @Test
+ fun test33AppWithImplicitUserSelectDoesntShowSelect() {
+ installPackage(APP_APK_PATH_STORAGE_33)
+
+ runWithShellPermissionIdentity {
+ val requestedPerms =
+ packageManager
+ .getPackageInfo(APP_PACKAGE_NAME, PackageManager.GET_PERMISSIONS)
+ .requestedPermissions!!
+ .toList()
+ assertTrue(
+ "Expected package to have USER_SELECTED",
+ requestedPerms.contains(READ_MEDIA_VISUAL_USER_SELECTED)
+ )
+ }
+
+ requestAppPermissions(READ_MEDIA_IMAGES, waitForWindowTransition = false) {
+ findView(By.res(SELECT_BUTTON), expected = false)
+ pressBack()
+ }
+
+ navigateToIndividualPermissionSetting(READ_MEDIA_IMAGES)
+ findView(By.res(SELECT_RADIO_BUTTON), expected = false)
+ }
+
+ @Test
+ fun testAppCantRequestOnlyPartialStoragePerms() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ requestAppPermissionsAndAssertResult(
+ READ_MEDIA_VISUAL_USER_SELECTED to false,
+ waitForWindowTransition = false
+ ) {}
+ uninstallPackage(APP_PACKAGE_NAME)
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissionsAndAssertResult(
+ READ_MEDIA_VISUAL_USER_SELECTED to false,
+ ACCESS_MEDIA_LOCATION to false,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @Test
+ fun testImplicitAppCanExpandAccessMediaLocation() {
+ installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE)
+ requestAppPermissions(ACCESS_MEDIA_LOCATION) { click(By.res(ALLOW_ALL_BUTTON)) }
+ requestAppPermissionsAndAssertResult(
+ READ_MEDIA_IMAGES to true,
+ READ_MEDIA_VIDEO to true,
+ waitForWindowTransition = false
+ ) {}
+ }
+
+ @Test
+ fun testExplicitAppCannotExpandAccessMediaLocation() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissionsAndAssertResult(
+ READ_MEDIA_IMAGES to false,
+ ACCESS_MEDIA_LOCATION to true,
+ READ_MEDIA_VISUAL_USER_SELECTED to true,
+ waitForWindowTransition = false
+ ) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ clickImageOrVideo()
+ clickAllow()
+ }
+ requestAppPermissions(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO) {
+ click(By.res(ALLOW_ALL_BUTTON))
+ }
+ }
+
+ @Test
+ fun testExplicitAppCannotRequestOnlyPartialAccess() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissionsAndAssertResult(
+ ACCESS_MEDIA_LOCATION to false,
+ READ_MEDIA_VISUAL_USER_SELECTED to false,
+ waitForWindowTransition = false
+ ) {
+ findView(By.res(SELECT_BUTTON), expected = false)
+ }
+ }
+
+ @Test
+ fun testMorePhotosDialogShowsAfterClickingSelect() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissionsAndAssertResult(
+ READ_MEDIA_IMAGES to false,
+ ACCESS_MEDIA_LOCATION to true,
+ READ_MEDIA_VISUAL_USER_SELECTED to true,
+ waitForWindowTransition = false
+ ) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ clickImageOrVideo()
+ doAndWaitForWindowTransition { clickAllow() }
+ }
+
+ requestAppPermissions(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO) {
+ findView(By.res(DONT_SELECT_MORE_BUTTON), expected = true)
+ click(By.res(ALLOW_ALL_BUTTON))
+ }
+ }
+
+ @Test
+ fun testAMLNotGrantedIfNotRequested() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissionsAndAssertResult(
+ READ_MEDIA_IMAGES to false,
+ READ_MEDIA_VISUAL_USER_SELECTED to true,
+ waitForWindowTransition = false
+ ) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ clickImageOrVideo()
+ doAndWaitForWindowTransition { clickAllow() }
+ }
+ assertAppHasPermission(ACCESS_MEDIA_LOCATION, false)
+ }
+
+ @Test
+ fun testDismissAfterActivityRecreatedWithPickerOpen() {
+ installPackage(APP_APK_PATH_LATEST)
+ requestAppPermissionsAndAssertResult(
+ READ_MEDIA_IMAGES to false,
+ READ_MEDIA_VISUAL_USER_SELECTED to true,
+ waitForWindowTransition = false
+ ) {
+ doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) }
+ clickImageOrVideo()
+ try {
+ doAndWaitForWindowTransition { uiAutomation.setRotation(ROTATION_FREEZE_270) }
+ clickImageOrVideo()
+ doAndWaitForWindowTransition { clickAllow() }
+ } finally {
+ uiAutomation.setRotation(ROTATION_UNFREEZE)
+ }
+ }
+ }
+
+ @Test
+ fun testCanSelectPhotosInSettings() {
+ installPackage(APP_APK_PATH_LATEST)
+ navigateToIndividualPermissionSetting(READ_MEDIA_IMAGES)
+ click(By.res(SELECT_RADIO_BUTTON))
+ doAndWaitForWindowTransition { click(By.res(EDIT_PHOTOS_BUTTON)) }
+ clickImageOrVideo()
+ clickAllow()
+ }
+
+ @Test
+ fun testEditButtonNotShownInSettingsWhenNoPhotosRequested() {
+ installPackage(APP_APK_PATH_LATEST)
+ navigateToIndividualPermissionSetting(READ_MEDIA_IMAGES)
+ UiAutomatorUtils2.waitUntilObjectGone(By.res(EDIT_PHOTOS_BUTTON))
+ }
+
+ private fun clickImageOrVideo() {
+ click(By.res(PhotoPickerUtils.getImageOrVideoResId(context)))
+ }
+
+ private fun clickAllow() {
+ click(By.res(PhotoPickerUtils.getAllowId(context)))
+ }
+
+ private fun findImageOrVideo(expected: Boolean) {
+ findView(By.res(PhotoPickerUtils.getImageOrVideoResId(context)), expected)
+ }
+
+ private fun findVideo(expected: Boolean) {
+ findView(By.res(PhotoPickerUtils.getVideoResId(context)), expected)
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerUtils.kt b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerUtils.kt
new file mode 100644
index 000000000..9a6de1514
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerUtils.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Bundle
+import android.os.FileUtils
+import android.provider.MediaStore
+import android.provider.cts.ProviderTestUtils
+import android.provider.cts.media.MediaStoreUtils
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import java.io.IOException
+
+object PhotoPickerUtils {
+ private const val DISPLAY_NAME_PREFIX = "ctsPermissionPhotoPicker"
+ private const val VIDEO_ICON_ID = ":id/icon_video"
+ private const val IMAGE_CHECK_BOX_ID = ":id/icon_check"
+ private const val ALLOW_ID = ":id/button_add"
+ private var mediaProviderPkgName: String? = null
+
+ fun getImageOrVideoResId(context: Context): String {
+ return "${getMediaProviderPkgName(context)!!}$IMAGE_CHECK_BOX_ID"
+ }
+
+ fun getVideoResId(context: Context): String {
+ return "${getMediaProviderPkgName(context)!!}$VIDEO_ICON_ID"
+ }
+
+ fun getAllowId(context: Context): String {
+ return "${getMediaProviderPkgName(context)!!}$ALLOW_ID"
+ }
+
+ fun getMediaProviderPkgName(context: Context): String? {
+ return mediaProviderPkgName
+ ?: callWithShellPermissionIdentity {
+ val pkgs = context.packageManager.getInstalledPackages(PackageManager.GET_PROVIDERS)
+ for (pkg in pkgs) {
+ pkg.providers?.let { providerInfos ->
+ for (providerInfo in providerInfos) {
+ if (providerInfo.authority == "media") {
+ mediaProviderPkgName = pkg.packageName
+ return@callWithShellPermissionIdentity mediaProviderPkgName
+ }
+ }
+ }
+ }
+ null
+ }
+ }
+
+ @Throws(java.lang.Exception::class)
+ fun createImage(context: Context): Uri {
+ return getPermissionAndStageMedia(
+ context,
+ R.raw.lg_g4_iso_800_jpg,
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ "image/jpeg"
+ )
+ .first
+ }
+
+ @Throws(java.lang.Exception::class)
+ fun createVideo(context: Context): Uri {
+ return getPermissionAndStageMedia(
+ context,
+ R.raw.test_video,
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ "video/mp4"
+ )
+ .first
+ }
+
+ @Throws(Exception::class)
+ fun deleteMedia(context: Context, uri: Uri?) {
+ if (uri == null) {
+ return
+ }
+ try {
+ ProviderTestUtils.setOwner(uri, context.packageName)
+ context.contentResolver.delete(uri, Bundle.EMPTY)
+ } catch (ignored: Exception) {}
+ }
+
+ @Throws(java.lang.Exception::class)
+ private fun getPermissionAndStageMedia(
+ context: Context,
+ resId: Int,
+ collectionUri: Uri,
+ mimeType: String,
+ ): Pair<Uri, String> {
+ return callWithShellPermissionIdentity {
+ stageMedia(context, resId, collectionUri, mimeType)
+ }
+ }
+ @Throws(IOException::class)
+ private fun stageMedia(
+ context: Context,
+ resId: Int,
+ collectionUri: Uri,
+ mimeType: String,
+ ): Pair<Uri, String> {
+ val displayName = DISPLAY_NAME_PREFIX + System.nanoTime()
+ val params = MediaStoreUtils.PendingParams(collectionUri, displayName, mimeType)
+ val pendingUri = MediaStoreUtils.createPending(context, params)
+ MediaStoreUtils.openPending(context, pendingUri).use { session ->
+ context.resources.openRawResource(resId).use { source ->
+ session.openOutputStream().use { target -> FileUtils.copy(source, target) }
+ }
+ return session.publish() to displayName
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/ReviewAccessibilityServicesTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/ReviewAccessibilityServicesTest.kt
new file mode 100644
index 000000000..03151c9fe
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/ReviewAccessibilityServicesTest.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService
+import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule
+import android.app.UiAutomation
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.platform.test.annotations.AppModeFull
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Configurator
+import androidx.test.uiautomator.StaleObjectException
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
+import com.android.compatibility.common.util.SystemUtil
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
+import java.util.regex.Pattern
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@AppModeFull(reason = "Instant apps cannot be a11y services")
+@FlakyTest
+class ReviewAccessibilityServicesTest {
+
+ private val context: Context = InstrumentationRegistry.getInstrumentation().context
+ private val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ private val testService1String = context.getString(R.string.test_accessibility_service)
+ private val testService2String = context.getString(R.string.test_accessibility_service_2)
+ private val packageName = context.packageManager.permissionControllerPackageName
+
+ companion object {
+ private const val EXPECTED_TIMEOUT_MS = 500L
+ private const val NEW_WINDOW_TIMEOUT_MILLIS: Long = 20_000
+ }
+
+ @get:Rule
+ val accessibilityServiceRule =
+ InstrumentedAccessibilityServiceTestRule(AccessibilityTestService1::class.java, false)
+
+ @get:Rule
+ val accessibilityServiceRule2 =
+ InstrumentedAccessibilityServiceTestRule(AccessibilityTestService2::class.java, false)
+
+ init {
+ Configurator.getInstance().uiAutomationFlags =
+ UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES
+ }
+
+ @Before
+ fun assumeNotAutoTvOrWear() {
+ Assume.assumeFalse(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
+ Assume.assumeFalse(
+ context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ )
+ Assume.assumeFalse(context.packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH))
+ }
+
+ @After
+ fun cleanUp() {
+ uiDevice.pressHome()
+ }
+
+ @Test
+ fun testActivityShowsSingleEnabledAccessibilityService() {
+ accessibilityServiceRule.enableService()
+ startAccessibilityActivity()
+ findTestService(true)
+ findTestService2(false)
+ }
+
+ @Test
+ fun testActivityShowsMultipleEnabledAccessibilityServices() {
+ accessibilityServiceRule.enableService()
+ accessibilityServiceRule2.enableService()
+ startAccessibilityActivity()
+ findTestService(true)
+ findTestService2(true)
+ }
+
+ @Test
+ fun testClickingSettingsGoesToIndividualSettingsWhenOneServiceEnabled() {
+ accessibilityServiceRule.enableService()
+ startAccessibilityActivity()
+ clickSettings()
+ waitForSettingsButtonToDisappear()
+ findTestService(true)
+ findTestService2(false)
+ }
+
+ @Test
+ @Ignore("b/293507233")
+ fun testClickingSettingsGoesToGeneralSettingsWhenMultipleServicesEnabled() {
+ accessibilityServiceRule.enableService()
+ accessibilityServiceRule2.enableService()
+ startAccessibilityActivity()
+ clickSettings()
+ waitForSettingsButtonToDisappear()
+ findTestService(true)
+ findTestService2(true)
+ }
+
+ @Test
+ fun testClickingIndividualGoesToIndividualSettingsWhenMultipleServicesEnabled() {
+ accessibilityServiceRule.enableService()
+ accessibilityServiceRule2.enableService()
+ startAccessibilityActivity()
+ findTestService2(true)!!.click()
+ waitForSettingsButtonToDisappear()
+ findTestService2(true)
+ findTestService(false)
+ }
+
+ private fun startAccessibilityActivity() {
+ val automan =
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES)
+ doAndWaitForWindowTransition {
+ automan.adoptShellPermissionIdentity()
+ try {
+ context.startActivity(
+ Intent(Intent.ACTION_REVIEW_ACCESSIBILITY_SERVICES)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ )
+ } catch (e: Exception) {
+ throw RuntimeException("Caught exception", e)
+ } finally {
+ automan.dropShellPermissionIdentity()
+ }
+ }
+ }
+
+ private inline fun doAndWaitForWindowTransition(crossinline block: () -> Unit) {
+ val timeoutOccurred: Boolean =
+ !uiDevice.performActionAndWait(
+ { block() },
+ Until.newWindow(),
+ NEW_WINDOW_TIMEOUT_MILLIS
+ )
+
+ if (timeoutOccurred) {
+ throw RuntimeException("Timed out waiting for window transition.")
+ }
+ }
+
+ private fun findTestService(shouldBePresent: Boolean): UiObject2? {
+ return findObjectByText(shouldBePresent, testService1String)
+ }
+
+ private fun findTestService2(shouldBePresent: Boolean): UiObject2? {
+ return findObjectByText(shouldBePresent, testService2String)
+ }
+
+ private fun clickSettings() {
+ findObjectByText(true, "Settings")?.click()
+ }
+
+ private fun waitForSettingsButtonToDisappear() {
+ SystemUtil.eventually {
+ findPCObjectByClassAndText(false,
+ "android.widget.Button",
+ "Settings"
+ )
+ }
+ }
+
+ private fun findObjectByTextWithoutRetry(
+ shouldBePresent: Boolean,
+ text: String,
+ ): UiObject2? {
+ val containsWithoutCaseSelector =
+ By.text(Pattern.compile(".*$text.*", Pattern.CASE_INSENSITIVE))
+ val view =
+ if (shouldBePresent) {
+ waitFindObjectOrNull(containsWithoutCaseSelector)
+ } else {
+ waitFindObjectOrNull(containsWithoutCaseSelector, EXPECTED_TIMEOUT_MS)
+ }
+
+ assertEquals(
+ "Expected to find view with text $text: $shouldBePresent",
+ shouldBePresent,
+ view != null
+ )
+ return view
+ }
+
+ private fun findObjectByText(expected: Boolean, text: String): UiObject2? {
+ try {
+ return findObjectByTextWithoutRetry(expected, text)
+ } catch (stale: StaleObjectException) {
+ return findObjectByTextWithoutRetry(expected, text)
+ }
+ }
+
+ private fun findPCObjectByClassAndText(
+ shouldBePresent: Boolean,
+ className: String,
+ text: String
+ ): UiObject2? {
+ val selector = By.pkg(packageName)
+ .clazz(className)
+ .text(text)
+ val view = waitFindObjectOrNull(selector)
+ assertEquals(
+ "Expected to find view with packageName '$packageName' className '$className' " +
+ "text '$text' : $shouldBePresent", shouldBePresent, view != null)
+ return view
+ }
+}
+
+/** Test Accessibility Services */
+class AccessibilityTestService1 : InstrumentedAccessibilityService()
+
+class AccessibilityTestService2 : InstrumentedAccessibilityService()
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/SafetyLabelChangesJobServiceTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/SafetyLabelChangesJobServiceTest.kt
new file mode 100644
index 000000000..690d76729
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/SafetyLabelChangesJobServiceTest.kt
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.Instrumentation
+import android.app.UiAutomation
+import android.content.Context
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_OTHER
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_STORE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.PersistableBundle
+import android.os.Process
+import android.permission.cts.CtsNotificationListenerHelperRule
+import android.permission.cts.CtsNotificationListenerServiceUtils
+import android.permission.cts.CtsNotificationListenerServiceUtils.getNotification
+import android.permission.cts.CtsNotificationListenerServiceUtils.getNotificationForPackageAndId
+import android.permission.cts.PermissionUtils
+import android.permission.cts.TestUtils
+import android.permissionui.cts.AppMetadata.createAppMetadataWithLocationSharingNoAds
+import android.permissionui.cts.AppMetadata.createAppMetadataWithNoSharing
+import android.provider.DeviceConfig
+import android.safetylabel.SafetyLabelConstants
+import android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule
+import com.android.compatibility.common.util.SystemUtil
+import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.SystemUtil.waitForBroadcasts
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+
+/** End-to-end test for SafetyLabelChangesJobService. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+@FlakyTest
+class SafetyLabelChangesJobServiceTest : BaseUsePermissionTest() {
+
+ @get:Rule
+ val safetyLabelChangeNotificationsEnabledConfig =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED,
+ true.toString()
+ )
+
+ /**
+ * This rule serves to limit the max number of safety labels that can be persisted, so that
+ * repeated tests don't overwhelm the disk storage on the device.
+ */
+ @get:Rule
+ val deviceConfigMaxSafetyLabelsPersistedPerApp =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP,
+ "2"
+ )
+
+ @get:Rule
+ val deviceConfigDataSharingUpdatesPeriod =
+ DeviceConfigStateChangerRule(
+ BasePermissionTest.context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_DATA_SHARING_UPDATE_PERIOD_MILLIS,
+ "600000"
+ )
+
+ @Before
+ fun setup() {
+ val packageManager = context.packageManager
+ Assume.assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
+ Assume.assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
+ Assume.assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH))
+
+ SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP")
+ SystemUtil.runShellCommand("wm dismiss-keyguard")
+
+ // Bypass battery saving restrictions
+ SystemUtil.runShellCommand(
+ "cmd tare set-vip " +
+ "${Process.myUserHandle().identifier} $permissionControllerPackageName true"
+ )
+ CtsNotificationListenerServiceUtils.cancelNotifications(permissionControllerPackageName)
+ resetPermissionControllerAndSimulateReboot()
+ }
+
+ @After
+ fun cancelJobsAndNotifications() {
+ cancelJob(SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID)
+ cancelJob(SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID)
+ CtsNotificationListenerServiceUtils.cancelNotifications(permissionControllerPackageName)
+ // Reset battery saving restrictions
+ SystemUtil.runShellCommand(
+ "cmd tare set-vip " +
+ "${Process.myUserHandle().identifier} $permissionControllerPackageName default"
+ )
+ }
+
+ @Test
+ fun runDetectUpdatesJob_initializesSafetyLabelsHistoryForApps() {
+ installPackageNoBroadcast(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app install is
+ // identified and recorded.
+ runDetectUpdatesJob()
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ waitForBroadcasts()
+
+ assertNotificationNotShown()
+ assertDataSharingScreenHasUpdates()
+ }
+
+ @Test
+ fun runNotificationJob_initializesSafetyLabelsHistoryForApps() {
+ installPackageNoBroadcast(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app install is
+ // identified and recorded.
+ runNotificationJob()
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ waitForBroadcasts()
+
+ assertDataSharingScreenHasUpdates()
+ }
+
+ @Test
+ fun runDetectUpdatesJob_updatesSafetyLabelHistoryForApps() {
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ waitForBroadcastReceiverFinished()
+ installPackageNoBroadcast(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app update is
+ // identified and recorded.
+ runDetectUpdatesJob()
+
+ assertNotificationNotShown()
+ assertDataSharingScreenHasUpdates()
+ }
+
+ @Test
+ fun runNotificationJob_updatesSafetyLabelHistoryForApps() {
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ waitForBroadcastReceiverFinished()
+ installPackageNoBroadcast(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app update is
+ // identified and recorded.
+ runNotificationJob()
+
+ assertDataSharingScreenHasUpdates()
+ }
+
+ @Test
+ fun runNotificationJob_whenLocationSharingUpdatesForLocationGrantedApps_showsNotification() {
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ waitForBroadcasts()
+ // TODO(b/279455955): Investigate why this is necessary and remove if possible.
+ Thread.sleep(500)
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ waitForBroadcasts()
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ runNotificationJob()
+
+ waitForNotificationShown()
+
+ val statusBarNotification =
+ getNotification(permissionControllerPackageName, SAFETY_LABEL_CHANGES_NOTIFICATION_ID)
+ val contentIntent = statusBarNotification!!.notification.contentIntent
+ contentIntent.send()
+
+ assertDataSharingScreenHasUpdates()
+ }
+
+ @Test
+ fun runNotificationJob_whenNoLocationGrantedApps_doesNotShowNotification() {
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ waitForBroadcasts()
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithLocationSharingNoAds())
+ waitForBroadcasts()
+
+ runNotificationJob()
+
+ assertNotificationNotShown()
+ }
+
+ @Test
+ fun runNotificationJob_whenNoLocationSharingUpdates_doesNotShowNotification() {
+ installPackageViaSession(APP_APK_NAME_31, createAppMetadataWithNoSharing())
+ waitForBroadcasts()
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ runNotificationJob()
+
+ assertNotificationNotShown()
+ }
+
+ @Test
+ fun runNotificationJob_packageSourceUnspecified_updatesSafetyLabelHistoryForApps() {
+ installPackageViaSession(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_UNSPECIFIED
+ )
+ waitForBroadcastReceiverFinished()
+ installPackageNoBroadcast(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_UNSPECIFIED
+ )
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app update is
+ // identified and recorded.
+ runNotificationJob()
+
+ assertDataSharingScreenHasUpdates()
+ }
+
+ @Test
+ fun runNotificationJob_packageSourceOther_doesNotShowNotification() {
+ installPackageViaSession(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_OTHER
+ )
+ waitForBroadcastReceiverFinished()
+ installPackageNoBroadcast(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_OTHER
+ )
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app update is
+ // identified and recorded.
+ runNotificationJob()
+
+ assertNotificationNotShown()
+ }
+
+ @Test
+ fun runNotificationJob_packageSourceStore_updatesSafetyLabelHistoryForApps() {
+ installPackageViaSession(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_STORE
+ )
+ waitForBroadcastReceiverFinished()
+ installPackageNoBroadcast(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_STORE
+ )
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app update is
+ // identified and recorded.
+ runNotificationJob()
+
+ assertDataSharingScreenHasUpdates()
+ }
+
+ @Test
+ fun runNotificationJob_packageSourceLocalFile_doesNotShowNotification() {
+ installPackageViaSession(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_LOCAL_FILE
+ )
+ waitForBroadcastReceiverFinished()
+ installPackageNoBroadcast(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_LOCAL_FILE
+ )
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app update is
+ // identified and recorded.
+ runNotificationJob()
+
+ assertNotificationNotShown()
+ }
+
+ @Test
+ fun runNotificationJob_packageSourceDownloadedFile_udoesNotShowNotification() {
+ installPackageViaSession(
+ APP_APK_NAME_31,
+ createAppMetadataWithNoSharing(),
+ PACKAGE_SOURCE_DOWNLOADED_FILE
+ )
+ waitForBroadcastReceiverFinished()
+ installPackageNoBroadcast(
+ APP_APK_NAME_31,
+ createAppMetadataWithLocationSharingNoAds(),
+ PACKAGE_SOURCE_DOWNLOADED_FILE
+ )
+ grantLocationPermission(APP_PACKAGE_NAME)
+
+ // Run the job to check whether the missing safety label for the above app update is
+ // identified and recorded.
+ runNotificationJob()
+
+ assertNotificationNotShown()
+ }
+
+ private fun grantLocationPermission(packageName: String) {
+ uiAutomation.grantRuntimePermission(
+ packageName,
+ android.Manifest.permission.ACCESS_FINE_LOCATION
+ )
+ }
+
+ private fun installPackageNoBroadcast(
+ apkName: String,
+ appMetadata: PersistableBundle? = null,
+ packageSource: Int? = null
+ ) {
+ // Disable the safety labels feature during install to simulate installing an app without
+ // receiving an update about the change to its safety label.
+ setDeviceConfigPrivacyProperty(SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false.toString())
+ installPackageViaSession(apkName, appMetadata, packageSource)
+ waitForBroadcastReceiverFinished()
+ setDeviceConfigPrivacyProperty(SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, true.toString())
+ }
+
+ private fun assertDataSharingScreenHasUpdates() {
+ startAppDataSharingUpdatesActivity()
+ try {
+ findView(By.descContains(DATA_SHARING_UPDATES), true)
+ findView(By.textContains(DATA_SHARING_UPDATES_SUBTITLE), true)
+ findView(By.textContains(UPDATES_IN_LAST_30_DAYS), true)
+ findView(By.textContains(APP_PACKAGE_NAME_SUBSTRING), true)
+ findView(By.textContains(DATA_SHARING_UPDATES_FOOTER_MESSAGE), true)
+ } finally {
+ pressBack()
+ }
+ }
+
+ companion object {
+ private const val TIMEOUT_TIME_MS = 60_000L
+ private const val SHORT_SLEEP_MS = 2000L
+
+ private const val SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID = 8
+ private const val SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID = 9
+ private const val SET_UP_SAFETY_LABEL_CHANGES_JOB =
+ "com.android.permissioncontroller.action.SET_UP_SAFETY_LABEL_CHANGES_JOB"
+ private const val SAFETY_LABEL_CHANGES_JOB_SERVICE_RECEIVER_CLASS =
+ "com.android.permissioncontroller.permission.service.v34" +
+ ".SafetyLabelChangesJobService\$Receiver"
+ private const val SAFETY_LABEL_CHANGES_NOTIFICATION_ID = 5
+ private const val JOB_STATUS_UNKNOWN = "unknown"
+ private const val JOB_STATUS_ACTIVE = "active"
+ private const val JOB_STATUS_WAITING = "waiting"
+
+ private val context: Context = InstrumentationRegistry.getTargetContext()
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private fun uiAutomation(): UiAutomation = instrumentation.uiAutomation
+ private val permissionControllerPackageName =
+ context.packageManager.permissionControllerPackageName
+ private val userId = Process.myUserHandle().identifier
+
+ @get:ClassRule
+ @JvmStatic
+ val ctsNotificationListenerHelper =
+ CtsNotificationListenerHelperRule(
+ InstrumentationRegistry.getInstrumentation().targetContext
+ )
+
+ private fun waitForNotificationShown() {
+ eventually {
+ val notification = getNotification(false)
+ assertThat(notification).isNotNull()
+ }
+ }
+
+ private fun assertNotificationNotShown() {
+ eventually {
+ val notification = getNotification(false)
+ assertThat(notification).isNull()
+ }
+ }
+
+ private fun getNotification(cancelNotification: Boolean) =
+ getNotificationForPackageAndId(
+ permissionControllerPackageName,
+ SAFETY_LABEL_CHANGES_NOTIFICATION_ID,
+ cancelNotification
+ )
+ ?.notification
+
+ private fun cancelJob(jobId: Int) {
+ SystemUtil.runShellCommandOrThrow(
+ "cmd jobscheduler cancel -u $userId $permissionControllerPackageName $jobId"
+ )
+ TestUtils.awaitJobUntilRequestedState(
+ permissionControllerPackageName,
+ jobId,
+ TIMEOUT_TIME_MS,
+ uiAutomation(),
+ JOB_STATUS_UNKNOWN
+ )
+ }
+
+ private fun runDetectUpdatesJob() {
+ startJob(SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID)
+ TestUtils.awaitJobUntilRequestedState(
+ permissionControllerPackageName,
+ SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID,
+ TIMEOUT_TIME_MS,
+ uiAutomation(),
+ JOB_STATUS_ACTIVE
+ )
+ TestUtils.awaitJobUntilRequestedState(
+ permissionControllerPackageName,
+ SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID,
+ TIMEOUT_TIME_MS,
+ uiAutomation(),
+ JOB_STATUS_UNKNOWN
+ )
+ }
+
+ private fun runNotificationJob() {
+ startJob(SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID)
+ TestUtils.awaitJobUntilRequestedState(
+ permissionControllerPackageName,
+ SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID,
+ TIMEOUT_TIME_MS,
+ uiAutomation(),
+ JOB_STATUS_ACTIVE
+ )
+ // TODO(b/266449833): In theory we should only have to wait for "waiting" here, but
+ // sometimes jobscheduler returns "unknown".
+ TestUtils.awaitJobUntilRequestedState(
+ permissionControllerPackageName,
+ SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID,
+ TIMEOUT_TIME_MS,
+ uiAutomation(),
+ JOB_STATUS_WAITING,
+ JOB_STATUS_UNKNOWN
+ )
+ }
+
+ private fun startJob(jobId: Int) {
+ val runJobCmd =
+ "cmd jobscheduler run -u $userId -f " + "$permissionControllerPackageName $jobId"
+ try {
+ SystemUtil.runShellCommandOrThrow(runJobCmd)
+ } catch (e: Throwable) {
+ throw RuntimeException(e)
+ }
+ }
+
+ private fun resetPermissionControllerAndSimulateReboot() {
+ PermissionUtils.resetPermissionControllerJob(
+ uiAutomation(),
+ permissionControllerPackageName,
+ SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID,
+ TIMEOUT_TIME_MS,
+ SET_UP_SAFETY_LABEL_CHANGES_JOB,
+ SAFETY_LABEL_CHANGES_JOB_SERVICE_RECEIVER_CLASS
+ )
+ }
+
+ private fun waitForBroadcastReceiverFinished() {
+ waitForBroadcasts()
+ // Add a short sleep to ensure that the SafetyLabelChangedBroadcastReceiver finishes its
+ // work based according to the current feature flag value before changing the flag
+ // value.
+ // While `waitForBroadcasts()` waits for broadcasts to be dispatched, it will not wait
+ // for
+ // the receivers' `onReceive` to finish.
+ Thread.sleep(SHORT_SLEEP_MS)
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/SafetyProtectionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/SafetyProtectionTest.kt
new file mode 100644
index 000000000..541ea9d16
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/SafetyProtectionTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.permissionui.cts
+
+import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.content.res.Resources
+import android.provider.DeviceConfig
+import androidx.test.filters.FlakyTest
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule
+import com.android.modules.utils.build.SdkLevel
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+/** Tests for Safety Protection related features. This feature should only be enabled on T+. */
+@FlakyTest
+class SafetyProtectionTest : BaseUsePermissionTest() {
+ @get:Rule
+ val safetyProtectionEnabled =
+ DeviceConfigStateChangerRule(
+ context,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SAFETY_PROTECTION_ENABLED_FLAG,
+ true.toString()
+ )
+
+ @Before
+ fun setup() {
+ assumeFalse(isAutomotive)
+ assumeFalse(isTv)
+ assumeFalse(isWatch)
+ }
+
+ @Ignore("b/276944839")
+ @Test
+ fun testSafetyProtectionSectionView_safetyProtection_belowT() {
+ assumeFalse("Safety Protection should only be enabled on T+", SdkLevel.isAtLeastT())
+ installPackageViaSession(APP_APK_NAME_31)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ findView(By.res(SAFETY_PROTECTION_DISPLAY_TEXT), false)
+ }
+ }
+
+ @Test
+ fun testSafetyProtectionSectionView_safetyProtectionDisabled_aboveT() {
+ assumeTrue("Safety Protection should only be enabled on T+", SdkLevel.isAtLeastT())
+ setDeviceConfigPrivacyProperty(SAFETY_PROTECTION_ENABLED_FLAG, false.toString())
+ installPackageViaSession(APP_APK_NAME_31)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ findView(By.res(SAFETY_PROTECTION_DISPLAY_TEXT), false)
+ }
+ }
+
+ @Test
+ fun testSafetyProtectionSectionView_safetyProtectionEnabled_aboveT() {
+ assumeTrue("Safety Protection should only be enabled on T+", SdkLevel.isAtLeastT())
+ assumeTrue(safetyProtectionResourcesExist)
+ installPackageViaSession(APP_APK_NAME_31)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ findView(By.res(SAFETY_PROTECTION_DISPLAY_TEXT), true)
+ }
+ }
+
+ @Test
+ fun testSafetyProtectionSectionView_safetyProtectionResourcesNotExist_aboveT() {
+ assumeTrue("Safety Protection should only be enabled on T+", SdkLevel.isAtLeastT())
+ assumeFalse(safetyProtectionResourcesExist)
+ installPackageViaSession(APP_APK_NAME_31)
+ assertAppHasPermission(ACCESS_COARSE_LOCATION, false)
+ assertAppHasPermission(ACCESS_FINE_LOCATION, false)
+ requestAppPermissionsForNoResult(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) {
+ findView(By.res(SAFETY_PROTECTION_DISPLAY_TEXT), false)
+ }
+ }
+
+ companion object {
+ private const val SAFETY_PROTECTION_ENABLED_FLAG = "safety_protection_enabled"
+ private const val SAFETY_PROTECTION_DISPLAY_TEXT =
+ "com.android.permissioncontroller:id/safety_protection_display_text"
+ private val safetyProtectionResourcesExist =
+ try {
+ context
+ .getResources()
+ .getBoolean(
+ Resources.getSystem()
+ .getIdentifier("config_safetyProtectionEnabled", "bool", "android")
+ ) &&
+ context.getDrawable(android.R.drawable.ic_safety_protection) != null &&
+ !context
+ .getString(android.R.string.safety_protection_display_text)
+ .isNullOrEmpty()
+ } catch (e: Resources.NotFoundException) {
+ false
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/SensorBlockedBannerTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/SensorBlockedBannerTest.kt
new file mode 100644
index 000000000..f8c7d4f51
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/SensorBlockedBannerTest.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.Manifest.permission_group.CAMERA as CAMERA_PERMISSION_GROUP
+import android.Manifest.permission_group.LOCATION as LOCATION_PERMISSION_GROUP
+import android.Manifest.permission_group.MICROPHONE as MICROPHONE_PERMISSION_GROUP
+import android.content.Intent
+import android.hardware.SensorPrivacyManager
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
+import android.location.LocationManager
+import android.os.Build
+import android.safetycenter.SafetyCenterManager
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import java.util.regex.Pattern
+import org.junit.Assert.assertTrue
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+
+/** Banner card display tests on sensors being blocked */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+@FlakyTest
+class SensorBlockedBannerTest : BaseUsePermissionTest() {
+ companion object {
+ const val LOCATION = -1
+ const val DELAY_MILLIS = 3000L
+ private const val CHANGE_BUTTON = "com.android.permissioncontroller:id/button_id"
+ private const val CAMERA_TOGGLE_LABEL = "Camera access"
+ }
+
+ private val sensorPrivacyManager = context.getSystemService(SensorPrivacyManager::class.java)!!
+ private val locationManager = context.getSystemService(LocationManager::class.java)!!
+ private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
+
+ private val sensorToPermissionGroup =
+ mapOf(
+ CAMERA to CAMERA_PERMISSION_GROUP,
+ MICROPHONE to MICROPHONE_PERMISSION_GROUP,
+ LOCATION to LOCATION_PERMISSION_GROUP
+ )
+
+ private val permToTitle =
+ mapOf(
+ CAMERA to "blocked_camera_title",
+ MICROPHONE to "blocked_microphone_title",
+ LOCATION to "blocked_location_title"
+ )
+
+ @Before
+ fun setup() {
+ Assume.assumeFalse(isTv)
+ Assume.assumeFalse(isWatch)
+ // TODO(b/203784852) Auto will eventually support the blocked sensor banner, but there won't
+ // be support in T or below
+ Assume.assumeFalse(isAutomotive)
+ installPackage(APP_APK_PATH_31)
+ }
+
+ private fun navigateAndTest(sensor: Int) {
+ val permissionGroup = sensorToPermissionGroup.getOrDefault(sensor, "Break")
+ val intent =
+ Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
+ .putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroup)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ runWithShellPermissionIdentity { context.startActivity(intent) }
+ val bannerTitle = permToTitle.getOrDefault(sensor, "Break")
+ waitFindObject(By.text(getPermissionControllerString(bannerTitle)))
+ }
+
+ private fun runSensorTest(sensor: Int) {
+ var blocked = false
+ try {
+ blocked = isSensorPrivacyEnabled(sensor)
+ if (!blocked) {
+ setSensor(sensor, true)
+ }
+ navigateAndTest(sensor)
+ } finally {
+ if (!blocked) {
+ setSensor(sensor, false)
+ }
+ }
+ }
+
+ @Test
+ fun testCameraCardDisplayed() {
+ Assume.assumeTrue(sensorPrivacyManager.supportsSensorToggle(CAMERA))
+ runSensorTest(CAMERA)
+ }
+
+ @Test
+ fun testMicCardDisplayed() {
+ Assume.assumeTrue(sensorPrivacyManager.supportsSensorToggle(MICROPHONE))
+ runSensorTest(MICROPHONE)
+ }
+
+ @Test
+ fun testLocationCardDisplayed() {
+ runSensorTest(LOCATION)
+ }
+
+ @Test
+ fun testCardClickOpenPrivacyControls() {
+ Assume.assumeTrue(sensorPrivacyManager.supportsSensorToggle(CAMERA))
+ var isSafetyCenterEnabled = false
+ runWithShellPermissionIdentity {
+ isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabled
+ }
+ Assume.assumeTrue(isSafetyCenterEnabled)
+ // Disable global camera toggle
+ val blocked = isSensorPrivacyEnabled(CAMERA)
+ if (!blocked) {
+ setSensor(CAMERA, true)
+ }
+ // verify sensor card is shown for blocked camera
+ navigateAndTest(CAMERA)
+ click(By.res(CHANGE_BUTTON))
+ // Enable global camera toggle and verify
+ waitFindObject(By.text(CAMERA_TOGGLE_LABEL)).click()
+ assertTrue(!isSensorPrivacyEnabled(CAMERA))
+ }
+
+ private fun setSensor(sensor: Int, enable: Boolean) {
+ if (sensor == LOCATION) {
+ runWithShellPermissionIdentity {
+ locationManager.setLocationEnabledForUser(
+ !enable,
+ android.os.Process.myUserHandle()
+ )
+ if (enable) {
+ try {
+ val closePattern = Pattern.compile("close", Pattern.CASE_INSENSITIVE)
+ waitFindObjectOrNull(By.text(closePattern), DELAY_MILLIS)?.click()
+ } catch (e: Exception) {
+ // Do nothing, warning didn't show up so test can proceed
+ }
+ }
+ }
+ } else {
+ runWithShellPermissionIdentity {
+ sensorPrivacyManager.setSensorPrivacy(
+ SensorPrivacyManager.Sources.OTHER,
+ sensor,
+ enable
+ )
+ }
+ }
+ }
+
+ private fun isSensorPrivacyEnabled(sensor: Int): Boolean {
+ return if (sensor == LOCATION) {
+ callWithShellPermissionIdentity { !locationManager.isLocationEnabled() }
+ } else {
+ callWithShellPermissionIdentity { sensorPrivacyManager.isSensorPrivacyEnabled(sensor) }
+ }
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/StartForFutureActivity.kt b/tests/cts/permissionui/src/android/permissionui/cts/StartForFutureActivity.kt
new file mode 100644
index 000000000..8caa4e6bf
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/StartForFutureActivity.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.Activity
+import android.app.Instrumentation
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import java.util.concurrent.CompletableFuture
+
+class StartForFutureActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ Log.w(TAG, "Activity was recreated. (Perhaps due to a configuration change?)")
+ }
+ }
+
+ fun startActivityForFuture(
+ intent: Intent,
+ future: CompletableFuture<Instrumentation.ActivityResult>
+ ) {
+ if (StartForFutureActivity.future != null) {
+ throw RuntimeException(
+ "StartForFutureActivity only supports launching one " +
+ "concurrent activity, but more than one was attempted."
+ )
+ }
+
+ startActivityForResult(intent, 1)
+ StartForFutureActivity.future = future
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ future!!.complete(Instrumentation.ActivityResult(resultCode, data))
+ future = null
+ finish()
+ }
+
+ companion object {
+ private var future: CompletableFuture<Instrumentation.ActivityResult>? = null
+ private val TAG = StartForFutureActivity::class.simpleName
+ }
+}
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/TestInstallerActivity.kt b/tests/cts/permissionui/src/android/permissionui/cts/TestInstallerActivity.kt
new file mode 100644
index 000000000..bae332a3c
--- /dev/null
+++ b/tests/cts/permissionui/src/android/permissionui/cts/TestInstallerActivity.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permissionui.cts
+
+import android.app.Activity
+
+class TestInstallerActivity : Activity()
diff --git a/tests/cts/role/Android.bp b/tests/cts/role/Android.bp
new file mode 100644
index 000000000..a2e3255c3
--- /dev/null
+++ b/tests/cts/role/Android.bp
@@ -0,0 +1,50 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsRoleTestCases",
+ defaults: ["mts-target-sdk-version-current"],
+ sdk_version: "test_current",
+ min_sdk_version: "30",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "truth",
+ "platform-test-annotations",
+ ],
+
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "mcts-permission",
+ ],
+
+ data: [
+ ":CtsRoleTestApp",
+ ":CtsRoleTestApp28",
+ ":CtsRoleTestApp33WithoutInCallService",
+ ],
+}
diff --git a/tests/cts/role/AndroidManifest.xml b/tests/cts/role/AndroidManifest.xml
new file mode 100644
index 000000000..a8c8c8e3d
--- /dev/null
+++ b/tests/cts/role/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.app.role.cts">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
+ <application>
+
+ <uses-library android:name="android.test.runner" />
+
+ <activity
+ android:name=".WaitForResultActivity"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"/>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.app.role.cts"
+ android:label="CTS tests of android.app.role">
+ </instrumentation>
+</manifest>
diff --git a/tests/cts/role/AndroidTest.xml b/tests/cts/role/AndroidTest.xml
new file mode 100644
index 000000000..527ac3d32
--- /dev/null
+++ b/tests/cts/role/AndroidTest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Config for CTS role test cases">
+
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="permissions" />
+ <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="run_on_sdk_sandbox" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsRoleTestCases.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/cts-role" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/cts-role"/>
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="CtsRoleTestApp.apk->/data/local/tmp/cts-role/CtsRoleTestApp.apk" />
+ <option name="push" value="CtsRoleTestApp28.apk->/data/local/tmp/cts-role/CtsRoleTestApp28.apk" />
+ <option name="push" value="CtsRoleTestApp33WithoutInCallService.apk->/data/local/tmp/cts-role/CtsRoleTestApp33WithoutInCallService.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.app.role.cts" />
+ <option name="runtime-hint" value="5m" />
+ </test>
+</configuration>
diff --git a/tests/cts/role/CtsRoleTestApp/Android.bp b/tests/cts/role/CtsRoleTestApp/Android.bp
new file mode 100644
index 000000000..1270e490b
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsRoleTestApp",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "30",
+ srcs: [
+ "src/**/*.java"
+ ],
+}
diff --git a/tests/cts/role/CtsRoleTestApp/AndroidManifest.xml b/tests/cts/role/CtsRoleTestApp/AndroidManifest.xml
new file mode 100644
index 000000000..b2dfca961
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp/AndroidManifest.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.app.role.cts.app">
+
+ <uses-permission android:name="android.permission.SEND_SMS" />
+
+ <application android:label="CtsRoleTestApp">
+
+ <activity
+ android:name=".RequestRoleActivity"
+ android:exported="true" />
+
+ <activity
+ android:name=".IsRoleHeldActivity"
+ android:exported="true" />
+
+ <activity
+ android:name=".ChangeDefaultDialerActivity"
+ android:exported="true" />
+
+ <activity
+ android:name=".ChangeDefaultSmsActivity"
+ android:exported="true" />
+
+ <!-- Dialer -->
+ <activity
+ android:name=".DialerDialActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="tel" />
+ </intent-filter>
+ </activity>
+ <service
+ android:name=".DialerInCallService"
+ android:permission="android.permission.BIND_INCALL_SERVICE"
+ android:exported="true">
+ <meta-data
+ android:name="android.telecom.IN_CALL_SERVICE_UI"
+ android:value="true"/>
+ <meta-data
+ android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
+ android:value="false"/>
+ <intent-filter>
+ <action android:name="android.telecom.InCallService" />
+ </intent-filter>
+ </service>
+ <!-- Sms -->
+ <activity
+ android:name=".SmsSendToActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.SENDTO" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="smsto" />
+ </intent-filter>
+ </activity>
+ <service
+ android:name=".SmsRespondViaMessageService"
+ android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="smsto" />
+ </intent-filter>
+ </service>
+ <receiver
+ android:name=".SmsDelieverReceiver"
+ android:permission="android.permission.BROADCAST_SMS"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.SMS_DELIVER" />
+ </intent-filter>
+ </receiver>
+ <receiver
+ android:name=".SmsWapPushDelieverReceiver"
+ android:permission="android.permission.BROADCAST_WAP_PUSH"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
+ <data android:mimeType="application/vnd.wap.mms-message" />
+ </intent-filter>
+ </receiver>
+
+ <!-- Browser -->
+ <activity
+ android:name=".BrowserActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http" />
+ </intent-filter>
+ </activity>
+
+ <!-- Assistant -->
+ <activity
+ android:name=".AssistantActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.ASSIST" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultDialerActivity.java b/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultDialerActivity.java
new file mode 100644
index 000000000..89cafa001
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultDialerActivity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts.app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecom.TelecomManager;
+
+/**
+ * An activity that tries to change the default dialer app.
+ */
+public class ChangeDefaultDialerActivity extends Activity {
+
+ private static final int REQUEST_CODE_CHANGE_DEFAULT_DIALER = 1;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState == null) {
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
+ .putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName);
+ startActivityForResult(intent, REQUEST_CODE_CHANGE_DEFAULT_DIALER);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CODE_CHANGE_DEFAULT_DIALER) {
+ setResult(resultCode, data);
+ finish();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+}
diff --git a/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultSmsActivity.java b/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultSmsActivity.java
new file mode 100644
index 000000000..00559bf44
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultSmsActivity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts.app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Telephony;
+
+/**
+ * An activity that tries to change the default SMS app.
+ */
+public class ChangeDefaultSmsActivity extends Activity {
+
+ private static final int REQUEST_CODE_CHANGE_DEFAULT_SMS = 1;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState == null) {
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT)
+ .putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, packageName);
+ startActivityForResult(intent, REQUEST_CODE_CHANGE_DEFAULT_SMS);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CODE_CHANGE_DEFAULT_SMS) {
+ setResult(resultCode, data);
+ finish();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+}
diff --git a/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/IsRoleHeldActivity.java b/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/IsRoleHeldActivity.java
new file mode 100644
index 000000000..8e97f9f24
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/IsRoleHeldActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts.app;
+
+import android.app.Activity;
+import android.app.role.RoleManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+/**
+ * An activity that checks whether a role is held.
+ */
+public class IsRoleHeldActivity extends Activity {
+
+ private static final String EXTRA_IS_ROLE_HELD = "android.app.role.cts.app.extra.IS_ROLE_HELD";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String roleName = getIntent().getStringExtra(Intent.EXTRA_ROLE_NAME);
+ if (TextUtils.isEmpty(roleName)) {
+ throw new IllegalArgumentException("Role name in extras cannot be null or empty");
+ }
+
+ RoleManager roleManager = getSystemService(RoleManager.class);
+ setResult(RESULT_OK, new Intent()
+ .putExtra(EXTRA_IS_ROLE_HELD, roleManager.isRoleHeld(roleName)));
+ finish();
+ }
+}
diff --git a/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/RequestRoleActivity.java b/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/RequestRoleActivity.java
new file mode 100644
index 000000000..b2d69e044
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp/src/android/app/role/cts/app/RequestRoleActivity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts.app;
+
+import android.app.Activity;
+import android.app.role.RoleManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+/**
+ * An activity that requests a role.
+ */
+public class RequestRoleActivity extends Activity {
+
+ private static final int REQUEST_CODE_REQUEST_ROLE = 1;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState == null) {
+ String roleName = getIntent().getStringExtra(Intent.EXTRA_ROLE_NAME);
+ RoleManager roleManager = getSystemService(RoleManager.class);
+ Intent intent = roleManager.createRequestRoleIntent(roleName);
+ startActivityForResult(intent, REQUEST_CODE_REQUEST_ROLE);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CODE_REQUEST_ROLE) {
+ setResult(resultCode, data);
+ finish();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+}
diff --git a/tests/cts/role/CtsRoleTestApp28/Android.bp b/tests/cts/role/CtsRoleTestApp28/Android.bp
new file mode 100644
index 000000000..dc8239edb
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp28/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsRoleTestApp28",
+ min_sdk_version: "28",
+ target_sdk_version: "28",
+
+ srcs: [
+ "src/**/*.java"
+ ],
+}
diff --git a/tests/cts/role/CtsRoleTestApp28/AndroidManifest.xml b/tests/cts/role/CtsRoleTestApp28/AndroidManifest.xml
new file mode 100644
index 000000000..8113b2676
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp28/AndroidManifest.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.app.role.cts.app28">
+
+ <uses-permission android:name="android.permission.SEND_SMS"/>
+
+ <application android:label="CtsRoleTestApp28">
+
+ <activity android:name=".ChangeDefaultDialerActivity"
+ android:exported="true"/>
+
+ <activity android:name=".ChangeDefaultSmsActivity"
+ android:exported="true"/>
+
+ <!-- Dialer -->
+ <activity android:name=".DialerDialActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="tel"/>
+ </intent-filter>
+ </activity>
+
+ <!-- Sms -->
+ <activity android:name=".SmsSendToActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.SENDTO"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="smsto"/>
+ </intent-filter>
+ </activity>
+ <service android:name=".SmsRespondViaMessageService"
+ android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.RESPOND_VIA_MESSAGE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="smsto"/>
+ </intent-filter>
+ </service>
+ <receiver android:name=".SmsDelieverReceiver"
+ android:permission="android.permission.BROADCAST_SMS"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.SMS_DELIVER"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:name=".SmsWapPushDelieverReceiver"
+ android:permission="android.permission.BROADCAST_WAP_PUSH"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER"/>
+ <data android:mimeType="application/vnd.wap.mms-message"/>
+ </intent-filter>
+ </receiver>
+ </application>
+</manifest>
diff --git a/tests/cts/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultDialerActivity.java b/tests/cts/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultDialerActivity.java
new file mode 100644
index 000000000..5d1c47cfc
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultDialerActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts.app28;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecom.TelecomManager;
+
+/**
+ * An activity that tries to change the default dialer app.
+ */
+public class ChangeDefaultDialerActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState == null) {
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
+ .putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName);
+ startActivity(intent);
+ }
+ }
+}
diff --git a/tests/cts/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultSmsActivity.java b/tests/cts/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultSmsActivity.java
new file mode 100644
index 000000000..37819bbec
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultSmsActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts.app28;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Telephony;
+import android.telecom.TelecomManager;
+
+/**
+ * An activity that tries to change the default SMS app.
+ */
+public class ChangeDefaultSmsActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState == null) {
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT)
+ .putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, packageName);
+ startActivity(intent);
+ }
+ }
+}
diff --git a/tests/cts/role/CtsRoleTestApp33WithoutInCallService/Android.bp b/tests/cts/role/CtsRoleTestApp33WithoutInCallService/Android.bp
new file mode 100644
index 000000000..7cce565af
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp33WithoutInCallService/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsRoleTestApp33WithoutInCallService",
+ min_sdk_version: "30",
+ target_sdk_version: "33",
+}
diff --git a/tests/cts/role/CtsRoleTestApp33WithoutInCallService/AndroidManifest.xml b/tests/cts/role/CtsRoleTestApp33WithoutInCallService/AndroidManifest.xml
new file mode 100644
index 000000000..a6504adae
--- /dev/null
+++ b/tests/cts/role/CtsRoleTestApp33WithoutInCallService/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.app.role.cts.app33WithoutInCallService">
+ <application android:label="CtsRoleTestApp33WithoutInCallService">
+ <!-- Dialer -->
+ <activity
+ android:name=".DialerDialActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="tel" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/cts/role/OWNERS b/tests/cts/role/OWNERS
new file mode 100644
index 000000000..fb6099cf7
--- /dev/null
+++ b/tests/cts/role/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 137825
+
+include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/tests/cts/role/TEST_MAPPING b/tests/cts/role/TEST_MAPPING
new file mode 100644
index 000000000..01d04bea0
--- /dev/null
+++ b/tests/cts/role/TEST_MAPPING
@@ -0,0 +1,48 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsRoleTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "CtsRoleTestCases[com.google.android.permission.apex]",
+ "options": [
+ // TODO(b/238677748): These two tests currently fails on R base image
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#openDefaultAppListThenIsNotDefaultAppInList"
+ },
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsRoleTestCases"
+ }
+ ],
+ "mainline-postsubmit": [
+ {
+ "name": "CtsRoleTestCases[com.google.android.permission.apex]",
+ "options": [
+ // TODO(b/238677748): These two tests currently fails on R base image
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#openDefaultAppListThenIsNotDefaultAppInList"
+ },
+ {
+ "exclude-filter": "android.app.role.cts.RoleManagerTest#removeSmsRoleHolderThenPermissionIsRevoked"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/cts/role/src/android/app/role/cts/RoleControllerManagerTest.kt b/tests/cts/role/src/android/app/role/cts/RoleControllerManagerTest.kt
new file mode 100644
index 000000000..0fd7c0152
--- /dev/null
+++ b/tests/cts/role/src/android/app/role/cts/RoleControllerManagerTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts
+
+import android.app.Instrumentation
+import android.app.role.RoleManager
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Process
+import android.provider.Settings
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.SdkSuppress
+import androidx.test.runner.AndroidJUnit4
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.ThrowingSupplier
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+import java.util.function.Consumer
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests RoleControllerManager APIs exposed on [RoleManager]. */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+class RoleControllerManagerTest {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context: Context = instrumentation.context
+ private val packageManager: PackageManager = context.packageManager
+ private val roleManager: RoleManager = context.getSystemService(RoleManager::class.java)!!
+
+ @Before
+ fun installApp() {
+ installPackage(APP_APK_PATH)
+ }
+
+ @After
+ fun uninstallApp() {
+ uninstallPackage(APP_PACKAGE_NAME)
+ }
+
+ @Test
+ fun appIsVisibleForRole() {
+ assumeRoleIsVisible()
+ assertAppIsVisibleForRole(APP_PACKAGE_NAME, ROLE_NAME, true)
+ }
+
+ @Test
+ fun settingsIsNotVisibleForHomeRole() {
+ // Settings should never show as a possible home app even if qualified.
+ val settingsPackageName =
+ packageManager
+ .resolveActivity(
+ Intent(Settings.ACTION_SETTINGS),
+ PackageManager.MATCH_DEFAULT_ONLY or
+ PackageManager.MATCH_DIRECT_BOOT_AWARE or
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ )!!
+ .activityInfo
+ .packageName
+ assertAppIsVisibleForRole(settingsPackageName, RoleManager.ROLE_HOME, false)
+ }
+
+ @Test
+ fun appIsNotVisibleForInvalidRole() {
+ assertAppIsVisibleForRole(APP_PACKAGE_NAME, "invalid", false)
+ }
+
+ @Test
+ fun invalidAppIsNotVisibleForRole() {
+ assertAppIsVisibleForRole("invalid", ROLE_NAME, false)
+ }
+
+ private fun assertAppIsVisibleForRole(
+ packageName: String,
+ roleName: String,
+ expectedIsVisible: Boolean
+ ) {
+ runWithShellPermissionIdentity {
+ val future = CompletableFuture<Boolean>()
+ roleManager.isApplicationVisibleForRole(
+ roleName,
+ packageName,
+ context.mainExecutor,
+ Consumer { future.complete(it) }
+ )
+ val isVisible = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ assertThat(isVisible).isEqualTo(expectedIsVisible)
+ }
+ }
+
+ private fun assumeRoleIsVisible() {
+ assumeTrue(isRoleVisible(ROLE_NAME))
+ }
+
+ @Test
+ fun systemGalleryRoleIsNotVisible() {
+ // The system gallery role should always be hidden.
+ assertThat(isRoleVisible(SYSTEM_GALLERY_ROLE_NAME)).isEqualTo(false)
+ }
+
+ @Test
+ fun invalidRoleIsNotVisible() {
+ assertThat(isRoleVisible("invalid")).isEqualTo(false)
+ }
+
+ private fun isRoleVisible(roleName: String): Boolean =
+ runWithShellPermissionIdentity(
+ ThrowingSupplier {
+ val future = CompletableFuture<Boolean>()
+ roleManager.isRoleVisible(
+ roleName,
+ context.mainExecutor,
+ Consumer { future.complete(it) }
+ )
+ future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ }
+ )
+
+ private fun installPackage(apkPath: String) {
+ assertEquals(
+ "Success",
+ runShellCommandOrThrow(
+ "pm install -r --user ${Process.myUserHandle().identifier} $apkPath"
+ )
+ .trim()
+ )
+ }
+
+ private fun uninstallPackage(packageName: String) {
+ assertEquals(
+ "Success",
+ runShellCommand("pm uninstall --user ${Process.myUserHandle().identifier} $packageName")
+ .trim()
+ )
+ }
+
+ companion object {
+ private const val ROLE_NAME = RoleManager.ROLE_BROWSER
+ private const val APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk"
+ private const val APP_PACKAGE_NAME = "android.app.role.cts.app"
+ private const val SYSTEM_GALLERY_ROLE_NAME = "android.app.role.SYSTEM_GALLERY"
+ private const val TIMEOUT_MILLIS = 15 * 1000L
+ }
+}
diff --git a/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java
new file mode 100644
index 000000000..c4fa9be93
--- /dev/null
+++ b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java
@@ -0,0 +1,1239 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts;
+
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject;
+import static com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Telephony;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.UiObjectNotFoundException;
+
+import com.android.compatibility.common.util.DisableAnimationRule;
+import com.android.compatibility.common.util.FreezeRotationRule;
+import com.android.compatibility.common.util.TestUtils;
+import com.android.compatibility.common.util.ThrowingRunnable;
+import com.android.compatibility.common.util.UiAutomatorUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+
+/**
+ * Tests {@link RoleManager}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RoleManagerTest {
+
+ private static final long TIMEOUT_MILLIS = 15 * 1000;
+
+ private static final long UNEXPECTED_TIMEOUT_MILLIS = 1000;
+
+ private static final String ROLE_NAME = RoleManager.ROLE_BROWSER;
+ private static final String ROLE_SHORT_LABEL = "Browser app";
+
+ private static final String APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk";
+ private static final String APP_PACKAGE_NAME = "android.app.role.cts.app";
+ private static final String APP_LABEL = "CtsRoleTestApp";
+ private static final String APP_IS_ROLE_HELD_ACTIVITY_NAME = APP_PACKAGE_NAME
+ + ".IsRoleHeldActivity";
+ private static final String APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD = APP_PACKAGE_NAME
+ + ".extra.IS_ROLE_HELD";
+ private static final String APP_REQUEST_ROLE_ACTIVITY_NAME = APP_PACKAGE_NAME
+ + ".RequestRoleActivity";
+ private static final String APP_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME = APP_PACKAGE_NAME
+ + ".ChangeDefaultDialerActivity";
+ private static final String APP_CHANGE_DEFAULT_SMS_ACTIVITY_NAME = APP_PACKAGE_NAME
+ + ".ChangeDefaultSmsActivity";
+
+ private static final String APP_28_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp28.apk";
+ private static final String APP_28_PACKAGE_NAME = "android.app.role.cts.app28";
+ private static final String APP_28_LABEL = "CtsRoleTestApp28";
+ private static final String APP_28_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME = APP_28_PACKAGE_NAME
+ + ".ChangeDefaultDialerActivity";
+ private static final String APP_28_CHANGE_DEFAULT_SMS_ACTIVITY_NAME = APP_28_PACKAGE_NAME
+ + ".ChangeDefaultSmsActivity";
+
+ private static final String APP_33_WITHOUT_INCALLSERVICE_APK_PATH =
+ "/data/local/tmp/cts-role/CtsRoleTestApp33WithoutInCallService.apk";
+ private static final String APP_33_WITHOUT_INCALLSERVICE_PACKAGE_NAME =
+ "android.app.role.cts.app33WithoutInCallService";
+
+ private static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
+ "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
+
+ private static final Instrumentation sInstrumentation =
+ InstrumentationRegistry.getInstrumentation();
+ private static final Context sContext = InstrumentationRegistry.getTargetContext();
+ private static final PackageManager sPackageManager = sContext.getPackageManager();
+ private static final RoleManager sRoleManager = sContext.getSystemService(RoleManager.class);
+ private static final boolean sIsWatch = sPackageManager.hasSystemFeature(
+ PackageManager.FEATURE_WATCH);
+
+ @Rule
+ public DisableAnimationRule mDisableAnimationRule = new DisableAnimationRule();
+
+ @Rule
+ public FreezeRotationRule mFreezeRotationRule = new FreezeRotationRule();
+
+ @Rule
+ public ActivityTestRule<WaitForResultActivity> mActivityRule =
+ new ActivityTestRule<>(WaitForResultActivity.class);
+
+ private String mRoleHolder;
+
+ @Before
+ public void saveRoleHolder() throws Exception {
+ List<String> roleHolders = getRoleHolders(ROLE_NAME);
+ mRoleHolder = !roleHolders.isEmpty() ? roleHolders.get(0) : null;
+
+ if (Objects.equals(mRoleHolder, APP_PACKAGE_NAME)) {
+ removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+ mRoleHolder = null;
+ }
+ }
+
+ @After
+ public void restoreRoleHolder() throws Exception {
+ removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+
+ if (mRoleHolder != null) {
+ addRoleHolder(ROLE_NAME, mRoleHolder);
+ }
+
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+ }
+
+ @Before
+ public void installApp() throws Exception {
+ installPackage(APP_APK_PATH);
+ installPackage(APP_28_APK_PATH);
+ installPackage(APP_33_WITHOUT_INCALLSERVICE_APK_PATH);
+ }
+
+ @After
+ public void uninstallApp() throws Exception {
+ uninstallPackage(APP_PACKAGE_NAME);
+ uninstallPackage(APP_28_PACKAGE_NAME);
+ uninstallPackage(APP_33_WITHOUT_INCALLSERVICE_PACKAGE_NAME);
+ }
+
+ @Before
+ public void wakeUpScreen() throws IOException {
+ runShellCommand(sInstrumentation, "input keyevent KEYCODE_WAKEUP");
+ }
+
+ @Before
+ public void closeNotificationShade() {
+ sContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ }
+
+ @Test
+ public void requestRoleIntentHasPermissionControllerPackage() throws Exception {
+ Intent intent = sRoleManager.createRequestRoleIntent(ROLE_NAME);
+
+ assertThat(intent.getPackage()).isEqualTo(
+ sPackageManager.getPermissionControllerPackageName());
+ }
+
+ @Test
+ public void requestRoleIntentHasExtraRoleName() throws Exception {
+ Intent intent = sRoleManager.createRequestRoleIntent(ROLE_NAME);
+
+ assertThat(intent.getStringExtra(Intent.EXTRA_ROLE_NAME)).isEqualTo(ROLE_NAME);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void requestRoleAndDenyThenIsNotRoleHolder() throws Exception {
+ requestRole(ROLE_NAME);
+ respondToRoleRequest(false);
+
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void requestRoleAndAllowThenIsRoleHolder() throws Exception {
+ requestRole(ROLE_NAME);
+ respondToRoleRequest(true);
+
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void requestRoleFirstTimeNoDontAskAgain() throws Exception {
+ requestRole(ROLE_NAME);
+ UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false);
+
+ assertThat(dontAskAgainCheck).isNull();
+
+ respondToRoleRequest(false);
+ }
+
+ @Test
+ @FlakyTest
+ public void requestRoleAndDenyThenHasDontAskAgain() throws Exception {
+ requestRole(ROLE_NAME);
+ respondToRoleRequest(false);
+
+ requestRole(ROLE_NAME);
+ UiObject2 dontAskAgainCheck = findDontAskAgainCheck();
+
+ assertThat(dontAskAgainCheck).isNotNull();
+
+ respondToRoleRequest(false);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void requestRoleAndDenyWithDontAskAgainReturnsCanceled() throws Exception {
+ requestRole(ROLE_NAME);
+ respondToRoleRequest(false);
+
+ requestRole(ROLE_NAME);
+ findDontAskAgainCheck().click();
+ Pair<Integer, Intent> result = clickButtonAndWaitForResult(true);
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ @FlakyTest
+ public void requestRoleAndDenyWithDontAskAgainThenDeniedAutomatically() throws Exception {
+ requestRole(ROLE_NAME);
+ respondToRoleRequest(false);
+
+ requestRole(ROLE_NAME);
+ findDontAskAgainCheck().click();
+ clickButtonAndWaitForResult(true);
+
+ requestRole(ROLE_NAME);
+ Pair<Integer, Intent> result = waitForResult();
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ @FlakyTest
+ public void requestRoleAndDenyWithDontAskAgainAndClearDataThenShowsUiWithoutDontAskAgain()
+ throws Exception {
+ requestRole(ROLE_NAME);
+ respondToRoleRequest(false);
+
+ requestRole(ROLE_NAME);
+ findDontAskAgainCheck().click();
+ clickButtonAndWaitForResult(true);
+ // Wait for the RequestRoleActivity inside the test app to be removed from our task so that
+ // when the test app is force stopped, our task isn't force finished and our
+ // WaitForResultActivity can survive.
+ Thread.sleep(5000);
+
+ clearPackageData(APP_PACKAGE_NAME);
+ // Wait for the don't ask again to be forgotten.
+ Thread.sleep(10000);
+
+ TestUtils.waitUntil("Find and respond to request role UI", () -> {
+ requestRole(ROLE_NAME);
+ UiObject2 cancelButton = waitFindObjectOrNull(By.res("android:id/button2"));
+ if (cancelButton == null) {
+ // Dialog not found, try again later.
+ return false;
+ }
+ UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false);
+
+ assertThat(dontAskAgainCheck).isNull();
+
+ respondToRoleRequest(false);
+ return true;
+ });
+ }
+
+ @Test
+ @FlakyTest
+ public void requestRoleAndDenyWithDontAskAgainAndReinstallThenShowsUiWithoutDontAskAgain()
+ throws Exception {
+ requestRole(ROLE_NAME);
+ respondToRoleRequest(false);
+
+ requestRole(ROLE_NAME);
+ findDontAskAgainCheck().click();
+ clickButtonAndWaitForResult(true);
+ // Wait for the RequestRoleActivity inside the test app to be removed from our task so that
+ // when the test app is uninstalled, our task isn't force finished and our
+ // WaitForResultActivity can survive.
+ Thread.sleep(5000);
+
+ uninstallPackage(APP_PACKAGE_NAME);
+ // Wait for the don't ask again to be forgotten.
+ Thread.sleep(10000);
+ installPackage(APP_APK_PATH);
+
+ TestUtils.waitUntil("Find and respond to request role UI", () -> {
+ requestRole(ROLE_NAME);
+ UiObject2 cancelButton = waitFindObjectOrNull(By.res("android:id/button2"));
+ if (cancelButton == null) {
+ // Dialog not found, try again later.
+ return false;
+ }
+ UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false);
+
+ assertThat(dontAskAgainCheck).isNull();
+
+ respondToRoleRequest(false);
+ return true;
+ });
+ }
+
+ @Test
+ public void requestInvalidRoleThenDeniedAutomatically() throws Exception {
+ requestRole("invalid");
+ Pair<Integer, Intent> result = waitForResult();
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ public void requestUnqualifiedRoleThenDeniedAutomatically() throws Exception {
+ requestRole(RoleManager.ROLE_HOME);
+ Pair<Integer, Intent> result = waitForResult();
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ public void requestAssistantRoleThenDeniedAutomatically() throws Exception {
+ requestRole(RoleManager.ROLE_ASSISTANT);
+ Pair<Integer, Intent> result = waitForResult();
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void requestHoldingRoleThenAllowedAutomatically() throws Exception {
+ requestRole(ROLE_NAME);
+ respondToRoleRequest(true);
+
+ requestRole(ROLE_NAME);
+ Pair<Integer, Intent> result = waitForResult();
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_OK);
+ }
+
+ private void requestRole(@NonNull String roleName) {
+ Intent intent = new Intent()
+ .setComponent(new ComponentName(APP_PACKAGE_NAME, APP_REQUEST_ROLE_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_ROLE_NAME, roleName);
+ mActivityRule.getActivity().startActivityToWaitForResult(intent);
+ }
+
+ private void respondToRoleRequest(boolean allow)
+ throws InterruptedException, UiObjectNotFoundException {
+ if (allow) {
+ waitFindObject(By.text(APP_LABEL)).click();
+ }
+ Pair<Integer, Intent> result = clickButtonAndWaitForResult(allow);
+ int expectedResult = allow ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
+
+ assertThat(result.first).isEqualTo(expectedResult);
+ }
+
+ @Nullable
+ private UiObject2 findDontAskAgainCheck(boolean expected) throws UiObjectNotFoundException {
+ BySelector selector = By.res("com.android.permissioncontroller:id/dont_ask_again");
+ return expected
+ ? waitFindObject(selector)
+ : waitFindObjectOrNull(selector, UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Nullable
+ private UiObject2 findDontAskAgainCheck() throws UiObjectNotFoundException {
+ return findDontAskAgainCheck(true);
+ }
+
+ @NonNull
+ private Pair<Integer, Intent> clickButtonAndWaitForResult(boolean positive)
+ throws InterruptedException, UiObjectNotFoundException {
+ waitFindObject(By.res(positive ? "android:id/button1" : "android:id/button2")).click();
+ return waitForResult();
+ }
+
+ @NonNull
+ private Pair<Integer, Intent> waitForResult() throws InterruptedException {
+ return mActivityRule.getActivity().waitForActivityResult(TIMEOUT_MILLIS);
+ }
+
+ private void clearPackageData(@NonNull String packageName) {
+ runShellCommand("pm clear --user " + Process.myUserHandle().getIdentifier() + " "
+ + packageName);
+ }
+
+ private void installPackage(@NonNull String apkPath) {
+ runShellCommandOrThrow(
+ "pm install -r --user " + Process.myUserHandle().getIdentifier() + " " + apkPath);
+ }
+
+ private void uninstallPackage(@NonNull String packageName) {
+ runShellCommand("pm uninstall --user " + Process.myUserHandle().getIdentifier() + " "
+ + packageName);
+ }
+
+ @Test
+ public void targetCurrentSdkAndChangeDefaultDialerThenDeniedAutomatically() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
+
+ WaitForResultActivity activity = mActivityRule.getActivity();
+ activity.startActivityToWaitForResult(new Intent()
+ .setComponent(new ComponentName(APP_PACKAGE_NAME,
+ APP_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME));
+ Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS);
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ public void targetCurrentSdkAndChangeDefaultSmsThenDeniedAutomatically() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ WaitForResultActivity activity = mActivityRule.getActivity();
+ activity.startActivityToWaitForResult(new Intent()
+ .setComponent(new ComponentName(APP_PACKAGE_NAME,
+ APP_CHANGE_DEFAULT_SMS_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME));
+ Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS);
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void targetSdk28AndChangeDefaultDialerAndAllowThenIsDefaultDialer() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
+
+ sContext.startActivity(new Intent()
+ .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
+ APP_28_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_28_PACKAGE_NAME)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ waitFindObject(By.text(APP_28_LABEL)).click();
+ waitFindObject(By.res("android:id/button1")).click();
+
+ // TODO(b/149037075): Use TelecomManager.getDefaultDialerPackage() once the bug is fixed.
+ //TelecomManager telecomManager = sContext.getSystemService(TelecomManager.class);
+ //TestUtils.waitUntil("App is not set as default dialer app", () -> Objects.equals(
+ // telecomManager.getDefaultDialerPackage(), APP_28_PACKAGE_NAME));
+ TestUtils.waitUntil("App is not set as default dialer app", () ->
+ getRoleHolders(RoleManager.ROLE_DIALER).contains(APP_28_PACKAGE_NAME));
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void targetSdk28AndChangeDefaultSmsAndAllowThenIsDefaultSms() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ sContext.startActivity(new Intent()
+ .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
+ APP_28_CHANGE_DEFAULT_SMS_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_28_PACKAGE_NAME)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ waitFindObject(By.text(APP_28_LABEL)).click();
+ waitFindObject(By.res("android:id/button1")).click();
+
+ TestUtils.waitUntil("App is not set as default sms app", () -> Objects.equals(
+ Telephony.Sms.getDefaultSmsPackage(sContext), APP_28_PACKAGE_NAME));
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void targetSdk28AndChangeDefaultDialerForAnotherAppThenDeniedAutomatically()
+ throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
+
+ WaitForResultActivity activity = mActivityRule.getActivity();
+ activity.startActivityToWaitForResult(new Intent()
+ .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
+ APP_28_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME));
+ Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS);
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void targetSdk28AndChangeDefaultSmsForAnotherAppThenDeniedAutomatically()
+ throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ WaitForResultActivity activity = mActivityRule.getActivity();
+ activity.startActivityToWaitForResult(new Intent()
+ .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
+ APP_28_CHANGE_DEFAULT_SMS_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME));
+ Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS);
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void
+ targetSdk28AndChangeDefaultDialerForAnotherAppAsHolderAndAllowThenTheOtherAppIsDefaultDialer()
+ throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
+
+ addRoleHolder(RoleManager.ROLE_DIALER, APP_28_PACKAGE_NAME);
+ sContext.startActivity(new Intent()
+ .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
+ APP_28_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ waitFindObject(By.text(APP_LABEL)).click();
+ waitFindObject(By.res("android:id/button1")).click();
+
+ // TODO(b/149037075): Use TelecomManager.getDefaultDialerPackage() once the bug is fixed.
+ //TelecomManager telecomManager = sContext.getSystemService(TelecomManager.class);
+ //TestUtils.waitUntil("App is not set as default dialer app", () -> Objects.equals(
+ // telecomManager.getDefaultDialerPackage(), APP_PACKAGE_NAME));
+ TestUtils.waitUntil("App is not set as default dialer app", () ->
+ getRoleHolders(RoleManager.ROLE_DIALER).contains(APP_PACKAGE_NAME));
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ public void testHoldDialerRoleRequirementWithInCallServiceAndSdk()
+ throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
+ // target below sdk 33 without InCallService component can hold dialer role
+ addRoleHolder(
+ RoleManager.ROLE_DIALER, APP_28_PACKAGE_NAME, true);
+ assertIsRoleHolder(
+ RoleManager.ROLE_DIALER, APP_28_PACKAGE_NAME, true);
+ // target sdk 33 without InCallService component cannot hold dialer role
+ addRoleHolder(
+ RoleManager.ROLE_DIALER, APP_33_WITHOUT_INCALLSERVICE_PACKAGE_NAME, false);
+ assertIsRoleHolder(
+ RoleManager.ROLE_DIALER, APP_33_WITHOUT_INCALLSERVICE_PACKAGE_NAME, false);
+ // target sdk 33 with InCallService component can hold dialer role
+ addRoleHolder(
+ RoleManager.ROLE_DIALER, APP_PACKAGE_NAME, true);
+ assertIsRoleHolder(
+ RoleManager.ROLE_DIALER, APP_PACKAGE_NAME, true);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void
+ targetSdk28AndChangeDefaultSmsForAnotherAppAsHolderAndAllowThenTheOtherAppIsDefaultSms()
+ throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ addRoleHolder(RoleManager.ROLE_SMS, APP_28_PACKAGE_NAME);
+ sContext.startActivity(new Intent()
+ .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
+ APP_28_CHANGE_DEFAULT_SMS_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ waitFindObject(By.text(APP_LABEL)).click();
+ waitFindObject(By.res("android:id/button1")).click();
+
+ TestUtils.waitUntil("App is not set as default sms app", () -> Objects.equals(
+ Telephony.Sms.getDefaultSmsPackage(sContext), APP_PACKAGE_NAME));
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void openDefaultAppDetailsThenIsNotDefaultApp() throws Exception {
+ runWithShellPermissionIdentity(() -> sContext.startActivity(new Intent(
+ Intent.ACTION_MANAGE_DEFAULT_APP)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NAME)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK)));
+
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(false).hasDescendant(By.text(APP_LABEL)));
+ } else {
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(false))
+ .hasDescendant(By.text(APP_LABEL)));
+ }
+
+ pressBack();
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void openDefaultAppDetailsAndSetDefaultAppThenIsDefaultApp() throws Exception {
+ runWithShellPermissionIdentity(() -> sContext.startActivity(new Intent(
+ Intent.ACTION_MANAGE_DEFAULT_APP)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NAME)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK)));
+ waitForIdle();
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(false).hasDescendant(
+ By.text(APP_LABEL))).click();
+ } else {
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(false))
+ .hasDescendant(By.text(APP_LABEL))).click();
+ }
+
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(true).hasDescendant(By.text(APP_LABEL)));
+ } else {
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(true))
+ .hasDescendant(By.text(APP_LABEL)));
+ }
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true);
+
+ pressBack();
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void openDefaultAppDetailsAndSetDefaultAppAndSetAnotherThenIsNotDefaultApp()
+ throws Exception {
+ runWithShellPermissionIdentity(() -> sContext.startActivity(new Intent(
+ Intent.ACTION_MANAGE_DEFAULT_APP)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NAME)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK)));
+ waitForIdle();
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(false).hasDescendant(
+ By.text(APP_LABEL))).click();
+ waitFindObject(By.clickable(true).checked(true).hasDescendant(By.text(APP_LABEL)));
+ } else {
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(false))
+ .hasDescendant(By.text(APP_LABEL))).click();
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(true))
+ .hasDescendant(By.text(APP_LABEL)));
+ }
+ waitForIdle();
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(false)).click();
+ } else {
+ waitFindObject(
+ By.clickable(true).hasDescendant(By.checkable(true).checked(false))).click();
+ }
+
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(false).hasDescendant(By.text(APP_LABEL)));
+ } else {
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(false))
+ .hasDescendant(By.text(APP_LABEL)));
+ }
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+
+ pressBack();
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void openDefaultAppListThenHasDefaultApp() throws Exception {
+ sContext.startActivity(new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
+
+ waitFindObject(By.text(ROLE_SHORT_LABEL));
+
+ pressBack();
+ }
+
+ @Test
+ public void openDefaultAppListThenIsNotDefaultAppInList() throws Exception {
+ sContext.startActivity(new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
+
+ assertThat(waitFindObjectOrNull(By.text(APP_LABEL), UNEXPECTED_TIMEOUT_MILLIS))
+ .isNull();
+
+ pressBack();
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void openDefaultAppListAndSetDefaultAppThenIsDefaultApp() throws Exception {
+ sContext.startActivity(new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
+ waitForIdle();
+ waitFindObject(By.text(ROLE_SHORT_LABEL)).click();
+ waitForIdle();
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(false).hasDescendant(
+ By.text(APP_LABEL))).click();
+ } else {
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(false))
+ .hasDescendant(By.text(APP_LABEL))).click();
+ }
+
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(true).hasDescendant(By.text(APP_LABEL)));
+ } else {
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(true))
+ .hasDescendant(By.text(APP_LABEL)));
+ }
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true);
+
+ pressBack();
+ pressBack();
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void openDefaultAppListAndSetDefaultAppThenIsDefaultAppInList() throws Exception {
+ sContext.startActivity(new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
+ waitForIdle();
+ waitFindObject(By.text(ROLE_SHORT_LABEL)).click();
+ waitForIdle();
+ if (sIsWatch) {
+ waitFindObject(By.clickable(true).checked(false).hasDescendant(
+ By.text(APP_LABEL))).click();
+ waitFindObject(By.clickable(true).checked(true).hasDescendant(By.text(APP_LABEL)));
+ } else {
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(false))
+ .hasDescendant(By.text(APP_LABEL))).click();
+ waitFindObject(By.clickable(true).hasDescendant(By.checkable(true).checked(true))
+ .hasDescendant(By.text(APP_LABEL)));
+ }
+ pressBack();
+
+ waitFindObject(By.text(APP_LABEL));
+
+ pressBack();
+ }
+
+ private static void waitForIdle() {
+ UiAutomatorUtils.getUiDevice().waitForIdle();
+ }
+
+ private static void pressBack() {
+ UiAutomatorUtils.getUiDevice().pressBack();
+ waitForIdle();
+ }
+
+ @Test
+ public void roleIsAvailable() {
+ assertThat(sRoleManager.isRoleAvailable(ROLE_NAME)).isTrue();
+ }
+
+ @Test
+ public void dontAddRoleHolderThenRoleIsNotHeld() throws Exception {
+ assertRoleIsHeld(ROLE_NAME, false);
+ }
+
+ @Test
+ public void addRoleHolderThenRoleIsHeld() throws Exception {
+ addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+
+ assertRoleIsHeld(ROLE_NAME, true);
+ }
+
+ @Test
+ public void addAndRemoveRoleHolderThenRoleIsNotHeld() throws Exception {
+ addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+ removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+
+ assertRoleIsHeld(ROLE_NAME, false);
+ }
+
+ private void assertRoleIsHeld(@NonNull String roleName, boolean isHeld)
+ throws InterruptedException {
+ Intent intent = new Intent()
+ .setComponent(new ComponentName(APP_PACKAGE_NAME, APP_IS_ROLE_HELD_ACTIVITY_NAME))
+ .putExtra(Intent.EXTRA_ROLE_NAME, roleName);
+ WaitForResultActivity activity = mActivityRule.getActivity();
+ activity.startActivityToWaitForResult(intent);
+ Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS);
+
+ assertThat(result.first).isEqualTo(Activity.RESULT_OK);
+ assertThat(result.second).isNotNull();
+ assertThat(result.second.hasExtra(APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD)).isTrue();
+ assertThat(result.second.getBooleanExtra(APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD, false))
+ .isEqualTo(isHeld);
+ }
+
+ @Test
+ public void dontAddRoleHolderThenIsNotRoleHolder() throws Exception {
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+ }
+
+ @Test
+ public void addRoleHolderThenIsRoleHolder() throws Exception {
+ addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true);
+ }
+
+ @Test
+ public void addAndRemoveRoleHolderThenIsNotRoleHolder() throws Exception {
+ addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+ removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+ }
+
+ @Test
+ public void addAndClearRoleHoldersThenIsNotRoleHolder() throws Exception {
+ addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+ clearRoleHolders(ROLE_NAME);
+
+ assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+ }
+
+ @Test
+ public void addInvalidRoleHolderThenFails() throws Exception {
+ addRoleHolder("invalid", APP_PACKAGE_NAME, false);
+ }
+
+ @Test
+ public void addUnqualifiedRoleHolderThenFails() throws Exception {
+ addRoleHolder(RoleManager.ROLE_HOME, APP_PACKAGE_NAME, false);
+ }
+
+ @Test
+ public void removeInvalidRoleHolderThenFails() throws Exception {
+ removeRoleHolder("invalid", APP_PACKAGE_NAME, false);
+ }
+
+ @Test
+ public void clearInvalidRoleHoldersThenFails() throws Exception {
+ clearRoleHolders("invalid", false);
+ }
+
+ @Test
+ public void addOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotified() throws Exception {
+ assertOnRoleHoldersChangedListenerIsNotified(() -> addRoleHolder(ROLE_NAME,
+ APP_PACKAGE_NAME));
+ }
+
+ @Test
+ public void addOnRoleHoldersChangedListenerAndRemoveRoleHolderThenIsNotified()
+ throws Exception {
+ addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+
+ assertOnRoleHoldersChangedListenerIsNotified(() -> removeRoleHolder(ROLE_NAME,
+ APP_PACKAGE_NAME));
+ }
+
+ @Test
+ public void addOnRoleHoldersChangedListenerAndClearRoleHoldersThenIsNotified()
+ throws Exception {
+ addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+
+ assertOnRoleHoldersChangedListenerIsNotified(() -> clearRoleHolders(ROLE_NAME));
+ }
+
+ private void assertOnRoleHoldersChangedListenerIsNotified(@NonNull ThrowingRunnable runnable)
+ throws Exception {
+ ListenerFuture future = new ListenerFuture();
+ UserHandle user = Process.myUserHandle();
+ runWithShellPermissionIdentity(() -> sRoleManager.addOnRoleHoldersChangedListenerAsUser(
+ sContext.getMainExecutor(), future, user));
+ Pair<String, UserHandle> result;
+ try {
+ runnable.run();
+ result = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } finally {
+ runWithShellPermissionIdentity(() ->
+ sRoleManager.removeOnRoleHoldersChangedListenerAsUser(future, user));
+ }
+
+ assertThat(result.first).isEqualTo(ROLE_NAME);
+ assertThat(result.second).isEqualTo(user);
+ }
+
+ @Test
+ public void addAndRemoveOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotNotified()
+ throws Exception {
+ ListenerFuture future = new ListenerFuture();
+ UserHandle user = Process.myUserHandle();
+ runWithShellPermissionIdentity(() -> {
+ sRoleManager.addOnRoleHoldersChangedListenerAsUser(sContext.getMainExecutor(), future,
+ user);
+ sRoleManager.removeOnRoleHoldersChangedListenerAsUser(future, user);
+ });
+ addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+
+ try {
+ future.get(UNEXPECTED_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ // Expected
+ return;
+ }
+ throw new AssertionError("OnRoleHoldersChangedListener was notified after removal");
+ }
+
+ @Test
+ public void setRoleNamesFromControllerShouldRequireManageRolesFromControllerPermission() {
+ assertRequiresManageRolesFromControllerPermission(
+ () -> sRoleManager.setRoleNamesFromController(Collections.emptyList()),
+ "setRoleNamesFromController");
+ }
+
+ @Test
+ public void addRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission() {
+ assertRequiresManageRolesFromControllerPermission(
+ () -> sRoleManager.addRoleHolderFromController(ROLE_NAME, APP_PACKAGE_NAME),
+ "addRoleHolderFromController");
+ }
+
+ @Test
+ public void removeRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission() {
+ assertRequiresManageRolesFromControllerPermission(
+ () -> sRoleManager.removeRoleHolderFromController(ROLE_NAME, APP_PACKAGE_NAME),
+ "removeRoleHolderFromController");
+ }
+
+ @Test
+ public void getHeldRolesFromControllerShouldRequireManageRolesFromControllerPermission() {
+ assertRequiresManageRolesFromControllerPermission(
+ () -> sRoleManager.getHeldRolesFromController(APP_PACKAGE_NAME),
+ "getHeldRolesFromController");
+ }
+
+ private void assertRequiresManageRolesFromControllerPermission(@NonNull Runnable runnable,
+ @NonNull String methodName) {
+ try {
+ runnable.run();
+ } catch (SecurityException e) {
+ if (e.getMessage().contains(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)) {
+ // Expected
+ return;
+ }
+ throw e;
+ }
+ fail("RoleManager." + methodName + "() should require "
+ + PERMISSION_MANAGE_ROLES_FROM_CONTROLLER);
+ }
+
+ @Test
+ public void manageRolesFromControllerPermissionShouldBeDeclaredByPermissionController()
+ throws PackageManager.NameNotFoundException {
+ PermissionInfo permissionInfo = sPackageManager.getPermissionInfo(
+ PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, 0);
+
+ assertThat(permissionInfo.packageName).isEqualTo(
+ sPackageManager.getPermissionControllerPackageName());
+ assertThat(permissionInfo.getProtection()).isEqualTo(PermissionInfo.PROTECTION_SIGNATURE);
+ assertThat(permissionInfo.getProtectionFlags()).isEqualTo(0);
+ }
+
+ @Test
+ public void smsRoleHasHolder() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ assertThat(getRoleHolders(RoleManager.ROLE_SMS)).isNotEmpty();
+ }
+
+ @Test
+ public void addSmsRoleHolderThenPermissionIsGranted() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
+
+ assertThat(sPackageManager.checkPermission(android.Manifest.permission.SEND_SMS,
+ APP_PACKAGE_NAME)).isEqualTo(PackageManager.PERMISSION_GRANTED);
+ }
+
+ @Test
+ public void removeSmsRoleHolderThenPermissionIsRevoked() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ String smsRoleHolder = getRoleHolders(RoleManager.ROLE_SMS).get(0);
+ addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
+ addRoleHolder(RoleManager.ROLE_SMS, smsRoleHolder);
+
+ assertThat(sPackageManager.checkPermission(android.Manifest.permission.SEND_SMS,
+ APP_PACKAGE_NAME)).isEqualTo(PackageManager.PERMISSION_DENIED);
+ }
+
+ @Test
+ public void removeSmsRoleHolderThenDialerRolePermissionIsRetained() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER)
+ && sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ addRoleHolder(RoleManager.ROLE_DIALER, APP_PACKAGE_NAME);
+ String smsRoleHolder = getRoleHolders(RoleManager.ROLE_SMS).get(0);
+ addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
+ addRoleHolder(RoleManager.ROLE_SMS, smsRoleHolder);
+
+ assertThat(sPackageManager.checkPermission(android.Manifest.permission.SEND_SMS,
+ APP_PACKAGE_NAME)).isEqualTo(PackageManager.PERMISSION_GRANTED);
+ }
+
+ @Test
+ public void packageManagerGetDefaultBrowserBackedByRole() throws Exception {
+ addRoleHolder(RoleManager.ROLE_BROWSER, APP_PACKAGE_NAME);
+
+ assertThat(sPackageManager.getDefaultBrowserPackageNameAsUser(UserHandle.myUserId()))
+ .isEqualTo(APP_PACKAGE_NAME);
+ }
+
+ @Test
+ @FlakyTest(bugId = 288468003, detail = "CtsRoleTestCases is breaching 20min SLO")
+ public void packageManagerSetDefaultBrowserBackedByRole() throws Exception {
+ callWithShellPermissionIdentity(() -> sPackageManager.setDefaultBrowserPackageNameAsUser(
+ APP_PACKAGE_NAME, UserHandle.myUserId()));
+
+ assertIsRoleHolder(RoleManager.ROLE_BROWSER, APP_PACKAGE_NAME, true);
+ }
+
+ @Test
+ public void telephonySmsGetDefaultSmsPackageBackedByRole() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
+
+ assertThat(Telephony.Sms.getDefaultSmsPackage(sContext)).isEqualTo(APP_PACKAGE_NAME);
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+ @Test
+ public void cannotBypassRoleQualificationWithoutPermission() throws Exception {
+ assertThrows(SecurityException.class, () ->
+ sRoleManager.setBypassingRoleQualification(true));
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+ @Test
+ public void bypassRoleQualificationThenCanAddUnqualifiedRoleHolder() throws Exception {
+ assertThat(sRoleManager.isRoleAvailable(RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER))
+ .isTrue();
+
+ runWithShellPermissionIdentity(() -> sRoleManager.setBypassingRoleQualification(true));
+ try {
+ assertThat(callWithShellPermissionIdentity(() ->
+ sRoleManager.isBypassingRoleQualification())).isTrue();
+
+ // The System Activity Recognizer role requires a system app, so this won't succeed
+ // without bypassing role qualification.
+ addRoleHolder(RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER, APP_PACKAGE_NAME);
+
+ assertThat(getRoleHolders(RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER))
+ .contains(APP_PACKAGE_NAME);
+ } finally {
+ runWithShellPermissionIdentity(() -> sRoleManager.setBypassingRoleQualification(false));
+ }
+ assertThat(callWithShellPermissionIdentity(() ->
+ sRoleManager.isBypassingRoleQualification())).isFalse();
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ public void cannotGetDefaultApplicationWithoutPermission() throws Exception {
+ assertThrows(SecurityException.class, ()->
+ sRoleManager.getDefaultApplication(
+ RoleManager.ROLE_SMS));
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ public void getDefaultApplicationChecksRoles() throws Exception {
+ runWithShellPermissionIdentity(() ->
+ assertThrows(IllegalArgumentException.class, () ->
+ sRoleManager.getDefaultApplication(
+ RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER)));
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ public void getDefaultApplicationReadsRole() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
+ runWithShellPermissionIdentity(() -> {
+ assertThat(sRoleManager.getDefaultApplication(RoleManager.ROLE_SMS))
+ .isEqualTo(APP_PACKAGE_NAME);
+ });
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ public void cannotSetDefaultApplicationWithoutPermission() throws Exception {
+ CallbackFuture future = new CallbackFuture();
+ assertThrows(SecurityException.class, ()->
+ sRoleManager.setDefaultApplication(
+ RoleManager.ROLE_SMS, APP_PACKAGE_NAME, 0,
+ sContext.getMainExecutor(), future));
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ public void setDefaultApplicationChecksRoles() throws Exception {
+ CallbackFuture future = new CallbackFuture();
+ runWithShellPermissionIdentity(() ->
+ assertThrows(IllegalArgumentException.class, () ->
+ sRoleManager.setDefaultApplication(
+ RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER, APP_PACKAGE_NAME, 0,
+ sContext.getMainExecutor(), future)));
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ public void setDefaultApplicationSetsRole() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ CallbackFuture future = new CallbackFuture();
+ runWithShellPermissionIdentity(() -> {
+ sRoleManager.setDefaultApplication(
+ RoleManager.ROLE_SMS, APP_PACKAGE_NAME, 0,
+ sContext.getMainExecutor(), future);
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+ assertThat(sRoleManager.getRoleHolders(RoleManager.ROLE_SMS))
+ .containsExactly(APP_PACKAGE_NAME);
+ });
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM,
+ codeName = "VanillaIceCream")
+ @Test
+ public void testSetAndGetRoleFallbackEnabled() {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
+
+ runWithShellPermissionIdentity(() -> {
+ sRoleManager.setRoleFallbackEnabled(RoleManager.ROLE_SMS, true);
+ assertThat(sRoleManager.isRoleFallbackEnabled(RoleManager.ROLE_SMS)).isTrue();
+ });
+ }
+
+ @NonNull
+ private List<String> getRoleHolders(@NonNull String roleName) throws Exception {
+ return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName));
+ }
+
+ private void assertIsRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ boolean shouldBeRoleHolder) throws Exception {
+ List<String> packageNames = getRoleHolders(roleName);
+
+ if (shouldBeRoleHolder) {
+ assertThat(packageNames).contains(packageName);
+ } else {
+ assertThat(packageNames).doesNotContain(packageName);
+ }
+ }
+
+ private void addRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ boolean expectSuccess) throws Exception {
+ CallbackFuture future = new CallbackFuture();
+ runWithShellPermissionIdentity(() -> sRoleManager.addRoleHolderAsUser(roleName,
+ packageName, 0, Process.myUserHandle(), sContext.getMainExecutor(), future));
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isEqualTo(expectSuccess);
+ }
+
+ private void addRoleHolder(@NonNull String roleName, @NonNull String packageName)
+ throws Exception {
+ addRoleHolder(roleName, packageName, true);
+ }
+
+ private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ boolean expectSuccess) throws Exception {
+ CallbackFuture future = new CallbackFuture();
+ runWithShellPermissionIdentity(() -> sRoleManager.removeRoleHolderAsUser(roleName,
+ packageName, 0, Process.myUserHandle(), sContext.getMainExecutor(), future));
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isEqualTo(expectSuccess);
+ }
+
+ private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName)
+ throws Exception {
+ removeRoleHolder(roleName, packageName, true);
+ }
+
+ private void clearRoleHolders(@NonNull String roleName, boolean expectSuccess)
+ throws Exception {
+ CallbackFuture future = new CallbackFuture();
+ runWithShellPermissionIdentity(() -> sRoleManager.clearRoleHoldersAsUser(roleName, 0,
+ Process.myUserHandle(), sContext.getMainExecutor(), future));
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isEqualTo(expectSuccess);
+ }
+
+ private void clearRoleHolders(@NonNull String roleName) throws Exception {
+ clearRoleHolders(roleName, true);
+ }
+
+ private static class ListenerFuture extends CompletableFuture<Pair<String, UserHandle>>
+ implements OnRoleHoldersChangedListener {
+
+ @Override
+ public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
+ complete(new Pair<>(roleName, user));
+ }
+ }
+
+ private static class CallbackFuture extends CompletableFuture<Boolean>
+ implements Consumer<Boolean> {
+
+ @Override
+ public void accept(Boolean successful) {
+ complete(successful);
+ }
+ }
+}
diff --git a/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt b/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt
new file mode 100644
index 000000000..7e58e1848
--- /dev/null
+++ b/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts
+
+import android.app.role.RoleManager
+import android.os.Build
+import android.os.UserHandle
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.SdkSuppress
+import androidx.test.runner.AndroidJUnit4
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests role shell commands. */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+class RoleShellCommandTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context = instrumentation.context
+ private val roleManager = context.getSystemService(RoleManager::class.java)!!
+ private val userId = UserHandle.myUserId()
+
+ private var roleHolder: String? = null
+ private var wasBypassingRoleQualification: Boolean = false
+
+ @Before
+ fun saveRoleHolder() {
+ roleHolder = getRoleHolders().firstOrNull()
+ if (roleHolder == APP_PACKAGE_NAME) {
+ removeRoleHolder()
+ roleHolder = null
+ }
+ }
+
+ @Before
+ fun saveBypassingRoleQualification() {
+ wasBypassingRoleQualification = isBypassingRoleQualification()
+ }
+
+ @After
+ fun restoreRoleHolder() {
+ removeRoleHolder()
+ roleHolder?.let { addRoleHolder(it) }
+ assertIsRoleHolder(false)
+ }
+
+ @After
+ fun restoreBypassingRoleQualification() {
+ setBypassingRoleQualification(wasBypassingRoleQualification)
+ }
+
+ @Before
+ fun installApp() {
+ installPackage(APP_APK_PATH)
+ }
+
+ @After
+ fun uninstallApp() {
+ uninstallPackage(APP_PACKAGE_NAME)
+ }
+
+ @Test
+ fun helpPrintsNonEmpty() {
+ assertThat(runShellCommandOrThrow("cmd role help")).isNotEmpty()
+ }
+
+ @Test
+ fun dontAddRoleHolderThenIsNotRoleHolder() {
+ assertIsRoleHolder(false)
+ }
+
+ @Test
+ fun addRoleHolderThenIsRoleHolder() {
+ addRoleHolder()
+
+ assertIsRoleHolder(true)
+ }
+
+ @Test
+ fun addAndRemoveRoleHolderThenIsNotRoleHolder() {
+ addRoleHolder()
+ removeRoleHolder()
+
+ assertIsRoleHolder(false)
+ }
+
+ @Test
+ fun addAndClearRoleHolderThenIsNotRoleHolder() {
+ addRoleHolder()
+ clearRoleHolders()
+
+ assertIsRoleHolder(false)
+ }
+
+ @Test
+ fun addInvalidRoleHolderThenFails() {
+ assertThrows(AssertionError::class.java) {
+ runShellCommandOrThrow("cmd role add-role-holder --user $userId $ROLE_NAME invalid")
+ }
+ }
+
+ @Test
+ fun addRoleHolderThenAppearsInDumpsys() {
+ addRoleHolder()
+
+ assertThat(runShellCommandOrThrow("dumpsys role")).contains(APP_PACKAGE_NAME)
+ }
+
+ @Test
+ fun setBypassingRoleQualificationToTrueThenSetsToTrue() {
+ setBypassingRoleQualification(false)
+
+ runShellCommandOrThrow("cmd role set-bypassing-role-qualification true")
+
+ assertThat(isBypassingRoleQualification()).isTrue()
+ }
+
+ @Test
+ fun setBypassingRoleQualificationToFalseThenSetsToFalse() {
+ setBypassingRoleQualification(true)
+
+ runShellCommandOrThrow("cmd role set-bypassing-role-qualification false")
+
+ assertThat(isBypassingRoleQualification()).isFalse()
+ }
+
+ private fun addRoleHolder(packageName: String = APP_PACKAGE_NAME) {
+ runShellCommandOrThrow("cmd role add-role-holder --user $userId $ROLE_NAME $packageName")
+ }
+
+ private fun removeRoleHolder(packageName: String = APP_PACKAGE_NAME) {
+ runShellCommandOrThrow("cmd role remove-role-holder --user $userId $ROLE_NAME $packageName")
+ }
+
+ private fun clearRoleHolders() {
+ runShellCommandOrThrow("cmd role clear-role-holders --user $userId $ROLE_NAME")
+ }
+
+ private fun getRoleHolders(): List<String> =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ runShellCommandOrThrow("cmd role get-role-holders --user $userId $ROLE_NAME")
+ .trim()
+ .let { if (it.isNotEmpty()) it.split(";") else emptyList() }
+ } else {
+ callWithShellPermissionIdentity { roleManager.getRoleHolders(ROLE_NAME) }
+ }
+
+ private fun assertIsRoleHolder(shouldBeRoleHolder: Boolean) {
+ val packageNames = getRoleHolders()
+ if (shouldBeRoleHolder) {
+ assertThat(packageNames).contains(APP_PACKAGE_NAME)
+ } else {
+ assertThat(packageNames).doesNotContain(APP_PACKAGE_NAME)
+ }
+ }
+
+ private fun installPackage(apkPath: String) {
+ assertThat(runShellCommandOrThrow("pm install -r --user $userId $apkPath").trim())
+ .isEqualTo("Success")
+ }
+
+ private fun uninstallPackage(packageName: String) {
+ assertThat(runShellCommandOrThrow("pm uninstall --user $userId $packageName").trim())
+ .isEqualTo("Success")
+ }
+
+ private fun isBypassingRoleQualification(): Boolean = callWithShellPermissionIdentity {
+ roleManager.isBypassingRoleQualification()
+ }
+
+ private fun setBypassingRoleQualification(value: Boolean) {
+ callWithShellPermissionIdentity { roleManager.setBypassingRoleQualification(value) }
+ }
+
+ companion object {
+ private const val ROLE_NAME = RoleManager.ROLE_BROWSER
+ private const val APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk"
+ private const val APP_PACKAGE_NAME = "android.app.role.cts.app"
+ }
+}
diff --git a/tests/cts/role/src/android/app/role/cts/WaitForResultActivity.java b/tests/cts/role/src/android/app/role/cts/WaitForResultActivity.java
new file mode 100644
index 000000000..fb13423d4
--- /dev/null
+++ b/tests/cts/role/src/android/app/role/cts/WaitForResultActivity.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An Activity that can start another Activity and wait for its result.
+ */
+public class WaitForResultActivity extends Activity {
+
+ private static final int REQUEST_CODE_WAIT_FOR_RESULT = 1;
+
+ private CountDownLatch mLatch;
+ private int mResultCode;
+ private Intent mData;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ throw new RuntimeException(
+ "Activity was recreated (perhaps due to a configuration change?) "
+ + "and this activity doesn't currently know how to gracefully handle "
+ + "configuration changes.");
+ }
+ }
+
+ public void startActivityToWaitForResult(@NonNull Intent intent) {
+ mLatch = new CountDownLatch(1);
+ startActivityForResult(intent, REQUEST_CODE_WAIT_FOR_RESULT);
+ }
+
+ @NonNull
+ public Pair<Integer, Intent> waitForActivityResult(long timeoutMillis)
+ throws InterruptedException {
+ mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+ return new Pair<>(mResultCode, mData);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ if (requestCode == REQUEST_CODE_WAIT_FOR_RESULT) {
+ mResultCode = resultCode;
+ mData = data;
+ mLatch.countDown();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+}
diff --git a/tests/cts/safetycenter/Android.bp b/tests/cts/safetycenter/Android.bp
index e980841b5..e7fe2ffd3 100644
--- a/tests/cts/safetycenter/Android.bp
+++ b/tests/cts/safetycenter/Android.bp
@@ -47,5 +47,6 @@ android_test {
"cts",
"general-tests",
"mts-permission",
+ "mcts-permission",
],
}
diff --git a/tests/cts/safetycenter/AndroidTest.xml b/tests/cts/safetycenter/AndroidTest.xml
index 5ec0c380e..6d8c3069c 100644
--- a/tests/cts/safetycenter/AndroidTest.xml
+++ b/tests/cts/safetycenter/AndroidTest.xml
@@ -43,9 +43,12 @@
aren't polluted by `BOOT_COMPLETED` or similar broadcasts still being delivered, which
causes our `ActivityManager#waitForBroadcastIdle()` calls to timeout. -->
<option name="run-command" value="am wait-for-broadcast-idle" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
<!-- 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" />
+ <!-- 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>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
diff --git a/tests/cts/safetycenter/TEST_MAPPING b/tests/cts/safetycenter/TEST_MAPPING
index e8c210a5d..b1f60307b 100644
--- a/tests/cts/safetycenter/TEST_MAPPING
+++ b/tests/cts/safetycenter/TEST_MAPPING
@@ -9,7 +9,7 @@
"name": "CtsSafetyCenterTestCases[com.google.android.permission.apex]",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt
index 33f52b564..c344d7ebd 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt
@@ -19,7 +19,7 @@ package android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.os.Build
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.os.Bundle
import android.safetycenter.SafetyCenterData
import android.safetycenter.SafetyCenterEntry
@@ -164,7 +164,7 @@ class SafetyCenterDataTest {
SafetyCenterData(status2, listOf(issue2), listOf(entryOrGroup2), listOf(staticEntryGroup2))
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getStatus_withDefaultBuilder_returnsStatus() {
val safetyCenterData = SafetyCenterData.Builder(status1).build()
@@ -172,7 +172,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getIssues_withDefaultBuilder_returnsEmptyList() {
val safetyCenterData = SafetyCenterData.Builder(status1).build()
@@ -180,7 +180,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getIssues_whenSetExplicitly_returnsIssues() {
val safetyCenterData =
SafetyCenterData.Builder(status1).addIssue(issue1).addIssue(issue2).build()
@@ -189,7 +189,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getEntriesOrGroups_withDefaultBuilder_returnsEmptyList() {
val safetyCenterData = SafetyCenterData.Builder(status1).build()
@@ -197,7 +197,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getEntriesOrGroups_whenSetExplicitly_returnsEntriesOrGroups() {
val safetyCenterData =
SafetyCenterData.Builder(status1)
@@ -211,7 +211,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getStaticGroups_withDefaultBuilder_returnsEmptyList() {
val safetyCenterData = SafetyCenterData.Builder(status1).build()
@@ -219,7 +219,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getStaticEntryGroups_whenSetExplicitly_returnsStaticEntryGroups() {
val safetyCenterData =
SafetyCenterData.Builder(status1)
@@ -233,7 +233,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getDismissedIssues_withDefaultBuilder_returnsEmptyList() {
val safetyCenterData = SafetyCenterData.Builder(status1).build()
@@ -241,7 +241,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getDismissedIssues_whenSetExplicitly_returnsIssues() {
val safetyCenterData =
SafetyCenterData.Builder(status1)
@@ -253,7 +253,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getExtras_withDefaultBuilder_returnsEmptyBundle() {
val safetyCenterData = SafetyCenterData.Builder(status1).build()
@@ -261,7 +261,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getExtras_whenSetExplicitly_returnsExtras() {
val safetyCenterData =
SafetyCenterData.Builder(status1).setExtras(filledExtrasIssuesToGroups1).build()
@@ -275,7 +275,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getExtras_whenCleared_returnsEmptyBundle() {
val safetyCenterData =
SafetyCenterData.Builder(status1)
@@ -299,7 +299,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getDismissedIssues_returnsDismissedIssues() {
val data3 = data1.withDismissedIssuesIfAtLeastU(listOf(issue2))
@@ -308,7 +308,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getDismissedIssues_mutationsAreNotAllowed() {
val mutatedDismissedIssues = data1.dismissedIssues
@@ -353,7 +353,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun builder_addIssue_doesNotMutatePreviouslyBuiltInstance() {
val safetyCenterDataBuilder = SafetyCenterData.Builder(status1).addIssue(issue1)
val issues = safetyCenterDataBuilder.build().issues
@@ -364,7 +364,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun builder_clearIssues_removesAllIssues() {
val safetyCenterData =
SafetyCenterData.Builder(status1)
@@ -377,7 +377,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun builder_addEntryOrGroup_doesNotMutatePreviouslyBuiltInstance() {
val safetyCenterDataBuilder =
SafetyCenterData.Builder(status1).addEntryOrGroup(entryOrGroup1)
@@ -389,7 +389,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun builder_clearEntriesOrGroups_removesAllEntriesOrGroups() {
val safetyCenterData =
SafetyCenterData.Builder(status1)
@@ -402,7 +402,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun builder_addStaticEntryGroup_doesNotMutatePreviouslyBuiltInstance() {
val safetyCenterDataBuilder =
SafetyCenterData.Builder(status1).addStaticEntryGroup(staticEntryGroup1)
@@ -414,7 +414,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun builder_clearStaticEntryGroups_removesAllStaticEntryGroups() {
val safetyCenterData =
SafetyCenterData.Builder(status1)
@@ -427,7 +427,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun builder_addDismissedIssue_doesNotMutatePreviouslyBuiltInstance() {
val safetyCenterDataBuilder = SafetyCenterData.Builder(status1).addDismissedIssue(issue1)
val dismissedIssues = safetyCenterDataBuilder.build().dismissedIssues
@@ -438,7 +438,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun builder_clearDismissedIssues_removesAllDismissedIssues() {
val safetyCenterData =
SafetyCenterData.Builder(status1)
@@ -463,7 +463,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun parcelRoundTrip_withDismissedIssues_recreatesEqual() {
val data3 = data1.withDismissedIssuesIfAtLeastU(listOf(issue2))
val data4 = data2.withDismissedIssuesIfAtLeastU(listOf(issue1))
@@ -473,7 +473,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun parcelRoundTrip_withExtras_recreatesEqual() {
val safetyCenterDataWithExtras = data1.withExtrasIfAtLeastU(filledAllExtras)
val safetyCenterDatafromParcel =
@@ -545,7 +545,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun equalsHashCode_atLeastU_usingEqualsHashCodeToStringTester() {
EqualsHashCodeToStringTester.ofParcelable(
parcelableCreator = SafetyCenterData.CREATOR,
@@ -680,7 +680,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun toString_withSingleKnownExtra_containsKnownExtra() {
val safetyCenterDataWithExtras = data1.withExtrasIfAtLeastU(filledExtrasIssuesToGroups1)
@@ -693,7 +693,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun toString_withAllKnownExtras_containsKnownExtras() {
val safetyCenterDataWithAllExtras = data1.withExtrasIfAtLeastU(filledAllExtras)
@@ -706,7 +706,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun toString_withOneKnowAndOneUnknownExtra_containsKnownAndUnknownExtras() {
val safetyCenterDataWithExtras = data1.withExtrasIfAtLeastU(filledOneKnownOneUnknown)
@@ -719,7 +719,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun toString_withSingleUnknownExtra_containsUnknownExtras() {
val safetyCenterDataWithExtras = data1.withExtrasIfAtLeastU(unknownExtras)
@@ -732,7 +732,7 @@ class SafetyCenterDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun toString_withoutExtras_containsNoExtras() {
val safetyCenterDataWithoutExtras = data1
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt
index 8d44f2736..be7ca343c 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt
@@ -19,7 +19,6 @@ package android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.os.Build
import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.SafetyCenterIssue
@@ -31,8 +30,8 @@ import androidx.test.ext.truth.os.ParcelableSubject.assertThat
import androidx.test.filters.SdkSuppress
import com.android.safetycenter.testing.EqualsHashCodeToStringTester
import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFails
import kotlin.test.assertFailsWith
-import org.junit.Assume.assumeFalse
import org.junit.Test
import org.junit.runner.RunWith
@@ -111,7 +110,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getAttributionTitle_returnsAttributionTitle() {
assertThat(
SafetyCenterIssue.Builder(issue1)
@@ -130,7 +129,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getAttributionTitle_withNullAttributionTitle_returnsNull() {
val safetyCenterIssue =
SafetyCenterIssue.Builder("issue_id", "Everything's good", "Please acknowledge this")
@@ -228,7 +227,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getGroupId_withNonNullValue_returnsGroupId() {
val issue = SafetyCenterIssue.Builder(issue1).setGroupId("group_id").build()
@@ -236,7 +235,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getGroupId_withNullValue_returnsNull() {
val issue =
SafetyCenterIssue.Builder("issue_id", "Everything's good", "Please acknowledge this")
@@ -247,23 +246,16 @@ class SafetyCenterIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun getGroupId_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun getGroupId_withVersionLessThanU_throws() {
val issue =
SafetyCenterIssue.Builder("issue_id", "Everything's good", "Please acknowledge this")
.build()
- val exception = assertFailsWith(UnsupportedOperationException::class) { issue.groupId }
-
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo("Method not supported for versions lower than UPSIDE_DOWN_CAKE")
+ assertFails { issue.groupId }
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setGroupId_withNullValue_returnsNull() {
val issue = SafetyCenterIssue.Builder(issue1).setGroupId(null).build()
@@ -272,19 +264,8 @@ class SafetyCenterIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun setGroupId_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
-
- val exception =
- assertFailsWith(UnsupportedOperationException::class) {
- SafetyCenterIssue.Builder(issue1).setGroupId("group_id").build()
- }
-
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo("Method not supported for versions lower than UPSIDE_DOWN_CAKE")
+ fun setGroupId_withVersionLessThanU_throws() {
+ assertFails { SafetyCenterIssue.Builder(issue1).setGroupId("group_id").build() }
}
@Test
@@ -300,7 +281,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun parcelRoundTrip_recreatesEqual_atLeastAndroidU() {
val safetyCenterIssue =
SafetyCenterIssue.Builder("issue_id", "Everything's good", "Please acknowledge this")
@@ -330,7 +311,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
newUpsideDownCakeEqualsHashCodeToStringTester().test()
}
@@ -373,21 +354,14 @@ class SafetyCenterIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun action_getConfirmationDialogDetails_withVersionLessThanU_throwsUnsupportedOperation() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
-
- assertFailsWith(UnsupportedOperationException::class) { action1.confirmationDialogDetails }
+ fun action_getConfirmationDialogDetails_withVersionLessThanU_throws() {
+ assertFails { action1.confirmationDialogDetails }
}
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun action_setConfirmationDialogDetails_withVersionLessThanU_throwsUnsupportedOperation() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
- assertFailsWith(UnsupportedOperationException::class) {
+ fun action_setConfirmationDialogDetails_withVersionLessThanU_throws() {
+ assertFails {
SafetyCenterIssue.Action.Builder("action_id", "Action label", pendingIntent1)
.setConfirmationDialogDetails(
ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -396,7 +370,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_getConfirmationDialogDetails_withDefaultBuilder_returnsNull() {
val action =
SafetyCenterIssue.Action.Builder("action_id", "Action label", pendingIntent1).build()
@@ -405,7 +379,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_getConfirmationDialogDetails_whenSetExplicitly_returnsConfirmation() {
val action =
SafetyCenterIssue.Action.Builder("action_id", "Action label", pendingIntent1)
@@ -431,7 +405,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_parcelRoundTrip_recreatesEqual_atLeastAndroidU() {
val action =
SafetyCenterIssue.Action.Builder(action1)
@@ -449,7 +423,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
issueActionNewTiramisuEqualsHashCodeToStringTester(
@@ -596,7 +570,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_getTitle_returnsTitle() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -604,7 +578,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_getText_returnsText() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -612,7 +586,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_getAcceptButtonText_returnsAcceptButtonText() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -620,7 +594,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_getDenyButtonText_returnsDenyButtonText() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -628,7 +602,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_describeContents_returns0() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -636,7 +610,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_parcelRoundTrip_recreatesEqual() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -644,7 +618,7 @@ class SafetyCenterIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
EqualsHashCodeToStringTester.ofParcelable(
parcelableCreator = ConfirmationDialogDetails.CREATOR
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
index 9f986c706..298d7643c 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
@@ -17,7 +17,6 @@
package android.safetycenter.cts
import android.content.Context
-import android.os.Build
import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.os.UserHandle.USER_NULL
@@ -40,7 +39,7 @@ import android.safetycenter.cts.testing.FakeExecutor
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.addOnSafetyCenterDataChangedListenerWithPermission
@@ -59,7 +58,6 @@ import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.set
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.setSafetySourceDataWithPermission
import com.android.safetycenter.testing.SafetyCenterEnabledChangedReceiver
import com.android.safetycenter.testing.SafetyCenterFlags
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_ALL_OPTIONAL_ID
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_BAREBONE_ID
@@ -77,6 +75,7 @@ import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.STATIC
import com.android.safetycenter.testing.SafetyCenterTestData
import com.android.safetycenter.testing.SafetyCenterTestHelper
import com.android.safetycenter.testing.SafetyCenterTestListener
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceIntentHandler.Request
import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
import com.android.safetycenter.testing.SafetySourceReceiver
@@ -89,15 +88,15 @@ import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_
import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ID
import com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
import com.android.safetycenter.testing.SafetySourceTestData.Companion.RECOMMENDATION_ISSUE_ID
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.google.common.base.Preconditions.checkState
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
+import kotlin.test.assertFails
import kotlin.test.assertFailsWith
import kotlinx.coroutines.TimeoutCancellationException
-import org.junit.After
-import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
-import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -105,36 +104,14 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SafetyCenterManagerTest {
private val context: Context = getApplicationContext()
- private val safetyCenterResourcesContext = SafetyCenterResourcesContext.forTests(context)
+ private val safetyCenterResourcesApk = SafetyCenterResourcesApk.forTests(context)
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
- // JUnit's Assume is not supported in @BeforeClass by the CTS tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
-
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
-
- @Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
- }
-
- @After
- fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
- }
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
@Test
fun isSafetyCenterEnabled_withFlagEnabled_returnsTrue() {
@@ -251,7 +228,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_wronglySignedPackage_throwsIllegalArgumentException() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceWithFakeCert)
@@ -266,7 +243,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_wronglySignedPackageButAllowedByFlag_isAllowed() {
SafetyCenterFlags.allowedAdditionalPackageCerts =
mapOf(context.packageName to setOf(safetyCenterTestConfigs.packageCertHash))
@@ -281,7 +258,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_invalidPackageCertificate_throwsIllegalArgumentException() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceWithInvalidCert)
@@ -309,9 +286,9 @@ class SafetyCenterManagerTest {
assertThat(thrown)
.hasMessageThat()
- .isEqualTo(
- "Safety source: $DYNAMIC_IN_STATELESS_ID is in a stateless group but specified a " +
- "severity level: $SEVERITY_LEVEL_INFORMATION"
+ .matches(
+ "Safety source: $DYNAMIC_IN_STATELESS_ID is in a (stateless|rigid) group but " +
+ "specified a severity level: $SEVERITY_LEVEL_INFORMATION"
)
}
@@ -834,10 +811,7 @@ class SafetyCenterManagerTest {
val enabledChangedReceiver = SafetyCenterEnabledChangedReceiver(context)
assertFailsWith(TimeoutCancellationException::class) {
- enabledChangedReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait(
- false,
- TIMEOUT_SHORT
- )
+ enabledChangedReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait(false)
}
enabledChangedReceiver.unregister()
}
@@ -874,10 +848,7 @@ class SafetyCenterManagerTest {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
assertFailsWith(TimeoutCancellationException::class) {
- SafetySourceReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait(
- false,
- TIMEOUT_SHORT
- )
+ SafetySourceReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait(false)
}
}
@@ -955,7 +926,7 @@ class SafetyCenterManagerTest {
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN,
- TIMEOUT_SHORT
+ timeout = TIMEOUT_SHORT
)
}
@@ -983,71 +954,6 @@ class SafetyCenterManagerTest {
}
@Test
- fun refreshSafetySources_reasonPageOpen_allowedByFlag_broadcastSent() {
- safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.noPageOpenConfig)
- safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
- SafetyCenterFlags.overrideRefreshOnPageOpenSources = setOf(SINGLE_SOURCE_ID)
- SafetySourceReceiver.setResponse(
- Request.Refresh(SINGLE_SOURCE_ID),
- Response.SetData(safetySourceTestData.informationWithIssue)
- )
-
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_PAGE_OPEN
- )
-
- val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
- assertThat(apiSafetySourceData).isEqualTo(safetySourceTestData.informationWithIssue)
- }
-
- @Test
- fun refreshSafetySources_reasonPageOpen_allowedByFlagLater_broadcastSentLater() {
- safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.noPageOpenConfig)
- safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
- SafetySourceReceiver.setResponse(
- Request.Refresh(SINGLE_SOURCE_ID),
- Response.SetData(safetySourceTestData.informationWithIssue)
- )
-
- assertFailsWith(TimeoutCancellationException::class) {
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_PAGE_OPEN,
- TIMEOUT_SHORT
- )
- }
- val apiSafetySourceDataBeforeSettingFlag =
- safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
- SafetyCenterFlags.overrideRefreshOnPageOpenSources = setOf(SINGLE_SOURCE_ID)
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_PAGE_OPEN
- )
- val apiSafetySourceDataAfterSettingFlag =
- safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
-
- assertThat(apiSafetySourceDataBeforeSettingFlag).isEqualTo(safetySourceTestData.information)
- assertThat(apiSafetySourceDataAfterSettingFlag)
- .isEqualTo(safetySourceTestData.informationWithIssue)
- }
-
- @Test
- fun refreshSafetySources_reasonPageOpen_noDataForSource_broadcastSent() {
- safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.noPageOpenConfig)
- SafetySourceReceiver.setResponse(
- Request.Refresh(SINGLE_SOURCE_ID),
- Response.SetData(safetySourceTestData.information)
- )
-
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_PAGE_OPEN
- )
-
- val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
- assertThat(apiSafetySourceData).isEqualTo(safetySourceTestData.information)
- }
-
- @Test
fun refreshSafetySources_whenSourceClearsData_sourceSendsNullData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
@@ -1135,8 +1041,7 @@ class SafetyCenterManagerTest {
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithoutReceiverPermissionAndWait(
- REFRESH_REASON_RESCAN_BUTTON_CLICK,
- TIMEOUT_SHORT
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
)
}
val apiSafetySourceData =
@@ -1154,7 +1059,7 @@ class SafetyCenterManagerTest {
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN,
- TIMEOUT_SHORT
+ timeout = TIMEOUT_SHORT
)
}
}
@@ -1409,7 +1314,7 @@ class SafetyCenterManagerTest {
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN,
- TIMEOUT_SHORT
+ timeout = TIMEOUT_SHORT
)
}
}
@@ -1493,7 +1398,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun refreshSafetySources_withRefreshReasonPeriodic_noBackgroundRefreshSourceDoesNotSendData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
SafetySourceReceiver.setResponse(
@@ -1505,7 +1410,7 @@ class SafetyCenterManagerTest {
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PERIODIC,
- TIMEOUT_SHORT
+ timeout = TIMEOUT_SHORT
)
}
@@ -1515,7 +1420,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun refreshSafetySources_withRefreshReasonPeriodic_backgroundRefreshSourceSendsData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
SafetySourceReceiver.setResponse(
@@ -1532,7 +1437,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun refreshSafetySources_withSafetySourceIds_onlySpecifiedSourcesSendData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
SafetySourceReceiver.apply {
@@ -1567,7 +1472,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun refreshSafetySources_withEmptySafetySourceIds_noSourcesSendData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
SafetySourceReceiver.setResponse(
@@ -1578,8 +1483,8 @@ class SafetyCenterManagerTest {
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN,
- TIMEOUT_SHORT,
- emptyList()
+ safetySourceIds = emptyList(),
+ timeout = TIMEOUT_SHORT,
)
}
@@ -1589,27 +1494,19 @@ class SafetyCenterManagerTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun refreshSafetySources_versionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun refreshSafetySources_versionLessThanU_throws() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
- val exception =
- assertFailsWith(UnsupportedOperationException::class) {
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_PAGE_OPEN,
- safetySourceIds = listOf(SOURCE_ID_1, SOURCE_ID_3)
- )
- }
-
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo("Method not supported for versions lower than UPSIDE_DOWN_CAKE")
+ assertFails {
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN,
+ safetySourceIds = listOf(SOURCE_ID_1, SOURCE_ID_3)
+ )
+ }
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun refreshSafetySources_withSafetySourceIds_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.refreshSafetySources(REFRESH_REASON_PAGE_OPEN, listOf())
@@ -2059,7 +1956,7 @@ class SafetyCenterManagerTest {
assertThat(error)
.isEqualTo(
SafetyCenterErrorDetails(
- safetyCenterResourcesContext.getStringByName("redirecting_error")
+ safetyCenterResourcesApk.getStringByName("redirecting_error")
)
)
}
@@ -2085,7 +1982,7 @@ class SafetyCenterManagerTest {
assertThat(error)
.isEqualTo(
SafetyCenterErrorDetails(
- safetyCenterResourcesContext.getStringByName("resolving_action_error")
+ safetyCenterResourcesApk.getStringByName("resolving_action_error")
)
)
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt
index 695265059..d882fc3cb 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt
@@ -42,12 +42,12 @@ import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.rep
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.setSafetyCenterConfigForTestsWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.setSafetySourceDataWithPermission
import com.android.safetycenter.testing.SafetyCenterEnabledChangedReceiver
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
import com.android.safetycenter.testing.SafetyCenterTestData
import com.android.safetycenter.testing.SafetyCenterTestHelper
import com.android.safetycenter.testing.SafetyCenterTestListener
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceReceiver
import com.android.safetycenter.testing.SafetySourceReceiver.Companion.executeSafetyCenterIssueActionWithPermissionAndWait
import com.android.safetycenter.testing.SafetySourceReceiver.Companion.refreshSafetySourcesWithReceiverPermissionAndWait
@@ -56,14 +56,13 @@ import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_
import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ID
import com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
import com.android.safetycenter.testing.SettingsPackage.getSettingsPackageName
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
import kotlin.test.assertFailsWith
import kotlinx.coroutines.TimeoutCancellationException
-import org.junit.After
import org.junit.Assume.assumeTrue
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -72,39 +71,17 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SafetyCenterUnsupportedTest {
- @get:Rule val disableAnimationRule = DisableAnimationRule()
-
- @get:Rule val freezeRotationRule = FreezeRotationRule()
-
private val context: Context = getApplicationContext()
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
- // JUnit's Assume is not supported in @BeforeClass by the CTS tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = !context.deviceSupportsSafetyCenter()
-
- @Before
- fun assumeDeviceDoesntSupportSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
-
- @Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
- }
- @After
- fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
- }
+ @get:Rule(order = 1)
+ val supportsSafetyCenterRule = SupportsSafetyCenterRule(context, requireSupportIs = false)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+ @get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
@Test
fun launchActivity_opensSettings() {
@@ -238,7 +215,7 @@ class SafetyCenterUnsupportedTest {
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN,
- TIMEOUT_SHORT
+ timeout = TIMEOUT_SHORT
)
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
index 3dec4f509..4d1cb6a8b 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
@@ -16,7 +16,7 @@
package android.safetycenter.cts
-import android.os.Build
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.SafetyEvent
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED
@@ -190,7 +190,7 @@ class SafetyEventTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
newTiramisuEqualsHashCodeToStringTester(
createCopyFromBuilder = { SafetyEvent.Builder(it).build() }
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt
index d7208c098..ba2ab3d76 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt
@@ -20,7 +20,7 @@ import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context
import android.content.Intent
-import android.os.Build
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.os.Bundle
import android.safetycenter.SafetySourceData
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
@@ -96,7 +96,7 @@ class SafetySourceDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getExtras_withDefaultBuilder_returnsEmptyBundle() {
val safetySourceData =
SafetySourceData.Builder().setStatus(createStatus(SEVERITY_LEVEL_INFORMATION)).build()
@@ -105,7 +105,7 @@ class SafetySourceDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getExtras_whenSetExplicitly_returnsExtras() {
val safetySourceData =
SafetySourceData.Builder()
@@ -118,7 +118,7 @@ class SafetySourceDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getExtras_whenCleared_returnsEmptyBundle() {
val safetySourceData =
SafetySourceData.Builder()
@@ -325,7 +325,7 @@ class SafetySourceDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun parcelRoundTrip_withExtras_recreatesEqual() {
val safetySourceData =
SafetySourceData.Builder()
@@ -384,7 +384,7 @@ class SafetySourceDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun equalsHashCode_atLeastU_usingEqualsHashCodeToStringTester() {
val firstStatus = createStatus(SEVERITY_LEVEL_INFORMATION, 1)
val secondStatus = createStatus(SEVERITY_LEVEL_INFORMATION, 2)
@@ -454,7 +454,7 @@ class SafetySourceDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun toString_withExtras_containsHasExtras() {
val safetySourceDataWithExtras =
SafetySourceData.Builder()
@@ -468,7 +468,7 @@ class SafetySourceDataTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun toString_withoutExtras_doesNotContainHasExtras() {
val safetySourceDataWithoutExtras =
SafetySourceData.Builder().setStatus(createStatus(SEVERITY_LEVEL_INFORMATION)).build()
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt
index 4749c3616..2d19a3175 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt
@@ -20,7 +20,6 @@ import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context
import android.content.Intent
-import android.os.Build
import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
@@ -42,8 +41,8 @@ import androidx.test.filters.SdkSuppress
import com.android.modules.utils.build.SdkLevel
import com.android.safetycenter.testing.EqualsHashCodeToStringTester
import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFails
import kotlin.test.assertFailsWith
-import org.junit.Assume.assumeFalse
import org.junit.Test
import org.junit.runner.RunWith
@@ -119,22 +118,16 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun action_getConfirmationDialogDetails_withVersionLessThanU_throwsUnsupportedOperation() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun action_getConfirmationDialogDetails_withVersionLessThanU_throws() {
val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
- assertFailsWith(UnsupportedOperationException::class) { action.confirmationDialogDetails }
+ assertFails { action.confirmationDialogDetails }
}
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun action_setConfirmationDialogDetails_withVersionLessThanU_throwsUnsupportedOperation() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
- assertFailsWith(UnsupportedOperationException::class) {
+ fun action_setConfirmationDialogDetails_withVersionLessThanU_throws() {
+ assertFails {
Action.Builder("action_id", "Action label", pendingIntent1)
.setConfirmationDialogDetails(
ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -143,7 +136,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_getConfirmationDialogDetails_withDefaultBuilder_returnsNull() {
val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
@@ -151,7 +144,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_getConfirmationDialogDetails_whenSetExplicitly_returnsConfirmation() {
val action =
Action.Builder("action_id", "Action label", pendingIntent1)
@@ -186,7 +179,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_build_withActivityPendingIntentAndWillResolve_throwsIllegalArgumentException() {
assertFailsWith(IllegalArgumentException::class) {
Action.Builder("action_id", "Action label", pendingIntent1).setWillResolve(true).build()
@@ -211,7 +204,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_parcelRoundTrip_recreatesEqual_atLeastAndroidU() {
val action =
Action.Builder("action_id", "Action label", pendingIntent1)
@@ -229,7 +222,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun action_equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
actionNewTiramisuEqualsHashCodeToStringTester(
@@ -293,7 +286,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_getTitle_returnsTitle() {
val notification = Notification.Builder("Notification title", "Notification text").build()
@@ -301,7 +294,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_getText_returnsText() {
val notification = Notification.Builder("Notification title", "Notification text").build()
@@ -309,7 +302,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_getActions_withDefaultBuilder_returnsEmptyList() {
val notification = Notification.Builder("", "").build()
@@ -317,7 +310,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_getActions_returnsActions() {
val notification =
Notification.Builder("", "").addAction(action1).addAction(action2).build()
@@ -326,7 +319,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_getActions_mutationsAreNotAllowed() {
val notification =
Notification.Builder("", "").addAction(action1).addAction(action2).build()
@@ -335,7 +328,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_describeContents_returns0() {
val notification =
Notification.Builder("Notification title", "Notification text")
@@ -347,7 +340,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_parcelRoundTrip_recreatesEqual() {
val notification =
Notification.Builder("Notification title", "Notification text")
@@ -359,7 +352,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_builder_withNullTitle_throwsNullPointerException() {
assertFailsWith(NullPointerException::class) {
Notification.Builder(Generic.asNull(), "Notification text")
@@ -367,7 +360,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_builder_withNullText_throwsNullPointerException() {
assertFailsWith(NullPointerException::class) {
Notification.Builder("Notification title", Generic.asNull())
@@ -375,7 +368,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_builder_addAction_doesNotMutatePreviouslyBuiltInstance() {
val notificationBuilder = Notification.Builder("", "").addAction(action1)
val actions = notificationBuilder.build().actions
@@ -386,7 +379,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_builder_addAction_withNull_throwsIllegalArgumentException() {
assertFailsWith(NullPointerException::class) {
Notification.Builder("", "").addAction(Generic.asNull())
@@ -394,7 +387,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_builder_addActions_keepsPreviouslyAddedActions() {
val notificationBuilder = Notification.Builder("", "").addAction(action1)
@@ -404,7 +397,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_builder_addActions_doesNotMutatePreviouslyBuiltInstance() {
val notificationBuilder = Notification.Builder("", "").addActions(listOf(action1))
val actions = notificationBuilder.build().actions
@@ -415,7 +408,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_builder_addActions_withNull_throwsIllegalArgumentException() {
assertFailsWith(NullPointerException::class) {
Notification.Builder("", "").addActions(Generic.asNull())
@@ -423,7 +416,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_builder_clearActions_removesAllActions() {
val notification =
Notification.Builder("", "")
@@ -437,7 +430,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_build_withDuplicateActionIds_throwsIllegalArgumentException() {
val notificationBuilder =
Notification.Builder("Notification title", "Notification text")
@@ -452,7 +445,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_build_withMoreThanTwoActions_throwsIllegalArgumentException() {
val notificationBuilder =
Notification.Builder("Notification title", "Notification text")
@@ -468,7 +461,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun notification_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
EqualsHashCodeToStringTester.ofParcelable(
parcelableCreator = Notification.CREATOR,
@@ -490,7 +483,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_getTitle_returnsTitle() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -498,7 +491,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_getText_returnsText() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -506,7 +499,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_getAcceptButtonText_returnsAcceptButtonText() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -514,7 +507,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_getDenyButtonText_returnsDenyButtonText() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -522,7 +515,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_describeContents_returns0() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -530,7 +523,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_parcelRoundTrip_recreatesEqual() {
val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
@@ -538,7 +531,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun actionConfirmation_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
EqualsHashCodeToStringTester.ofParcelable(
parcelableCreator = ConfirmationDialogDetails.CREATOR
@@ -636,7 +629,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getAttributionTitle_withNullAttributionTitle_returnsNull() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -653,7 +646,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getAttributionTitle_returnsAttributionTitle() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -672,10 +665,7 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun getAttributionTitle_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun getAttributionTitle_withVersionLessThanU_throws() {
val safetySourceIssue =
SafetySourceIssue.Builder(
"Issue id",
@@ -687,15 +677,12 @@ class SafetySourceIssueTest {
.addAction(action1)
.build()
- assertFailsWith(UnsupportedOperationException::class) { safetySourceIssue.attributionTitle }
+ assertFails { safetySourceIssue.attributionTitle }
}
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun setAttributionTitle_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun setAttributionTitle_withVersionLessThanU_throws() {
val safetySourceIssueBuilder =
SafetySourceIssue.Builder(
"Issue id",
@@ -705,9 +692,7 @@ class SafetySourceIssueTest {
"issue_type_id"
)
- assertFailsWith(UnsupportedOperationException::class) {
- safetySourceIssueBuilder.setAttributionTitle("title")
- }
+ assertFails { safetySourceIssueBuilder.setAttributionTitle("title") }
}
@Test
@@ -760,7 +745,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getIssueCategory_whenSetExplicitlyWithUValueOnU_returnsIssueCategory() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -884,7 +869,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getDeduplicationId_withDefaultBuilder_returnsNull() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -901,7 +886,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getDeduplicationId_whenSetExplicitly_returnsDeduplicationId() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -920,10 +905,7 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun getDeduplicationId_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun getDeduplicationId_withVersionLessThanU_throws() {
val safetySourceIssue =
SafetySourceIssue.Builder(
"Issue id",
@@ -935,15 +917,12 @@ class SafetySourceIssueTest {
.addAction(action1)
.build()
- assertFailsWith(UnsupportedOperationException::class) { safetySourceIssue.deduplicationId }
+ assertFails { safetySourceIssue.deduplicationId }
}
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun setDeduplicationId_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun setDeduplicationId_withVersionLessThanU_throws() {
val safetySourceIssueBuilder =
SafetySourceIssue.Builder(
"Issue id",
@@ -953,9 +932,7 @@ class SafetySourceIssueTest {
"issue_type_id"
)
- assertFailsWith(UnsupportedOperationException::class) {
- safetySourceIssueBuilder.setDeduplicationId("id")
- }
+ assertFails { safetySourceIssueBuilder.setDeduplicationId("id") }
}
@Test
@@ -975,7 +952,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getCustomNotification_withDefaultBuilder_returnsNull() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -992,7 +969,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getCustomNotification_whenSetExplicitly_returnsCustomNotification() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1020,10 +997,7 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun getCustomNotification_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun getCustomNotification_withVersionLessThanU_throws() {
val safetySourceIssue =
SafetySourceIssue.Builder(
"Issue id",
@@ -1035,17 +1009,12 @@ class SafetySourceIssueTest {
.addAction(action1)
.build()
- assertFailsWith(UnsupportedOperationException::class) {
- safetySourceIssue.customNotification
- }
+ assertFails { safetySourceIssue.customNotification }
}
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun setCustomNotification_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun setCustomNotification_withVersionLessThanU_throws() {
val safetySourceIssueBuilder =
SafetySourceIssue.Builder(
"Issue id",
@@ -1055,13 +1024,11 @@ class SafetySourceIssueTest {
"issue_type_id"
)
- assertFailsWith(UnsupportedOperationException::class) {
- safetySourceIssueBuilder.setCustomNotification(null)
- }
+ assertFails { safetySourceIssueBuilder.setCustomNotification(null) }
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getNotificationBehavior_withDefaultBuilder_returnsUnspecified() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1079,7 +1046,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getNotificationBehavior_whenSetExplicitly_returnsSpecifiedBehavior() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1099,10 +1066,7 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun getNotificationBehavior_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun getNotificationBehavior_withVersionLessThanU_throws() {
val safetySourceIssue =
SafetySourceIssue.Builder(
"Issue id",
@@ -1114,13 +1078,11 @@ class SafetySourceIssueTest {
.addAction(action1)
.build()
- assertFailsWith(UnsupportedOperationException::class) {
- safetySourceIssue.notificationBehavior
- }
+ assertFails { safetySourceIssue.notificationBehavior }
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setNotificationBehavior_withInvalidNotificationBehavior_throwsIllegalArgumentException() {
val builder =
SafetySourceIssue.Builder(
@@ -1141,10 +1103,7 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun setNotificationBehavior_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun setNotificationBehavior_withVersionLessThanU_throws() {
val safetySourceIssueBuilder =
SafetySourceIssue.Builder(
"Issue id",
@@ -1154,13 +1113,11 @@ class SafetySourceIssueTest {
"issue_type_id"
)
- assertFailsWith(UnsupportedOperationException::class) {
- safetySourceIssueBuilder.setNotificationBehavior(0)
- }
+ assertFails { safetySourceIssueBuilder.setNotificationBehavior(0) }
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getIssueActionability_withDefaultBuilder_returnsManual() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1178,7 +1135,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getIssueActionability_whenSetExplicitly_returnsValueSet() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1198,10 +1155,7 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun getIssueActionability_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun getIssueActionability_withVersionLessThanU_throws() {
val safetySourceIssue =
SafetySourceIssue.Builder(
"Issue id",
@@ -1213,13 +1167,11 @@ class SafetySourceIssueTest {
.addAction(action1)
.build()
- assertFailsWith(UnsupportedOperationException::class) {
- safetySourceIssue.issueActionability
- }
+ assertFails { safetySourceIssue.issueActionability }
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setIssueActionability_withInvalidIssueActionability_throwsIllegalArgumentException() {
val builder =
SafetySourceIssue.Builder(
@@ -1240,10 +1192,7 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
- fun setIssueActionability_withVersionLessThanU_throwsUnsupportedOperationException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
+ fun setIssueActionability_withVersionLessThanU_throws() {
val safetySourceIssueBuilder =
SafetySourceIssue.Builder(
"Issue id",
@@ -1253,9 +1202,7 @@ class SafetySourceIssueTest {
"issue_type_id"
)
- assertFailsWith(UnsupportedOperationException::class) {
- safetySourceIssueBuilder.setIssueActionability(0)
- }
+ assertFails { safetySourceIssueBuilder.setIssueActionability(0) }
}
@Test
@@ -1366,9 +1313,6 @@ class SafetySourceIssueTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
fun build_withUIssueCategoryValueOnT_throwsIllegalArgumentException() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
val builder =
SafetySourceIssue.Builder(
"Issue id",
@@ -1480,7 +1424,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun build_withNoActionsAndManualActionabilityOnU_throwsIllegalArgumentException() {
val safetySourceIssueBuilder =
SafetySourceIssue.Builder(
@@ -1500,7 +1444,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun build_withNoActionsAndTipActionabilityOnU_success() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1517,7 +1461,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun build_withNoActionsAndAutomaticActionabilityOnU_success() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1574,7 +1518,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun parcelRoundTrip_recreatesEqual_atLeastAndroidU() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1601,7 +1545,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun parcelRoundTrip_recreatesEqual_atLeastUpsideDownCake() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -1636,7 +1580,7 @@ class SafetySourceIssueTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastUpsideDownCake() {
newUpsideDownCakeEqualsHashCodeToStringTester().test()
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt
index 5aeea21f1..2a20cd45d 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt
@@ -20,7 +20,7 @@ import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context
import android.content.Intent
-import android.os.Build
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
@@ -285,7 +285,7 @@ class SafetySourceStatusTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
newTiramisuEqualsHashCodeToStringTester(
createCopyFromBuilder = { SafetySourceStatus.Builder(it).build() }
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt
index 7dff9dd54..68dcd4a11 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt
@@ -16,7 +16,7 @@
package android.safetycenter.cts.config
-import android.os.Build
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.config.SafetyCenterConfig
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.truth.os.ParcelableSubject.assertThat
@@ -86,7 +86,7 @@ class SafetyCenterConfigTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
newTiramisuEqualsHashCodeToStringTester(
createCopyFromBuilder = { SafetyCenterConfig.Builder(it).build() }
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt
index 055e82ad3..59cc6547a 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt
@@ -17,7 +17,7 @@
package android.safetycenter.cts.config
import android.content.res.Resources
-import android.os.Build
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.config.SafetySource
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.truth.os.ParcelableSubject.assertThat
@@ -75,7 +75,7 @@ class SafetySourceTest {
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getOptionalPackageName_returnsPackageNameOrNull() {
assertThat(DYNAMIC_BAREBONE.optionalPackageName).isEqualTo(PACKAGE_NAME)
assertThat(dynamicAllOptional().optionalPackageName).isEqualTo(PACKAGE_NAME)
@@ -259,7 +259,7 @@ class SafetySourceTest {
assertThat(issueOnlyAllOptional().isRefreshOnPageOpenAllowed).isEqualTo(true)
}
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
@Test
fun areNotificationsAllowed_returnsNotificationsAllowed() {
assertThat(DYNAMIC_BAREBONE.areNotificationsAllowed()).isFalse()
@@ -273,7 +273,7 @@ class SafetySourceTest {
assertThat(issueOnlyAllOptional().areNotificationsAllowed()).isTrue()
}
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
@Test
fun getDeduplicationGroupsList_returnsDeduplicationGroups() {
assertThat(DYNAMIC_BAREBONE.deduplicationGroup).isNull()
@@ -287,7 +287,7 @@ class SafetySourceTest {
assertThat(issueOnlyAllOptional().deduplicationGroup).isEqualTo(DEDUPLICATION_GROUP)
}
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
@Test
fun getPackageCertificateHashes_returnsPackageCerts() {
assertThat(DYNAMIC_BAREBONE.packageCertificateHashes).isEmpty()
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt
index 015d18842..f741369eb 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt
@@ -211,7 +211,7 @@ class SafetySourcesGroupTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun build_hiddenGroupWithDynamicSource_throwsIllegalStateException() {
val builder =
SafetySourcesGroup.Builder()
@@ -228,7 +228,7 @@ class SafetySourcesGroupTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun build_hiddenGroupWithStaticSource_throwsIllegalStateException() {
val builder =
SafetySourcesGroup.Builder()
@@ -245,7 +245,7 @@ class SafetySourcesGroupTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun build_statefulGroupWithIssueOnlySource_throwsIllegalStateException() {
val builder =
SafetySourcesGroup.Builder()
@@ -264,7 +264,7 @@ class SafetySourcesGroupTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun build_statelessGroupWithIssueOnlySource_throwsIllegalStateException() {
val builder =
SafetySourcesGroup.Builder()
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt
index 32959629c..7c9e2cffc 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt
@@ -24,15 +24,14 @@ import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.safetycenter.config.SafetyCenterConfigParser
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterConfigWithPermission
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
-import org.junit.After
-import org.junit.Assume.assumeTrue
-import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,33 +39,12 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class XmlConfigTest {
private val context: Context = getApplicationContext()
- private val safetyCenterContext = SafetyCenterResourcesContext.forTests(context)
- private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
+ private val safetyCenterResourcesApk = SafetyCenterResourcesApk.forTests(context)
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
- // JUnit's Assume is not supported in @BeforeClass by the CTS tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
-
- @Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
- }
-
- @After
- fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
- }
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2)
+ val safetyCenterTestRule = SafetyCenterTestRule(SafetyCenterTestHelper(context))
@Test
fun safetyCenterConfigResource_validConfig() {
@@ -93,7 +71,7 @@ class XmlConfigTest {
}
private fun assertThatIntentResolves(intentAction: String) {
- val pm = safetyCenterContext.packageManager
+ val pm = context.packageManager
assertWithMessage("Intent '%s' cannot be resolved.", intentAction)
.that(pm.queryIntentActivities(Intent(intentAction), ResolveInfoFlags.of(0)))
.isNotEmpty()
@@ -109,8 +87,8 @@ class XmlConfigTest {
private fun parseXmlConfig() =
SafetyCenterConfigParser.parseXmlResource(
- safetyCenterContext.safetyCenterConfig!!,
- safetyCenterContext.resources!!
+ safetyCenterResourcesApk.safetyCenterConfig!!,
+ safetyCenterResourcesApk.resources
)
companion object {
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt
index 8fb56b09e..111f01243 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt
@@ -24,15 +24,14 @@ import com.android.compatibility.common.util.DisableAnimationRule
import com.android.compatibility.common.util.FreezeRotationRule
import com.android.compatibility.common.util.UiAutomatorUtils2.getUiDevice
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SettingsPackage.getSettingsPackageName
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.android.safetycenter.testing.UiTestHelper.resetRotation
import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitPageTitleDisplayed
import org.junit.After
-import org.junit.Assume.assumeTrue
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -41,36 +40,16 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SafetyCenterActivityTest {
- @get:Rule val disableAnimationRule = DisableAnimationRule()
-
- @get:Rule val freezeRotationRule = FreezeRotationRule()
-
private val context: Context = getApplicationContext()
-
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
- // JUnit's Assume is not supported in @BeforeClass by the CTS tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
-
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
- @Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
- }
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+ @get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
@After
fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
getUiDevice().resetRotation()
}
diff --git a/tests/functional/safetycenter/multiusers/AndroidTest.xml b/tests/functional/safetycenter/multiusers/AndroidTest.xml
index c1e19d2e4..20032357a 100644
--- a/tests/functional/safetycenter/multiusers/AndroidTest.xml
+++ b/tests/functional/safetycenter/multiusers/AndroidTest.xml
@@ -43,9 +43,12 @@
aren't polluted by `BOOT_COMPLETED` or similar broadcasts still being delivered, which
causes our `ActivityManager#waitForBroadcastIdle()` calls to timeout. -->
<option name="run-command" value="am wait-for-broadcast-idle" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
<!-- 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" />
+ <!-- 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>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
diff --git a/tests/functional/safetycenter/multiusers/TEST_MAPPING b/tests/functional/safetycenter/multiusers/TEST_MAPPING
index aedf92b86..65f53b453 100644
--- a/tests/functional/safetycenter/multiusers/TEST_MAPPING
+++ b/tests/functional/safetycenter/multiusers/TEST_MAPPING
@@ -1,30 +1,11 @@
{
- "presubmit": [
- {
- "name": "SafetyCenterFunctionalMultiUsersTestCases",
- "options": [
- {
- "exclude-annotation": "com.android.bedstead.harrier.annotations.Postsubmit"
- }
- ]
- }
- ],
"postsubmit": [
+ // Note that these test cases are running in postsubmit only. Bedstead tests can be pretty slow
+ // (due to adding/removing users, which makes the device somewhat unresponsive). This can also
+ // cause flakyness due to timeouts. In postsubmit, these tests have more time to run which makes
+ // them less flaky (and this flakyness is arguably less of an issue in this case).
{
"name": "SafetyCenterFunctionalMultiUsersTestCases"
}
- ],
- "mainline-presubmit": [
- {
- "name": "SafetyCenterFunctionalMultiUsersTestCases[com.google.android.permission.apex]",
- "options": [
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "exclude-annotation": "com.android.bedstead.harrier.annotations.Postsubmit"
- }
- ]
- }
]
}
diff --git a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
index 07ae129ec..acbc5cfc0 100644
--- a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
+++ b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
@@ -20,9 +20,9 @@ import android.Manifest.permission.INTERACT_ACROSS_USERS
import android.Manifest.permission.INTERACT_ACROSS_USERS_FULL
import android.app.PendingIntent
import android.content.Context
-import android.content.Intent
import android.os.UserHandle
import android.safetycenter.SafetyCenterData
+import android.safetycenter.SafetyCenterEntry
import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN
import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED
@@ -30,32 +30,35 @@ import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_
import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
import android.safetycenter.SafetyCenterEntryGroup
import android.safetycenter.SafetyCenterEntryOrGroup
+import android.safetycenter.SafetyCenterIssue
import android.safetycenter.SafetyCenterManager
import android.safetycenter.SafetyCenterStaticEntry
import android.safetycenter.SafetyCenterStaticEntryGroup
import android.safetycenter.SafetyEvent
import android.safetycenter.SafetySourceData
import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
import com.android.bedstead.harrier.BedsteadJUnit4
import com.android.bedstead.harrier.DeviceState
import com.android.bedstead.harrier.annotations.EnsureHasAdditionalUser
import com.android.bedstead.harrier.annotations.EnsureHasCloneProfile
import com.android.bedstead.harrier.annotations.EnsureHasNoWorkProfile
import com.android.bedstead.harrier.annotations.EnsureHasWorkProfile
-import com.android.bedstead.harrier.annotations.Postsubmit
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner
import com.android.bedstead.nene.TestApis
import com.android.bedstead.nene.types.OptionalBoolean.TRUE
import com.android.compatibility.common.util.DisableAnimationRule
import com.android.compatibility.common.util.FreezeRotationRule
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
+import com.android.safetycenter.testing.NotificationCharacteristics
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterDataWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetySourceDataWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.setSafetySourceDataWithPermission
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
+import com.android.safetycenter.testing.SafetyCenterFlags
import com.android.safetycenter.testing.SafetyCenterTestConfigs
-import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ACTION_TEST_ACTIVITY
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_BAREBONE_ID
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_DISABLED_ID
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_GROUP_ID
@@ -76,27 +79,30 @@ import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.STATIC
import com.android.safetycenter.testing.SafetyCenterTestData
import com.android.safetycenter.testing.SafetyCenterTestData.Companion.withoutExtras
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceTestData
import com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.ISSUE_TYPE_ID
import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
+import com.android.safetycenter.testing.TestNotificationListener
import com.android.safetycenter.testing.UiTestHelper.waitAllTextDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitAllTextNotDisplayed
import com.google.common.base.Preconditions.checkState
import com.google.common.truth.Truth.assertThat
import kotlin.test.assertFailsWith
import org.junit.After
-import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.ClassRule
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
/**
* Functional tests for our APIs and UI on a device with multiple users. e.g. with a managed or
- * secondary user(s).
+ * additional user(s).
*/
+@LargeTest
@RunWith(BedsteadJUnit4::class)
class SafetyCenterMultiUsersTest {
@@ -104,70 +110,65 @@ class SafetyCenterMultiUsersTest {
@JvmField @ClassRule @Rule val deviceState: DeviceState = DeviceState()
}
- @get:Rule val disableAnimationRule = DisableAnimationRule()
-
- @get:Rule val freezeRotationRule = FreezeRotationRule()
-
private val context: Context = ApplicationProvider.getApplicationContext()
- private val safetyCenterResourcesContext = SafetyCenterResourcesContext.forTests(context)
+ private val safetyCenterResourcesApk = SafetyCenterResourcesApk.forTests(context)
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestData = SafetyCenterTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
- // JUnit's Assume is not supported in @BeforeClass by the CTS tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
private var inQuietMode = false
- private val primaryProfileOnlyIssues =
- listOf(
- safetyCenterTestData.safetyCenterIssueCritical(
- DYNAMIC_BAREBONE_ID,
- groupId = DYNAMIC_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueCritical(
- ISSUE_ONLY_BAREBONE_ID,
- attributionTitle = null,
- groupId = ISSUE_ONLY_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueRecommendation(
- DYNAMIC_DISABLED_ID,
- groupId = DYNAMIC_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueRecommendation(
- ISSUE_ONLY_ALL_OPTIONAL_ID,
- attributionTitle = null,
- groupId = ISSUE_ONLY_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueInformation(
- DYNAMIC_IN_STATELESS_ID,
- groupId = MIXED_STATELESS_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueInformation(
- ISSUE_ONLY_IN_STATELESS_ID,
- groupId = MIXED_STATELESS_GROUP_ID
+ private val primaryProfileOnlyIssues: List<SafetyCenterIssue>
+ get() =
+ listOf(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ DYNAMIC_BAREBONE_ID,
+ groupId = DYNAMIC_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueCritical(
+ ISSUE_ONLY_BAREBONE_ID,
+ attributionTitle = null,
+ groupId = ISSUE_ONLY_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ DYNAMIC_DISABLED_ID,
+ groupId = DYNAMIC_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ attributionTitle = null,
+ groupId = ISSUE_ONLY_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ DYNAMIC_IN_STATELESS_ID,
+ groupId = MIXED_STATELESS_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ ISSUE_ONLY_IN_STATELESS_ID,
+ groupId = MIXED_STATELESS_GROUP_ID
+ )
)
- )
- private val dynamicBareboneDefault =
- safetyCenterTestData.safetyCenterEntryDefault(DYNAMIC_BAREBONE_ID)
+ private val dynamicBareboneDefault: SafetyCenterEntry
+ get() = safetyCenterTestData.safetyCenterEntryDefault(DYNAMIC_BAREBONE_ID)
- private val dynamicBareboneUpdated =
- safetyCenterTestData.safetyCenterEntryCritical(DYNAMIC_BAREBONE_ID)
+ private val dynamicBareboneUpdated: SafetyCenterEntry
+ get() = safetyCenterTestData.safetyCenterEntryCritical(DYNAMIC_BAREBONE_ID)
- private val dynamicDisabledDefault =
- safetyCenterTestData
- .safetyCenterEntryDefaultBuilder(DYNAMIC_DISABLED_ID)
- .setPendingIntent(null)
- .setEnabled(false)
- .build()
+ private val dynamicDisabledDefault: SafetyCenterEntry
+ get() =
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(DYNAMIC_DISABLED_ID)
+ .setPendingIntent(null)
+ .setEnabled(false)
+ .build()
- private val dynamicDisabledUpdated =
- safetyCenterTestData.safetyCenterEntryRecommendation(DYNAMIC_DISABLED_ID)
+ private val dynamicDisabledUpdated: SafetyCenterEntry
+ get() = safetyCenterTestData.safetyCenterEntryRecommendation(DYNAMIC_DISABLED_ID)
- private val dynamicDisabledForWorkDefaultBuilder
+ private val dynamicDisabledForWorkDefaultBuilder: SafetyCenterEntry.Builder
get() =
safetyCenterTestData
.safetyCenterEntryDefaultBuilder(
@@ -178,26 +179,54 @@ class SafetyCenterMultiUsersTest {
.setPendingIntent(null)
.setEnabled(false)
- private val dynamicDisabledForWorkDefault
+ private val dynamicDisabledForWorkDefault: SafetyCenterEntry
get() = dynamicDisabledForWorkDefaultBuilder.build()
- private val dynamicDisabledForWorkPaused
+ private val dynamicDisabledForWorkPausedUpdated: SafetyCenterEntry
get() =
- dynamicDisabledForWorkDefaultBuilder
- // TODO(b/233188021): This needs to use the Enterprise API to override the "work"
- // keyword.
- .setSummary(safetyCenterResourcesContext.getStringByName("work_profile_paused"))
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(
+ DYNAMIC_DISABLED_ID,
+ deviceState.workProfile().id(),
+ title = "Ok title for Work",
+ pendingIntent = null
+ )
+ .setSummary(
+ safetyCenterResourcesApk.getStringByName("work_profile_paused"),
+ )
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
+ .setEnabled(false)
.build()
- private val dynamicDisabledForWorkUpdated
+ private val dynamicDisabledForWorkUpdated: SafetyCenterEntry
get() = safetyCenterEntryOkForWork(DYNAMIC_DISABLED_ID, deviceState.workProfile().id())
- private val dynamicHiddenUpdated =
- safetyCenterTestData.safetyCenterEntryUnspecified(DYNAMIC_HIDDEN_ID, pendingIntent = null)
+ private val dynamicHiddenUpdated: SafetyCenterEntry
+ get() =
+ safetyCenterTestData.safetyCenterEntryUnspecified(
+ DYNAMIC_HIDDEN_ID,
+ pendingIntent = null
+ )
- private val dynamicHiddenForWorkUpdated
+ private val dynamicHiddenForWorkUpdated: SafetyCenterEntry
get() = safetyCenterEntryOkForWork(DYNAMIC_HIDDEN_ID, deviceState.workProfile().id())
+ private val dynamicHiddenForWorkPausedUpdated
+ get() =
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(
+ DYNAMIC_HIDDEN_ID,
+ deviceState.workProfile().id(),
+ title = "Ok title for Work",
+ pendingIntent = null
+ )
+ .setSummary(
+ safetyCenterResourcesApk.getStringByName("work_profile_paused"),
+ )
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
+ .setEnabled(false)
+ .build()
+
private val staticGroupBuilder =
SafetyCenterEntryGroup.Builder(STATIC_GROUP_ID, "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
@@ -223,7 +252,8 @@ class SafetyCenterMultiUsersTest {
)
.setPendingIntent(
createTestActivityRedirectPendingIntentForUser(
- deviceState.workProfile().userHandle()
+ deviceState.workProfile().userHandle(),
+ explicit = false
)
)
@@ -233,50 +263,55 @@ class SafetyCenterMultiUsersTest {
private val staticAllOptionalForWorkPaused
get() =
staticAllOptionalForWorkBuilder
- // TODO(b/233188021): This needs to use the Enterprise API to override the "work"
- // keyword.
- .setSummary(safetyCenterResourcesContext.getStringByName("work_profile_paused"))
+ .setSummary(safetyCenterResourcesApk.getStringByName("work_profile_paused"))
.setEnabled(false)
.build()
- private val staticEntry =
+ private fun createStaticEntry(explicit: Boolean = true): SafetyCenterStaticEntry =
SafetyCenterStaticEntry.Builder("OK")
.setSummary("OK")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
- .build()
-
- private val staticEntryUpdated =
- SafetyCenterStaticEntry.Builder("Unspecified title")
- .setSummary("Unspecified summary")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent(explicit)
+ )
.build()
- private val staticEntryForWorkBuilder
+ private val staticEntryUpdated: SafetyCenterStaticEntry
get() =
- SafetyCenterStaticEntry.Builder("Paste")
- .setSummary("OK")
- .setPendingIntent(
- createTestActivityRedirectPendingIntentForUser(
- deviceState.workProfile().userHandle()
- )
+ SafetyCenterStaticEntry.Builder("Unspecified title")
+ .setSummary("Unspecified summary")
+ .setPendingIntent(safetySourceTestData.createTestActivityRedirectPendingIntent())
+ .build()
+
+ private fun staticEntryForWorkBuilder(title: CharSequence = "Paste", explicit: Boolean = true) =
+ SafetyCenterStaticEntry.Builder(title)
+ .setSummary("OK")
+ .setPendingIntent(
+ createTestActivityRedirectPendingIntentForUser(
+ deviceState.workProfile().userHandle(),
+ explicit
)
+ )
- private val staticEntryForWork
- get() = staticEntryForWorkBuilder.build()
+ private fun createStaticEntryForWork(explicit: Boolean = true): SafetyCenterStaticEntry =
+ staticEntryForWorkBuilder(explicit = explicit).build()
- private val staticEntryForWorkPaused
+ private fun createStaticEntryForWorkPaused(): SafetyCenterStaticEntry =
+ staticEntryForWorkBuilder(explicit = false)
+ .setSummary(safetyCenterResourcesApk.getStringByName("work_profile_paused"))
+ .build()
+
+ private val staticEntryForWorkPausedUpdated: SafetyCenterStaticEntry
get() =
- staticEntryForWorkBuilder
- // TODO(b/233188021): This needs to use the Enterprise API to override the "work"
- // keyword.
- .setSummary(safetyCenterResourcesContext.getStringByName("work_profile_paused"))
+ staticEntryForWorkBuilder(title = "Unspecified title for Work")
+ .setSummary(safetyCenterResourcesApk.getStringByName("work_profile_paused"))
.build()
- private val staticEntryForWorkUpdated =
- SafetyCenterStaticEntry.Builder("Unspecified title for Work")
- .setSummary("Unspecified summary")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
- .build()
+ private val staticEntryForWorkUpdated: SafetyCenterStaticEntry
+ get() =
+ SafetyCenterStaticEntry.Builder("Unspecified title for Work")
+ .setSummary("Unspecified summary")
+ .setPendingIntent(safetySourceTestData.createTestActivityRedirectPendingIntent())
+ .build()
private val safetyCenterDataForAdditionalUser
get() =
@@ -298,34 +333,26 @@ class SafetyCenterMultiUsersTest {
emptyList()
)
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2)
+ val safetyCenterTestRule =
+ SafetyCenterTestRule(safetyCenterTestHelper, withNotifications = true)
+ @get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
@Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
+ fun setRefreshTimeoutsBeforeTest() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
}
@After
- fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
- resetQuietMode()
+ fun resetQuietModeAfterTest() {
+ setQuietMode(false)
}
@Test
@EnsureHasWorkProfile
- @Ignore
- // Tests that check the UI takes a lot of time and they might get timeout in the postsubmits.
- // TODO(b/242999951): Write this test using the APIs instead of checking the UI.
- fun launchActivity_withProfileOwner_displaysWorkPolicyInfo() {
+ fun getSafetyCenterData_withProfileOwner_hasWorkPolicyInfo() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.workPolicyInfoConfig)
findWorkPolicyInfo()
@@ -333,10 +360,7 @@ class SafetyCenterMultiUsersTest {
@Test
@EnsureHasDeviceOwner
- @Ignore
- // Tests that check the UI takes a lot of time and they might get timeout in the postsubmits.
- // TODO(b/242999951): Write this test using the APIs instead of checking the UI.
- fun launchActivity_withDeviceOwner_displaysWorkPolicyInfo() {
+ fun getSafetyCenterData_withDeviceOwner_hasWorkPolicyInfo() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.workPolicyInfoConfig)
findWorkPolicyInfo()
@@ -344,21 +368,24 @@ class SafetyCenterMultiUsersTest {
@Test
@EnsureHasWorkProfile
- @Ignore
- // Tests that check the UI takes a lot of time and they might get timeout in the postsubmits.
- // TODO(b/242999951): Write this test using the APIs instead of checking the UI.
- fun launchActivity_withQuietModeEnabled_shouldNotDisplayWorkPolicyInfo() {
+ fun launchActivity_withQuietModeEnabled_hasWorkPolicyInfo() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.workPolicyInfoConfig)
- findWorkPolicyInfo()
setQuietMode(true)
+
+ findWorkPolicyInfo()
+ }
+
+ @Test
+ @EnsureHasNoWorkProfile
+ @EnsureHasNoDeviceOwner
+ fun launchActivity_withoutWorkProfileOrDeviceOwner_doesntHaveWorkPolicyInfo() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.workPolicyInfoConfig)
+
context.launchSafetyCenterActivity { waitAllTextNotDisplayed("Your work policy info") }
}
@Test
- @Ignore
- // Test involving toggling of quiet mode are flaky.
- // TODO(b/237365018): Re-enable them back once we figure out a way to make them stable.
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun getSafetySourceData_withQuietModeEnabled_dataIsNotCleared() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -381,7 +408,6 @@ class SafetyCenterMultiUsersTest {
@Test
@EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
- @Postsubmit(reason = "Test takes too much time to setup")
fun getSafetySourceData_afterAdditionalUserRemoved_returnsNull() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
val additionalUserSafetyCenterManager =
@@ -409,7 +435,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun getSafetySourceData_withoutInteractAcrossUserPermission_shouldThrowError() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -422,7 +447,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun getSafetySourceData_withoutAppInstalledForWorkProfile_shouldReturnNull() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -444,7 +468,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun getSafetySourceData_withRemovedProfile_shouldReturnNull() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -466,10 +489,7 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
- @Ignore
- // Test involving toggling of quiet mode are flaky.
fun getSafetySourceData_withProfileInQuietMode_shouldReturnData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
val managedSafetyCenterManager =
@@ -490,7 +510,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasNoWorkProfile
fun getSafetyCenterData_withComplexConfigWithoutWorkProfile_returnsPrimaryDataFromConfig() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexAllProfileConfig)
@@ -506,9 +525,7 @@ class SafetyCenterMultiUsersTest {
SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
.setSummary(
- safetyCenterResourcesContext.getStringByName(
- "group_unknown_summary"
- )
+ safetyCenterResourcesApk.getStringByName("group_unknown_summary")
)
.setEntries(listOf(dynamicBareboneDefault, dynamicDisabledDefault))
.setSeverityUnspecifiedIconType(
@@ -522,13 +539,17 @@ class SafetyCenterMultiUsersTest {
.build()
)
),
- listOf(SafetyCenterStaticEntryGroup("OK", listOf(staticEntry, staticEntry)))
+ listOf(
+ SafetyCenterStaticEntryGroup(
+ "OK",
+ listOf(createStaticEntry(), createStaticEntry(explicit = false))
+ )
+ )
)
assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig)
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun getSafetyCenterData_withComplexConfigWithoutDataProvided_returnsDataFromConfig() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexAllProfileConfig)
@@ -544,9 +565,7 @@ class SafetyCenterMultiUsersTest {
SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
.setSummary(
- safetyCenterResourcesContext.getStringByName(
- "group_unknown_summary"
- )
+ safetyCenterResourcesApk.getStringByName("group_unknown_summary")
)
.setEntries(
listOf(
@@ -571,7 +590,12 @@ class SafetyCenterMultiUsersTest {
listOf(
SafetyCenterStaticEntryGroup(
"OK",
- listOf(staticEntry, staticEntryForWork, staticEntry, staticEntryForWork)
+ listOf(
+ createStaticEntry(),
+ createStaticEntryForWork(),
+ createStaticEntry(explicit = false),
+ createStaticEntryForWork(explicit = false)
+ )
)
)
)
@@ -579,7 +603,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun getSafetyCenterData_withComplexConfigWithPrimaryDataProvided_returnsPrimaryDataProvided() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexAllProfileConfig)
@@ -622,9 +645,9 @@ class SafetyCenterMultiUsersTest {
"OK",
listOf(
staticEntryUpdated,
- staticEntryForWork,
- staticEntry,
- staticEntryForWork
+ createStaticEntryForWork(),
+ createStaticEntry(explicit = false),
+ createStaticEntryForWork(explicit = false)
)
)
)
@@ -633,7 +656,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun getSafetyCenterData_withComplexConfigWithAllDataProvided_returnsAllDataProvided() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexAllProfileConfig)
@@ -733,8 +755,8 @@ class SafetyCenterMultiUsersTest {
listOf(
staticEntryUpdated,
staticEntryForWorkUpdated,
- staticEntry,
- staticEntryForWork
+ createStaticEntry(explicit = false),
+ createStaticEntryForWork(explicit = false)
)
)
)
@@ -744,15 +766,12 @@ class SafetyCenterMultiUsersTest {
@Test
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
- @Ignore
- // Test involving toggling of quiet mode are flaky.
- // TODO(b/237365018): Re-enable them back once we figure out a way to make them stable.
fun getSafetyCenterData_withQuietMode_shouldHaveWorkProfilePausedSummaryAndNoWorkIssues() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexAllProfileConfig)
updatePrimaryProfileSources()
updateWorkProfileSources()
-
setQuietMode(true)
+
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
val safetyCenterDataFromComplexConfig =
@@ -768,8 +787,9 @@ class SafetyCenterMultiUsersTest {
listOf(
dynamicBareboneUpdated,
dynamicDisabledUpdated,
- dynamicDisabledForWorkPaused,
- dynamicHiddenUpdated
+ dynamicDisabledForWorkPausedUpdated,
+ dynamicHiddenUpdated,
+ dynamicHiddenForWorkPausedUpdated,
)
)
.setSeverityUnspecifiedIconType(
@@ -794,9 +814,9 @@ class SafetyCenterMultiUsersTest {
"OK",
listOf(
staticEntryUpdated,
- staticEntryForWorkPaused,
- staticEntry,
- staticEntryForWorkPaused
+ staticEntryForWorkPausedUpdated,
+ createStaticEntry(explicit = false),
+ createStaticEntryForWorkPaused()
)
)
)
@@ -807,7 +827,6 @@ class SafetyCenterMultiUsersTest {
@Test
@EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
- @Postsubmit(reason = "Test takes too much time to setup")
fun getSafetyCenterData_withDataForDifferentUserProfileGroup_shouldBeUnaffected() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
val dataForPrimaryUser = safetySourceTestData.information
@@ -830,7 +849,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Ignore // Removing a managed profile causes a refresh, which makes some tests flaky.
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun getSafetyCenterData_afterManagedProfileRemoved_returnsDefaultData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -845,9 +863,7 @@ class SafetyCenterMultiUsersTest {
SafetyCenterEntryGroup.Builder(SINGLE_SOURCE_GROUP_ID, "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
.setSummary(
- safetyCenterResourcesContext.getStringByName(
- "group_unknown_summary"
- )
+ safetyCenterResourcesApk.getStringByName("group_unknown_summary")
)
.setEntries(
listOf(
@@ -905,7 +921,6 @@ class SafetyCenterMultiUsersTest {
@Test
@EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
- @Postsubmit(reason = "Test takes too much time to setup")
fun getSafetyCenterData_afterAdditionalUserRemoved_returnsDefaultData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
val additionalUserSafetyCenterManager =
@@ -926,7 +941,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun setSafetySourceData_primaryProfileIssueOnlySource_shouldNotBeAbleToSetDataToWorkProfile() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
@@ -944,7 +958,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun setSafetySourceData_withoutInteractAcrossUserPermission_shouldThrowError() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -962,7 +975,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun setSafetySourceData_withoutAppInstalledForWorkProfile_shouldNoOp() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -984,7 +996,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun setSafetySourceData_withRemovedProfile_shouldNoOp() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -1006,7 +1017,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasCloneProfile(installInstrumentedApp = TRUE)
fun setSafetySourceData_withUnsupportedProfile_shouldNoOp() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -1027,10 +1037,7 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
- @Ignore
- // Test involving toggling of quiet mode are flaky.
fun setSafetySourceData_withProfileInQuietMode_shouldSetData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
val dataForWork = safetySourceTestData.informationWithIssueForWork
@@ -1051,7 +1058,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun setSafetySourceData_issuesOnlySourceWithWorkProfile_shouldBeAbleToSetData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceAllProfileConfig)
@@ -1079,7 +1085,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun setSafetySourceData_primaryProfileSource_shouldNotBeAbleToSetDataToWorkProfile() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -1096,7 +1101,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
fun setSafetySourceData_sourceWithWorkProfile_shouldBeAbleToSetData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
@@ -1122,7 +1126,32 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_notificationsAllowed_workProfile_sendsNotification() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ SafetyCenterFlags.notificationsEnabled = true
+ SafetyCenterFlags.notificationsAllowedSources = setOf(SINGLE_SOURCE_ALL_PROFILE_ID)
+ SafetyCenterFlags.immediateNotificationBehaviorIssues =
+ setOf("$SINGLE_SOURCE_ALL_PROFILE_ID/$ISSUE_TYPE_ID")
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+
+ TestNotificationListener.waitForNotificationsMatching(
+ NotificationCharacteristics(
+ title = "Information issue title",
+ text = "Information issue summary",
+ actions = listOf("Review")
+ )
+ )
+ }
+
+ @Test
@EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
fun setSafetySourceData_forStoppedUser_shouldSetData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -1144,7 +1173,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
fun setSafetySourceData_forBothPrimaryAdditionalUser_shouldSetData() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -1170,7 +1198,6 @@ class SafetyCenterMultiUsersTest {
}
@Test
- @Postsubmit(reason = "Test takes too much time to setup")
@EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
fun setSafetySourceData_forAdditionalUser_shouldNotAffectDataForPrimaryUser() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -1190,8 +1217,6 @@ class SafetyCenterMultiUsersTest {
private fun findWorkPolicyInfo() {
context.launchSafetyCenterActivity {
- // TODO(b/233188021): This needs to use the Enterprise API to override the "work"
- // keyword.
waitAllTextDisplayed("Your work policy info", "Settings managed by your IT admin")
}
}
@@ -1207,11 +1232,14 @@ class SafetyCenterMultiUsersTest {
}
}
- private fun createTestActivityRedirectPendingIntentForUser(user: UserHandle): PendingIntent {
+ private fun createTestActivityRedirectPendingIntentForUser(
+ user: UserHandle,
+ explicit: Boolean = true
+ ): PendingIntent {
return callWithShellPermissionIdentity(INTERACT_ACROSS_USERS) {
SafetySourceTestData.createRedirectPendingIntent(
getContextForUser(user),
- Intent(ACTION_TEST_ACTIVITY)
+ SafetySourceTestData.createTestActivityIntent(getContextForUser(user), explicit)
)
}
}
@@ -1238,16 +1266,23 @@ class SafetyCenterMultiUsersTest {
getSafetyCenterDataWithPermission()
}
- private fun setQuietMode(value: Boolean) {
- deviceState.workProfile().setQuietMode(value)
- inQuietMode = value
- }
-
- private fun resetQuietMode() {
- if (!inQuietMode) {
+ private fun setQuietMode(enableQuietMode: Boolean) {
+ if (inQuietMode == enableQuietMode) {
return
}
- setQuietMode(false)
+ if (enableQuietMode) {
+ deviceState.workProfile().setQuietMode(true)
+ } else {
+ // This is needed to ensure the refresh broadcast doesn't leak onto other tests.
+ disableQuietModeAndWaitForRefreshToComplete()
+ }
+ inQuietMode = enableQuietMode
+ }
+
+ private fun disableQuietModeAndWaitForRefreshToComplete() {
+ val listener = safetyCenterTestHelper.addListener()
+ deviceState.workProfile().setQuietMode(false)
+ listener.waitForSafetyCenterRefresh()
}
private fun safetyCenterEntryOkForWork(sourceId: String, managedUserId: Int) =
diff --git a/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml b/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml
index 5357ed4f7..a1826653f 100644
--- a/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml
+++ b/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml
@@ -43,9 +43,12 @@
aren't polluted by `BOOT_COMPLETED` or similar broadcasts still being delivered, which
causes our `ActivityManager#waitForBroadcastIdle()` calls to timeout. -->
<option name="run-command" value="am wait-for-broadcast-idle" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
<!-- 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" />
+ <!-- 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>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
diff --git a/tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING b/tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING
index 533b4d2a5..dcc2f817f 100644
--- a/tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING
+++ b/tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING
@@ -9,7 +9,7 @@
"name": "SafetyCenterActivityFunctionalTestCases[com.google.android.permission.apex]",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt b/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt
index b1c39e563..73f435615 100644
--- a/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt
+++ b/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt
@@ -17,7 +17,7 @@
package android.safetycenter.functional.ui
import android.content.Context
-import android.os.Build.VERSION.CODENAME
+import android.os.Build
import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.os.Bundle
@@ -37,7 +37,6 @@ import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity
import com.android.safetycenter.testing.SafetyCenterFlags
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_ALL_OPTIONAL_ID
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
@@ -47,12 +46,15 @@ import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_4
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_5
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceIntentHandler.Request
import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
import com.android.safetycenter.testing.SafetySourceReceiver
import com.android.safetycenter.testing.SafetySourceTestData
import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ID
import com.android.safetycenter.testing.SafetySourceTestData.Companion.RECOMMENDATION_ISSUE_ID
+import com.android.safetycenter.testing.SettingsPackage.getSettingsPackageName
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.android.safetycenter.testing.UiTestHelper.MORE_ISSUES_LABEL
import com.android.safetycenter.testing.UiTestHelper.RESCAN_BUTTON_LABEL
import com.android.safetycenter.testing.UiTestHelper.clickConfirmDismissal
@@ -67,13 +69,12 @@ import com.android.safetycenter.testing.UiTestHelper.waitButtonDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitCollapsedIssuesDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitExpandedIssuesDisplayed
+import com.android.safetycenter.testing.UiTestHelper.waitPageTitleDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitSourceDataDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueNotDisplayed
import org.junit.After
-import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -82,38 +83,18 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SafetyCenterActivityTest {
- @get:Rule val disableAnimationRule = DisableAnimationRule()
-
- @get:Rule val freezeRotationRule = FreezeRotationRule()
-
private val context: Context = getApplicationContext()
-
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
- // JUnit's Assume is not supported in @BeforeClass by the tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
-
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
- @Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
- }
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+ @get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
@After
fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
getUiDevice().resetRotation()
}
@@ -549,7 +530,7 @@ class SafetyCenterActivityTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun issueCard_withAttribution_hasProperContentDescriptions() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -722,7 +703,7 @@ class SafetyCenterActivityTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun issueCard_resolveIssue_withDialogClickYes_resolves() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
safetyCenterTestHelper.setData(
@@ -748,7 +729,7 @@ class SafetyCenterActivityTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun issueCard_resolveIssue_withDialog_rotates_clickYes_resolves() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
safetyCenterTestHelper.setData(
@@ -778,7 +759,7 @@ class SafetyCenterActivityTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun issueCard_resolveIssue_withDialogClicksNo_cancels() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
safetyCenterTestHelper.setData(
@@ -880,7 +861,7 @@ class SafetyCenterActivityTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun issueCard_withAttributionTitleSetBySource_displaysAttributionTitle() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -891,7 +872,7 @@ class SafetyCenterActivityTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun issueCard_attributionNotSetBySource_displaysGroupTitleAsAttribution() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -902,7 +883,7 @@ class SafetyCenterActivityTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun issueCard_attributionNotSetBySourceAndGroupTitleNull_doesNotDisplayAttributionTitle() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceNoGroupTitleConfig)
@@ -915,9 +896,6 @@ class SafetyCenterActivityTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
fun issueCard_attributionNotSetBySourceOnTiramisu_doesNotDisplayAttributionTitle() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(CODENAME == "UpsideDownCake")
- assumeFalse(CODENAME == "VanillaIceCream")
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
val data = safetySourceTestData.recommendationWithGeneralIssue
@@ -1430,10 +1408,6 @@ class SafetyCenterActivityTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
fun launchSafetyCenter_enableSubpagesFlagOnT_stillShowsExpandAndCollapseEntries() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(CODENAME == "UpsideDownCake")
- assumeFalse(CODENAME == "VanillaIceCream")
-
SafetyCenterFlags.showSubpages = true
val sourceTestData = safetySourceTestData.information
val config = safetyCenterTestConfigs.multipleSourceGroupsConfig
@@ -1478,7 +1452,7 @@ class SafetyCenterActivityTest {
@Test
fun startStaticEntryActivity_withConfigToBeSettingsActivity_trueExtraInBundle() {
- safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleStaticSettingsSource)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleStaticSettingsSourceConfig)
context.launchSafetyCenterActivity {
waitDisplayed(By.text("OK")) { it.click() }
@@ -1487,17 +1461,40 @@ class SafetyCenterActivityTest {
}
}
- companion object {
- private const val EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY = "expand_issue_group_qs_fragment_key"
- private const val SAFETY_SOURCE_1_TITLE = "Safety Source 1 Title"
- private const val SAFETY_SOURCE_1_SUMMARY = "Safety Source 1 Summary"
- private const val SAFETY_SOURCE_2_TITLE = "Safety Source 2 Title"
- private const val SAFETY_SOURCE_2_SUMMARY = "Safety Source 2 Summary"
- private const val SAFETY_SOURCE_3_TITLE = "Safety Source 3 Title"
- private const val SAFETY_SOURCE_3_SUMMARY = "Safety Source 3 Summary"
- private const val SAFETY_SOURCE_4_TITLE = "Safety Source 4 Title"
- private const val SAFETY_SOURCE_4_SUMMARY = "Safety Source 4 Summary"
- private const val SAFETY_SOURCE_5_TITLE = "Safety Source 5 Title"
- private const val SAFETY_SOURCE_5_SUMMARY = "Safety Source 5 Summary"
+ @Test
+ fun launchActivity_openWithPrivacyControlsIntent_showsPrivacyControls() {
+ context.launchSafetyCenterActivity(intentAction = PRIVACY_CONTROLS_ACTION) {
+ waitPageTitleDisplayed("Privacy controls")
+ }
+ }
+
+ @Test
+ fun launchActivity_openWithPrivacyControlsIntentWithScDisabled_showsLegacyPrivacyPage() {
+ // This test should technically run on T+ but we have to restrict it to V+ as b/286690307 is
+ // causing a flake which was only fixed on master.
+ assumeTrue(
+ Build.VERSION.SDK_INT > UPSIDE_DOWN_CAKE || Build.VERSION.CODENAME == "VanillaIceCream"
+ )
+ safetyCenterTestHelper.setEnabled(false)
+
+ context.launchSafetyCenterActivity(intentAction = PRIVACY_CONTROLS_ACTION) {
+ waitDisplayed(By.pkg(context.getSettingsPackageName()))
+ waitPageTitleDisplayed("Privacy")
+ }
+ }
+
+ private companion object {
+ const val EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY = "expand_issue_group_qs_fragment_key"
+ const val SAFETY_SOURCE_1_TITLE = "Safety Source 1 Title"
+ const val SAFETY_SOURCE_1_SUMMARY = "Safety Source 1 Summary"
+ const val SAFETY_SOURCE_2_TITLE = "Safety Source 2 Title"
+ const val SAFETY_SOURCE_2_SUMMARY = "Safety Source 2 Summary"
+ const val SAFETY_SOURCE_3_TITLE = "Safety Source 3 Title"
+ const val SAFETY_SOURCE_3_SUMMARY = "Safety Source 3 Summary"
+ const val SAFETY_SOURCE_4_TITLE = "Safety Source 4 Title"
+ const val SAFETY_SOURCE_4_SUMMARY = "Safety Source 4 Summary"
+ const val SAFETY_SOURCE_5_TITLE = "Safety Source 5 Title"
+ const val SAFETY_SOURCE_5_SUMMARY = "Safety Source 5 Summary"
+ const val PRIVACY_CONTROLS_ACTION = "android.settings.PRIVACY_CONTROLS"
}
}
diff --git a/tests/functional/safetycenter/singleuser/AndroidManifest.xml b/tests/functional/safetycenter/singleuser/AndroidManifest.xml
index 7ca38dede..18a3b167a 100644
--- a/tests/functional/safetycenter/singleuser/AndroidManifest.xml
+++ b/tests/functional/safetycenter/singleuser/AndroidManifest.xml
@@ -17,14 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.safetycenter.functional">
<application>
- <service android:name=".testing.TestNotificationListener"
- android:label="TestNotificationListener"
- android:exported="false"
- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
- <intent-filter>
- <action android:name="android.service.notification.NotificationListenerService" />
- </intent-filter>
- </service>
+
<uses-library android:name="android.test.runner"/>
</application>
diff --git a/tests/functional/safetycenter/singleuser/AndroidTest.xml b/tests/functional/safetycenter/singleuser/AndroidTest.xml
index d9d5b1361..3aa173508 100644
--- a/tests/functional/safetycenter/singleuser/AndroidTest.xml
+++ b/tests/functional/safetycenter/singleuser/AndroidTest.xml
@@ -43,9 +43,12 @@
aren't polluted by `BOOT_COMPLETED` or similar broadcasts still being delivered, which
causes our `ActivityManager#waitForBroadcastIdle()` calls to timeout. -->
<option name="run-command" value="am wait-for-broadcast-idle" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
<!-- 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" />
+ <!-- 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>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
diff --git a/tests/functional/safetycenter/singleuser/TEST_MAPPING b/tests/functional/safetycenter/singleuser/TEST_MAPPING
index 8285ecd5a..9ba98a87a 100644
--- a/tests/functional/safetycenter/singleuser/TEST_MAPPING
+++ b/tests/functional/safetycenter/singleuser/TEST_MAPPING
@@ -9,7 +9,7 @@
"name": "SafetyCenterFunctionalTestCases[com.google.android.permission.apex]",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt
index b8fd17b37..8bcc724f3 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt
@@ -16,10 +16,9 @@
package android.safetycenter.functional
-import android.app.PendingIntent
+import android.Manifest.permission.MANAGE_SAFETY_CENTER
import android.content.Context
import android.content.Intent
-import android.os.Build
import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.os.UserHandle
@@ -63,25 +62,25 @@ import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
-import com.android.compatibility.common.preconditions.ScreenLockHelper
import com.android.compatibility.common.util.SystemUtil
import com.android.modules.utils.build.SdkLevel
import com.android.safetycenter.internaldata.SafetyCenterBundles
import com.android.safetycenter.internaldata.SafetyCenterBundles.ISSUES_TO_GROUPS_BUNDLE_KEY
import com.android.safetycenter.internaldata.SafetyCenterEntryId
import com.android.safetycenter.internaldata.SafetyCenterIds
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
import com.android.safetycenter.testing.Coroutines.waitForWithTimeout
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterConfigWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterDataWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetySourceDataWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.refreshSafetySourcesWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.reportSafetySourceErrorWithPermission
import com.android.safetycenter.testing.SafetyCenterFlags
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ACTION_TEST_ACTIVITY
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ACTION_TEST_ACTIVITY_EXPORTED
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_ALL_OPTIONAL_ID
@@ -116,6 +115,7 @@ import com.android.safetycenter.testing.SafetyCenterTestData.Companion.withAttri
import com.android.safetycenter.testing.SafetyCenterTestData.Companion.withDismissedIssuesIfAtLeastU
import com.android.safetycenter.testing.SafetyCenterTestData.Companion.withoutExtras
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceIntentHandler.Request
import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
import com.android.safetycenter.testing.SafetySourceReceiver
@@ -130,15 +130,14 @@ import com.android.safetycenter.testing.SafetySourceTestData.Companion.INFORMATI
import com.android.safetycenter.testing.SafetySourceTestData.Companion.RECOMMENDATION_ISSUE_ID
import com.android.safetycenter.testing.SettingsPackage.getSettingsPackageName
import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.google.common.base.Preconditions.checkState
import com.google.common.truth.Truth.assertThat
import java.time.Duration
import kotlin.test.assertFailsWith
import kotlinx.coroutines.TimeoutCancellationException
-import org.junit.After
import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
-import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -146,588 +145,657 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SafetyCenterManagerTest {
private val context: Context = getApplicationContext()
- private val safetyCenterResourcesContext = SafetyCenterResourcesContext.forTests(context)
+ private val safetyCenterResourcesApk = SafetyCenterResourcesApk.forTests(context)
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestData = SafetyCenterTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
- private val safetyCenterStatusOk =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_summary")
- )
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
- .build()
+ private val safetyCenterStatusOk: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary")
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .build()
+
+ private val safetyCenterStatusUnknownScanning: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName("scanning_title"),
+ safetyCenterResourcesApk.getStringByName("loading_summary")
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ .setRefreshStatus(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
+ .build()
+
+ private val safetyCenterStatusOkOneAlert: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .build()
+
+ private val safetyCenterStatusOkReviewOneAlert: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_ok_review_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .build()
+
+ private val safetyCenterStatusOkReview: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_ok_review_title"
+ ),
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_ok_review_summary"
+ )
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .build()
+
+ private val safetyCenterStatusGeneralRecommendationOneAlert: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_safety_recommendation_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
+ .build()
+
+ private val safetyCenterStatusAccountRecommendationOneAlert: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_account_recommendation_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
+ .build()
+
+ private val safetyCenterStatusDeviceRecommendationOneAlert: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_device_recommendation_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
+ .build()
- private val safetyCenterStatusUnknownScanning =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName("scanning_title"),
- safetyCenterResourcesContext.getStringByName("loading_summary")
+ private val safetyCenterStatusGeneralCriticalOneAlert: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_critical_safety_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusGeneralCriticalTwoAlerts: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_critical_safety_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(2)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusAccountCriticalOneAlert: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_critical_account_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusAccountCriticalTwoAlerts: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_critical_account_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(2)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusDeviceCriticalOneAlert: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_critical_device_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusDeviceCriticalTwoAlerts: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_critical_device_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(2)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterEntryOrGroupRecommendation: SafetyCenterEntryOrGroup
+ get() =
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
+ )
+
+ private val safetyCenterEntryOrGroupCritical: SafetyCenterEntryOrGroup
+ get() =
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryCritical(SINGLE_SOURCE_ID)
+ )
+
+ private val safetyCenterEntryGroupMixedFromComplexConfig: SafetyCenterEntryOrGroup
+ get() =
+ SafetyCenterEntryOrGroup(
+ SafetyCenterEntryGroup.Builder(MIXED_STATEFUL_GROUP_ID, "OK")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
+ .setSummary(safetyCenterResourcesApk.getStringByName("group_unknown_summary"))
+ .setEntries(
+ listOf(
+ safetyCenterTestData.safetyCenterEntryDefault(DYNAMIC_IN_STATEFUL_ID),
+ SafetyCenterEntry.Builder(
+ SafetyCenterTestData.entryId(STATIC_IN_STATEFUL_ID),
+ "OK"
+ )
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
+ .setSummary("OK")
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent(
+ explicit = false
+ )
+ )
+ .setSeverityUnspecifiedIconType(
+ SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON
+ )
+ .build()
+ )
+ )
+ .setSeverityUnspecifiedIconType(
+ SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+ )
+ .build()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
- .setRefreshStatus(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
- .build()
- private val safetyCenterStatusOkOneAlert =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
- safetyCenterTestData.getAlertString(1)
+ private val safetyCenterStaticEntryGroupFromComplexConfig: SafetyCenterStaticEntryGroup
+ get() =
+ SafetyCenterStaticEntryGroup(
+ "OK",
+ listOf(
+ SafetyCenterStaticEntry.Builder("OK")
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent(
+ explicit = false
+ )
+ )
+ .build(),
+ SafetyCenterStaticEntry.Builder("OK")
+ .setSummary("OK")
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent(
+ explicit = false
+ )
+ )
+ .build()
+ )
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
- .build()
- private val safetyCenterStatusOkReviewOneAlert =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_ok_review_title"
- ),
- safetyCenterTestData.getAlertString(1)
+ private val safetyCenterStaticEntryGroupMixedFromComplexConfig: SafetyCenterStaticEntryGroup
+ get() =
+ SafetyCenterStaticEntryGroup(
+ "OK",
+ listOf(
+ SafetyCenterStaticEntry.Builder("OK")
+ .setSummary("OK")
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
+ )
+ .build(),
+ SafetyCenterStaticEntry.Builder("OK")
+ .setSummary("OK")
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent(
+ explicit = false
+ )
+ )
+ .build()
+ )
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
- .build()
- private val safetyCenterStatusOkReview =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_ok_review_title"
- ),
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_ok_review_summary"
+ private val safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig:
+ SafetyCenterStaticEntryGroup
+ get() =
+ SafetyCenterStaticEntryGroup(
+ "OK",
+ listOf(
+ SafetyCenterStaticEntry.Builder("Unspecified title")
+ .setSummary("Unspecified summary")
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
+ )
+ .build(),
+ SafetyCenterStaticEntry.Builder("OK")
+ .setSummary("OK")
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent(
+ explicit = false
+ )
+ )
+ .build()
)
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
- .build()
- private val safetyCenterStatusGeneralRecommendationOneAlert =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_safety_recommendation_title"
+ private val safetyCenterDataFromConfigScanning: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusUnknownScanning,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ID)
+ )
),
- safetyCenterTestData.getAlertString(1)
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
- private val safetyCenterStatusAccountRecommendationOneAlert =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_account_recommendation_title"
+ private val safetyCenterDataFromConfig: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusUnknown,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ID)
+ )
),
- safetyCenterTestData.getAlertString(1)
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
- private val safetyCenterStatusDeviceRecommendationOneAlert =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_device_recommendation_title"
+ private val safetyCenterDataUnspecified: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusOk,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryUnspecified(SINGLE_SOURCE_ID)
+ )
),
- safetyCenterTestData.getAlertString(1)
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
- private val safetyCenterStatusGeneralCriticalOneAlert =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_critical_safety_warning_title"
+ private val safetyCenterDataOk: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusOk,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID)
+ )
),
- safetyCenterTestData.getAlertString(1)
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
- private val safetyCenterStatusGeneralCriticalTwoAlerts =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_critical_safety_warning_title"
+ private val safetyCenterDataOkWithIconAction: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusOk,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData
+ .safetyCenterEntryOkBuilder(SINGLE_SOURCE_ID)
+ .setIconAction(
+ ICON_ACTION_TYPE_INFO,
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
+ )
+ .build()
+ )
),
- safetyCenterTestData.getAlertString(2)
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
- private val safetyCenterStatusAccountCriticalOneAlert =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_critical_account_warning_title"
+ private val safetyCenterDataUnknownScanningWithError: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusUnknownScanning,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryError(SINGLE_SOURCE_ID)
+ )
),
- safetyCenterTestData.getAlertString(1)
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
- private val safetyCenterStatusAccountCriticalTwoAlerts =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_critical_account_warning_title"
+ private val safetyCenterDataUnknownReviewError: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusUnknown,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryError(SINGLE_SOURCE_ID)
+ )
),
- safetyCenterTestData.getAlertString(2)
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
- private val safetyCenterStatusDeviceCriticalOneAlert =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_critical_device_warning_title"
+ private val safetyCenterDataOkOneAlert: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusOkOneAlert,
+ listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID)
+ )
),
- safetyCenterTestData.getAlertString(1)
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
- private val safetyCenterStatusDeviceCriticalTwoAlerts =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_critical_device_warning_title"
- ),
- safetyCenterTestData.getAlertString(2)
+ private val safetyCenterDataOkReviewCriticalEntry: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusOkReview,
+ emptyList(),
+ listOf(safetyCenterEntryOrGroupCritical),
+ emptyList()
)
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
- private val safetyCenterEntryOrGroupRecommendation =
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
- )
+ private val safetyCenterDataOkReviewRecommendationEntry: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusOkReview,
+ emptyList(),
+ listOf(safetyCenterEntryOrGroupRecommendation),
+ emptyList()
+ )
- private val safetyCenterEntryOrGroupCritical =
- SafetyCenterEntryOrGroup(safetyCenterTestData.safetyCenterEntryCritical(SINGLE_SOURCE_ID))
+ private val safetyCenterDataOkReviewOneAlert: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusOkReviewOneAlert,
+ listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)),
+ listOf(safetyCenterEntryOrGroupCritical),
+ emptyList()
+ )
- private val safetyCenterEntryGroupMixedFromComplexConfig =
- SafetyCenterEntryOrGroup(
- SafetyCenterEntryGroup.Builder(MIXED_STATEFUL_GROUP_ID, "OK")
- .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
- .setSummary(safetyCenterResourcesContext.getStringByName("group_unknown_summary"))
- .setEntries(
- listOf(
- safetyCenterTestData.safetyCenterEntryDefault(DYNAMIC_IN_STATEFUL_ID),
- SafetyCenterEntry.Builder(
- SafetyCenterTestData.entryId(STATIC_IN_STATEFUL_ID),
- "OK"
- )
- .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
- .setSummary("OK")
- .setPendingIntent(
- safetySourceTestData.testActivityRedirectPendingIntent
- )
- .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON)
- .build()
+ private val safetyCenterDataGeneralRecommendationOneAlert: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusGeneralRecommendationOneAlert,
+ listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
)
- )
- .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
- .build()
- )
-
- private val safetyCenterStaticEntryGroupFromComplexConfig =
- SafetyCenterStaticEntryGroup(
- "OK",
- listOf(
- SafetyCenterStaticEntry.Builder("OK")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
- .build(),
- SafetyCenterStaticEntry.Builder("OK")
- .setSummary("OK")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
- .build()
+ ),
+ emptyList()
)
- )
- private val safetyCenterStaticEntryGroupMixedFromComplexConfig =
- SafetyCenterStaticEntryGroup(
- "OK",
- listOf(
- SafetyCenterStaticEntry.Builder("OK")
- .setSummary("OK")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
- .build(),
- SafetyCenterStaticEntry.Builder("OK")
- .setSummary("OK")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
- .build()
+ private val safetyCenterDataGeneralRecommendationAlertWithConfirmation: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusGeneralRecommendationOneAlert,
+ listOf(
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ SINGLE_SOURCE_ID,
+ confirmationDialog = true
+ )
+ ),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
+ )
+ ),
+ emptyList()
)
- )
- private val safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig =
- SafetyCenterStaticEntryGroup(
- "OK",
- listOf(
- SafetyCenterStaticEntry.Builder("Unspecified title")
- .setSummary("Unspecified summary")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
- .build(),
- SafetyCenterStaticEntry.Builder("OK")
- .setSummary("OK")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
- .build()
+ private val safetyCenterDataAccountRecommendationOneAlert: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusAccountRecommendationOneAlert,
+ listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
+ )
+ ),
+ emptyList()
)
- )
-
- private val safetyCenterDataFromConfigScanning =
- SafetyCenterData(
- safetyCenterStatusUnknownScanning,
- emptyList(),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataFromConfig =
- SafetyCenterData(
- safetyCenterTestData.safetyCenterStatusUnknown,
- emptyList(),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataUnspecified =
- SafetyCenterData(
- safetyCenterStatusOk,
- emptyList(),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryUnspecified(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataOk =
- SafetyCenterData(
- safetyCenterStatusOk,
- emptyList(),
- listOf(
- SafetyCenterEntryOrGroup(safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID))
- ),
- emptyList()
- )
-
- private val safetyCenterDataOkWithIconAction =
- SafetyCenterData(
- safetyCenterStatusOk,
- emptyList(),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData
- .safetyCenterEntryOkBuilder(SINGLE_SOURCE_ID)
- .setIconAction(
- ICON_ACTION_TYPE_INFO,
- safetySourceTestData.testActivityRedirectPendingIntent
- )
- .build()
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataUnknownScanningWithError =
- SafetyCenterData(
- safetyCenterStatusUnknownScanning,
- emptyList(),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryError(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
- private val safetyCenterDataUnknownReviewError =
- SafetyCenterData(
- safetyCenterTestData.safetyCenterStatusUnknown,
- emptyList(),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryError(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataOkOneAlert =
- SafetyCenterData(
- safetyCenterStatusOkOneAlert,
- listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)),
- listOf(
- SafetyCenterEntryOrGroup(safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID))
- ),
- emptyList()
- )
-
- private val safetyCenterDataOkReviewCriticalEntry =
- SafetyCenterData(
- safetyCenterStatusOkReview,
- emptyList(),
- listOf(safetyCenterEntryOrGroupCritical),
- emptyList()
- )
-
- private val safetyCenterDataOkReviewRecommendationEntry =
- SafetyCenterData(
- safetyCenterStatusOkReview,
- emptyList(),
- listOf(safetyCenterEntryOrGroupRecommendation),
- emptyList()
- )
-
- private val safetyCenterDataOkReviewOneAlert =
- SafetyCenterData(
- safetyCenterStatusOkReviewOneAlert,
- listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)),
- listOf(safetyCenterEntryOrGroupCritical),
- emptyList()
- )
-
- private val safetyCenterDataGeneralRecommendationOneAlert =
- SafetyCenterData(
- safetyCenterStatusGeneralRecommendationOneAlert,
- listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataGeneralRecommendationAlertWithConfirmation =
- SafetyCenterData(
- safetyCenterStatusGeneralRecommendationOneAlert,
- listOf(
- safetyCenterTestData.safetyCenterIssueRecommendation(
- SINGLE_SOURCE_ID,
- confirmationDialog = true
- )
- ),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataAccountRecommendationOneAlert =
- SafetyCenterData(
- safetyCenterStatusAccountRecommendationOneAlert,
- listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataDeviceRecommendationOneAlert =
- SafetyCenterData(
- safetyCenterStatusDeviceRecommendationOneAlert,
- listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)),
- listOf(
- SafetyCenterEntryOrGroup(
- safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
- )
- ),
- emptyList()
- )
-
- private val safetyCenterDataGeneralCriticalOneAlert =
- SafetyCenterData(
- safetyCenterStatusGeneralCriticalOneAlert,
- listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)),
- listOf(safetyCenterEntryOrGroupCritical),
- emptyList()
- )
-
- private val safetyCenterDataAccountCriticalOneAlert =
- SafetyCenterData(
- safetyCenterStatusAccountCriticalOneAlert,
- listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)),
- listOf(safetyCenterEntryOrGroupCritical),
- emptyList()
- )
+ private val safetyCenterDataDeviceRecommendationOneAlert: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusDeviceRecommendationOneAlert,
+ listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
+ )
+ ),
+ emptyList()
+ )
- private val safetyCenterDataDeviceCriticalOneAlert =
- SafetyCenterData(
- safetyCenterStatusDeviceCriticalOneAlert,
- listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)),
- listOf(safetyCenterEntryOrGroupCritical),
- emptyList()
- )
+ private val safetyCenterDataGeneralCriticalOneAlert: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusGeneralCriticalOneAlert,
+ listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)),
+ listOf(safetyCenterEntryOrGroupCritical),
+ emptyList()
+ )
- private val safetyCenterDataCriticalOneAlertInFlight =
- SafetyCenterData(
- safetyCenterStatusGeneralCriticalOneAlert,
- listOf(
- safetyCenterTestData.safetyCenterIssueCritical(
- SINGLE_SOURCE_ID,
- isActionInFlight = true
- )
- ),
- listOf(safetyCenterEntryOrGroupCritical),
- emptyList()
- )
+ private val safetyCenterDataAccountCriticalOneAlert: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusAccountCriticalOneAlert,
+ listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)),
+ listOf(safetyCenterEntryOrGroupCritical),
+ emptyList()
+ )
- private val safetyCenterDataOkReviewOneDismissedAlertInFlight =
- SafetyCenterData(
- safetyCenterStatusOkReview,
- emptyList(),
+ private val safetyCenterDataDeviceCriticalOneAlert: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusDeviceCriticalOneAlert,
+ listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)),
listOf(safetyCenterEntryOrGroupCritical),
emptyList()
)
- .withDismissedIssuesIfAtLeastU(
+
+ private val safetyCenterDataCriticalOneAlertInFlight: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusGeneralCriticalOneAlert,
listOf(
safetyCenterTestData.safetyCenterIssueCritical(
SINGLE_SOURCE_ID,
isActionInFlight = true
)
- )
+ ),
+ listOf(safetyCenterEntryOrGroupCritical),
+ emptyList()
)
- private val safetyCenterDataFromComplexConfig =
- SafetyCenterData(
- safetyCenterTestData.safetyCenterStatusUnknown,
- emptyList(),
- listOf(
- SafetyCenterEntryOrGroup(
- SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
- .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
- .setSummary(
- safetyCenterResourcesContext.getStringByName("group_unknown_summary")
+ private val safetyCenterDataOkReviewOneDismissedAlertInFlight: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterStatusOkReview,
+ emptyList(),
+ listOf(safetyCenterEntryOrGroupCritical),
+ emptyList()
+ )
+ .withDismissedIssuesIfAtLeastU(
+ listOf(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SINGLE_SOURCE_ID,
+ isActionInFlight = true
)
- .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
- .setEntries(
- listOf(
- safetyCenterTestData.safetyCenterEntryDefault(DYNAMIC_BAREBONE_ID),
- safetyCenterTestData
- .safetyCenterEntryDefaultBuilder(DYNAMIC_ALL_OPTIONAL_ID)
- .setEnabled(false)
- .build(),
- safetyCenterTestData
- .safetyCenterEntryDefaultBuilder(DYNAMIC_DISABLED_ID)
- .setPendingIntent(null)
- .setEnabled(false)
- .build(),
- safetyCenterTestData
- .safetyCenterEntryDefaultBuilder(DYNAMIC_OTHER_PACKAGE_ID)
- .setPendingIntent(null)
- .setEnabled(false)
- .build()
+ )
+ )
+
+ private val safetyCenterDataFromComplexConfig: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusUnknown,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
+ .setSummary(
+ safetyCenterResourcesApk.getStringByName("group_unknown_summary")
)
- )
- .build()
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
+ .setEntries(
+ listOf(
+ safetyCenterTestData.safetyCenterEntryDefault(
+ DYNAMIC_BAREBONE_ID
+ ),
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(DYNAMIC_ALL_OPTIONAL_ID)
+ .setEnabled(false)
+ .build(),
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(DYNAMIC_DISABLED_ID)
+ .setPendingIntent(null)
+ .setEnabled(false)
+ .build(),
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(DYNAMIC_OTHER_PACKAGE_ID)
+ .setPendingIntent(null)
+ .setEnabled(false)
+ .build()
+ )
+ )
+ .build()
+ ),
+ safetyCenterEntryGroupMixedFromComplexConfig
),
- safetyCenterEntryGroupMixedFromComplexConfig
- ),
- listOf(
- safetyCenterStaticEntryGroupFromComplexConfig,
- safetyCenterStaticEntryGroupMixedFromComplexConfig
+ listOf(
+ safetyCenterStaticEntryGroupFromComplexConfig,
+ safetyCenterStaticEntryGroupMixedFromComplexConfig
+ )
)
- )
- private val safetyCenterDataFromComplexConfigUpdated =
- SafetyCenterData(
- safetyCenterTestData.safetyCenterStatusCritical(6),
- listOf(
- safetyCenterTestData.safetyCenterIssueCritical(
- DYNAMIC_BAREBONE_ID,
- groupId = DYNAMIC_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueCritical(
- ISSUE_ONLY_BAREBONE_ID,
- groupId = ISSUE_ONLY_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueRecommendation(
- DYNAMIC_DISABLED_ID,
- groupId = DYNAMIC_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueRecommendation(
- ISSUE_ONLY_ALL_OPTIONAL_ID,
- groupId = ISSUE_ONLY_GROUP_ID
- ),
- safetyCenterTestData.safetyCenterIssueInformation(
- DYNAMIC_IN_STATELESS_ID,
- groupId = MIXED_STATELESS_GROUP_ID
+ private val safetyCenterDataFromComplexConfigUpdated: SafetyCenterData
+ get() =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusCritical(6),
+ listOf(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ DYNAMIC_BAREBONE_ID,
+ groupId = DYNAMIC_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueCritical(
+ ISSUE_ONLY_BAREBONE_ID,
+ groupId = ISSUE_ONLY_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ DYNAMIC_DISABLED_ID,
+ groupId = DYNAMIC_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ groupId = ISSUE_ONLY_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ DYNAMIC_IN_STATELESS_ID,
+ groupId = MIXED_STATELESS_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ ISSUE_ONLY_IN_STATELESS_ID,
+ groupId = MIXED_STATELESS_GROUP_ID
+ )
),
- safetyCenterTestData.safetyCenterIssueInformation(
- ISSUE_ONLY_IN_STATELESS_ID,
- groupId = MIXED_STATELESS_GROUP_ID
- )
- ),
- listOf(
- SafetyCenterEntryOrGroup(
- SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
- .setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
- .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
- .setSummary("Critical summary")
- .setEntries(
- listOf(
- safetyCenterTestData.safetyCenterEntryCritical(DYNAMIC_BAREBONE_ID),
- safetyCenterTestData
- .safetyCenterEntryDefaultBuilder(DYNAMIC_ALL_OPTIONAL_ID)
- .setEnabled(false)
- .build(),
- safetyCenterTestData.safetyCenterEntryRecommendation(
- DYNAMIC_DISABLED_ID
- ),
- safetyCenterTestData.safetyCenterEntryUnspecified(
- DYNAMIC_HIDDEN_ID,
- pendingIntent = null
- ),
- safetyCenterTestData.safetyCenterEntryOk(
- DYNAMIC_HIDDEN_WITH_SEARCH_ID
- ),
- safetyCenterTestData
- .safetyCenterEntryDefaultBuilder(DYNAMIC_OTHER_PACKAGE_ID)
- .setPendingIntent(null)
- .setEnabled(false)
- .build()
+ listOf(
+ SafetyCenterEntryOrGroup(
+ SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
+ .setSummary("Critical summary")
+ .setEntries(
+ listOf(
+ safetyCenterTestData.safetyCenterEntryCritical(
+ DYNAMIC_BAREBONE_ID
+ ),
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(DYNAMIC_ALL_OPTIONAL_ID)
+ .setEnabled(false)
+ .build(),
+ safetyCenterTestData.safetyCenterEntryRecommendation(
+ DYNAMIC_DISABLED_ID
+ ),
+ safetyCenterTestData.safetyCenterEntryUnspecified(
+ DYNAMIC_HIDDEN_ID,
+ pendingIntent = null
+ ),
+ safetyCenterTestData.safetyCenterEntryOk(
+ DYNAMIC_HIDDEN_WITH_SEARCH_ID
+ ),
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(DYNAMIC_OTHER_PACKAGE_ID)
+ .setPendingIntent(null)
+ .setEnabled(false)
+ .build()
+ )
)
- )
- .build()
+ .build()
+ ),
+ safetyCenterEntryGroupMixedFromComplexConfig
),
- safetyCenterEntryGroupMixedFromComplexConfig
- ),
- listOf(
- safetyCenterStaticEntryGroupFromComplexConfig,
- safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig
+ listOf(
+ safetyCenterStaticEntryGroupFromComplexConfig,
+ safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig
+ )
)
- )
- // JUnit's Assume is not supported in @BeforeClass by the CTS tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
+ @Test
+ fun getSafetySourceData_differentPackageWithManageSafetyCenterPermission_returnsData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
- @Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
- }
+ val data =
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) {
+ safetyCenterManager.getSafetySourceData(DYNAMIC_OTHER_PACKAGE_ID)
+ }
- @After
- fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
+ assertThat(data).isNull()
}
@Test
@@ -808,9 +876,9 @@ class SafetyCenterManagerTest {
val status1 = listener.receiveSafetyCenterData().status
assertThat(status1.refreshStatus).isEqualTo(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
assertThat(status1.title.toString())
- .isEqualTo(safetyCenterResourcesContext.getStringByName("scanning_title"))
+ .isEqualTo(safetyCenterResourcesApk.getStringByName("scanning_title"))
assertThat(status1.summary.toString())
- .isEqualTo(safetyCenterResourcesContext.getStringByName("loading_summary"))
+ .isEqualTo(safetyCenterResourcesApk.getStringByName("loading_summary"))
val status2 = listener.receiveSafetyCenterData().status
assertThat(status2.refreshStatus).isEqualTo(REFRESH_STATUS_NONE)
assertThat(status2).isEqualTo(safetyCenterStatusOk)
@@ -832,9 +900,9 @@ class SafetyCenterManagerTest {
val status1 = listener.receiveSafetyCenterData().status
assertThat(status1.refreshStatus).isEqualTo(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS)
assertThat(status1.title.toString())
- .isEqualTo(safetyCenterResourcesContext.getStringByName("scanning_title"))
+ .isEqualTo(safetyCenterResourcesApk.getStringByName("scanning_title"))
assertThat(status1.summary.toString())
- .isEqualTo(safetyCenterResourcesContext.getStringByName("loading_summary"))
+ .isEqualTo(safetyCenterResourcesApk.getStringByName("loading_summary"))
val status2 = listener.receiveSafetyCenterData().status
assertThat(status2.refreshStatus).isEqualTo(REFRESH_STATUS_NONE)
assertThat(status2).isEqualTo(safetyCenterStatusOk)
@@ -858,13 +926,78 @@ class SafetyCenterManagerTest {
assertThat(status1.refreshStatus).isEqualTo(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS)
assertThat(status1.title.toString()).isEqualTo(safetyCenterStatusOk.title.toString())
assertThat(status1.summary.toString())
- .isEqualTo(safetyCenterResourcesContext.getStringByName("loading_summary"))
+ .isEqualTo(safetyCenterResourcesApk.getStringByName("loading_summary"))
val status2 = listener.receiveSafetyCenterData().status
assertThat(status2.refreshStatus).isEqualTo(REFRESH_STATUS_NONE)
assertThat(status2).isEqualTo(safetyCenterStatusOk)
}
@Test
+ fun refreshSafetySources_reasonPageOpen_allowedByFlag_broadcastSent() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.noPageOpenConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ SafetyCenterFlags.overrideRefreshOnPageOpenSources = setOf(SINGLE_SOURCE_ID)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.informationWithIssue)
+ )
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceTestData.informationWithIssue)
+ }
+
+ @Test
+ fun refreshSafetySources_reasonPageOpen_allowedByFlagLater_broadcastSentLater() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.noPageOpenConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.informationWithIssue)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN,
+ timeout = TIMEOUT_SHORT
+ )
+ }
+ val apiSafetySourceDataBeforeSettingFlag =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ SafetyCenterFlags.overrideRefreshOnPageOpenSources = setOf(SINGLE_SOURCE_ID)
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+ val apiSafetySourceDataAfterSettingFlag =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+
+ assertThat(apiSafetySourceDataBeforeSettingFlag).isEqualTo(safetySourceTestData.information)
+ assertThat(apiSafetySourceDataAfterSettingFlag)
+ .isEqualTo(safetySourceTestData.informationWithIssue)
+ }
+
+ @Test
+ fun refreshSafetySources_reasonPageOpen_noDataForSource_broadcastSent() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.noPageOpenConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
fun getSafetyCenterData_withoutDataProvided_returnsDataFromConfig() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -874,28 +1007,105 @@ class SafetyCenterManagerTest {
}
@Test
+ fun getSafetyCenterData_withoutDataExplicitIntentConfig_defaultEntryHasExplicitIntent() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val expectedExplicitPendingIntent =
+ SafetySourceTestData.createRedirectPendingIntent(
+ context,
+ Intent(ACTION_TEST_ACTIVITY).setPackage(context.packageName)
+ )
+ val defaultEntryPendingIntent =
+ apiSafetyCenterData.entriesOrGroups.firstOrNull()?.entry?.pendingIntent
+ val defaultEntryIntentFilterEqualsToExplicitIntent =
+ callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") {
+ expectedExplicitPendingIntent.intentFilterEquals(defaultEntryPendingIntent)
+ }
+ assertThat(defaultEntryIntentFilterEqualsToExplicitIntent).isTrue()
+ }
+
+ @Test
fun getSafetyCenterData_withoutDataImplicitIntentConfig_defaultEntryHasImplicitIntent() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.implicitIntentSingleSourceConfig)
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
- val implicitPendingIntentCreatedByCts =
- PendingIntent.getActivity(
+ val expectedImplicitPendingIntent =
+ SafetySourceTestData.createRedirectPendingIntent(
context,
- 0 /* requestCode */,
- Intent(ACTION_TEST_ACTIVITY_EXPORTED),
- PendingIntent.FLAG_IMMUTABLE
+ Intent(ACTION_TEST_ACTIVITY_EXPORTED)
)
val defaultEntryPendingIntent =
apiSafetyCenterData.entriesOrGroups.firstOrNull()?.entry?.pendingIntent
val defaultEntryIntentFilterEqualsToImplicitIntent =
callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") {
- implicitPendingIntentCreatedByCts.intentFilterEquals(defaultEntryPendingIntent)
+ expectedImplicitPendingIntent.intentFilterEquals(defaultEntryPendingIntent)
}
assertThat(defaultEntryIntentFilterEqualsToImplicitIntent).isTrue()
}
@Test
+ fun getSafetyCenterData_withStaticImplicitResolving_implicitStaticEntry() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.staticSourcesConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val expectedImplicitPendingIntent =
+ SafetySourceTestData.createRedirectPendingIntent(
+ context,
+ Intent(ACTION_TEST_ACTIVITY_EXPORTED)
+ )
+ val staticEntryPendingIntent =
+ apiSafetyCenterData.staticEntryGroups
+ .firstOrNull()
+ ?.staticEntries
+ ?.firstOrNull()
+ ?.pendingIntent
+ val staticEntryIntentFilterEqualsToImplicitIntent =
+ callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") {
+ expectedImplicitPendingIntent.intentFilterEquals(staticEntryPendingIntent)
+ }
+ assertThat(staticEntryIntentFilterEqualsToImplicitIntent).isTrue()
+ }
+
+ @Test
+ fun getSafetyCenterData_withStaticImplicitNotExported_explicitStaticEntryUsingCallerPackage() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.singleStaticImplicitIntentNotExportedConfig
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val expectedExplicitPendingIntent =
+ SafetySourceTestData.createRedirectPendingIntent(
+ context,
+ Intent(ACTION_TEST_ACTIVITY).setPackage(context.packageName)
+ )
+ val staticEntryPendingIntent =
+ apiSafetyCenterData.staticEntryGroups
+ .firstOrNull()
+ ?.staticEntries
+ ?.firstOrNull()
+ ?.pendingIntent
+ val staticEntryIntentFilterEqualsToExplicitIntent =
+ callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") {
+ expectedExplicitPendingIntent.intentFilterEquals(staticEntryPendingIntent)
+ }
+ assertThat(staticEntryIntentFilterEqualsToExplicitIntent).isTrue()
+ }
+
+ @Test
+ fun getSafetyCenterData_withStaticNotResolving_noStaticEntry() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleStaticInvalidIntentConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData.staticEntryGroups).isEmpty()
+ }
+
+ @Test
fun getSafetyCenterData_withComplexConfigWithoutDataProvided_returnsDataFromConfig() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
@@ -940,7 +1150,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_attributionTitleProvidedBySource_returnsIssueWithAttributionTitle() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
safetyCenterTestHelper.setData(
@@ -956,7 +1166,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_attributionTitleNotProvided_returnsGroupTitleAsAttributionTitle() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
@@ -969,7 +1179,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_attributionNotSetAndGroupTitleNull_returnsNullAttributionTitle() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceNoGroupTitleConfig)
safetyCenterTestHelper.setData(
@@ -997,9 +1207,6 @@ class SafetyCenterManagerTest {
@Test
@SdkSuppress(maxSdkVersion = TIRAMISU)
fun getSafetyCenterData_attributionNotSetBySourceOnTiramisu_returnsNullAttributionTitle() {
- // TODO(b/258228790): Remove after U is no longer in pre-release
- assumeFalse(Build.VERSION.CODENAME == "UpsideDownCake")
- assumeFalse(Build.VERSION.CODENAME == "VanillaIceCream")
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
@@ -1074,7 +1281,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_withActionConfirmation_returnsRecommendationWithActionConfirmation() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
safetyCenterTestHelper.setData(
@@ -1154,7 +1361,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_withRecommendationDataIssue_returnsDataRecommendationStatus() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1179,7 +1386,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_withCriticalDataIssue_returnsDataCriticalStatus() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1204,7 +1411,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_withRecommendationPasswordsIssue_returnsDataRecommendationStatus() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1229,7 +1436,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_withCriticalPasswordsIssue_returnsDataCriticalStatus() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1254,7 +1461,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_withRecommendationPersonalIssue_returnsDataRecommendationStatus() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1279,7 +1486,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_withCriticalPersonalIssue_returnsDataCriticalStatus() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1304,7 +1511,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_infoStatusTipFirstIssueSingleTip_infoStatusWithTipSummary() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1324,7 +1531,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_infoStatusTipFirstIssueMultiTips_infoStatusWithTipsSummary() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1360,7 +1567,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_infoStatusActionFirstIssueSingleAction_infoStatusWithActionSummary() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1380,7 +1587,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_infoStatusActionFirstIssueMultiActions_infoStatusWithActionsSummary() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1416,7 +1623,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_infoStatusManualFirstIssueSingleManual_infoStatusWithAlertSummary() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1442,7 +1649,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_infoStatusManualFirstIssueMultiManual_infoStatusWithAlertsSummary() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
safetyCenterTestHelper.setData(
@@ -1480,7 +1687,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_withStaticEntryGroups_hasStaticEntriesToIdsMapping() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.staticSourcesConfig)
@@ -1560,7 +1767,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesOfSameSeverities_issueOfFirstSourceInConfigShown() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1592,7 +1799,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesInDifferentSourceGroups_topIssueRelevantForBothGroups() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1622,7 +1829,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesInSameSourceGroups_topIssueRelevantForThatGroup() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1652,7 +1859,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_noDuplicateIssues_noGroupBelongingSpecified() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1680,7 +1887,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_differentDuplicationId_bothIssuesShown() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1717,7 +1924,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_differentDuplicationGroup_bothIssuesShown() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1754,7 +1961,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_threeDuplicateIssues_onlyOneIssueShown() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1793,7 +2000,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesOfDifferentSeverities_moreSevereIssueShown() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1825,7 +2032,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_multipleDuplicationsOfIssues_correctlyDeduplicated() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1901,7 +2108,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesBothDismissed_topOneShownAsDismissed() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1942,7 +2149,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesLowerSeverityOneDismissed_topOneShown() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -1980,7 +2187,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesHigherSeverityOneDismissed_topOneShownAsDismissed() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -2018,7 +2225,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_dupIssuesLowerPrioritySameSeverityOneDismissed_topShownAsDismissed() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -2056,7 +2263,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_dupIssuesTopOneDismissedThenDisappears_bottomOneReemergesTimely() {
SafetyCenterFlags.tempHiddenIssueResurfaceDelay = Duration.ZERO
SafetyCenterFlags.resurfaceIssueMaxCounts = mapOf(SEVERITY_LEVEL_CRITICAL_WARNING to 99L)
@@ -2110,7 +2317,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_dupsOfDiffSeveritiesTopOneDismissedThenGone_bottomOneReemergesTimely() {
SafetyCenterFlags.tempHiddenIssueResurfaceDelay = Duration.ZERO
SafetyCenterFlags.resurfaceIssueMaxCounts =
@@ -2173,7 +2380,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesLowerOneResurfaces_lowerOneStillFilteredOut() {
SafetyCenterFlags.resurfaceIssueMaxCounts =
mapOf(
@@ -2236,7 +2443,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_duplicateIssuesTopOneResurfaces_topOneShown() {
SafetyCenterFlags.resurfaceIssueMaxCounts =
mapOf(
@@ -2297,7 +2504,7 @@ class SafetyCenterManagerTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun getSafetyCenterData_dupIssuesTopOneResolved_bottomOneReemergesAfterTemporaryHiddenPeriod() {
SafetyCenterFlags.tempHiddenIssueResurfaceDelay = RESURFACE_DELAY
safetyCenterTestHelper.setConfig(
@@ -2831,7 +3038,7 @@ class SafetyCenterManagerTest {
safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
assertThat(group.summary)
- .isEqualTo(safetyCenterResourcesContext.getStringByName("group_unknown_summary"))
+ .isEqualTo(safetyCenterResourcesApk.getStringByName("group_unknown_summary"))
assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_UNKNOWN)
}
@@ -2845,7 +3052,7 @@ class SafetyCenterManagerTest {
.getGroup(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
assertThat(initialGroup.summary)
- .isEqualTo(safetyCenterResourcesContext.getStringByName("group_unknown_summary"))
+ .isEqualTo(safetyCenterResourcesApk.getStringByName("group_unknown_summary"))
assertThat(initialGroup.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_UNKNOWN)
safetyCenterTestHelper.setData(DYNAMIC_BAREBONE_ID, safetySourceTestData.unspecified)
@@ -3340,7 +3547,7 @@ class SafetyCenterManagerTest {
assertThat(error)
.isEqualTo(
SafetyCenterErrorDetails(
- safetyCenterResourcesContext.getStringByName("resolving_action_error")
+ safetyCenterResourcesApk.getStringByName("resolving_action_error")
)
)
}
@@ -3374,7 +3581,7 @@ class SafetyCenterManagerTest {
assertThat(error)
.isEqualTo(
SafetyCenterErrorDetails(
- safetyCenterResourcesContext.getStringByName("resolving_action_error")
+ safetyCenterResourcesApk.getStringByName("resolving_action_error")
)
)
}
@@ -3538,46 +3745,6 @@ class SafetyCenterManagerTest {
}
@Test
- fun lockScreenSource_withoutReplaceLockScreenIconActionFlag_doesntReplace() {
- // Must have a screen lock for the icon action to be set
- assumeTrue(ScreenLockHelper.isDeviceSecure(context))
- safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.settingsLockScreenSourceConfig)
- val listener = safetyCenterTestHelper.addListener()
- SafetyCenterFlags.replaceLockScreenIconAction = false
-
- safetyCenterManager.refreshSafetySourcesWithPermission(REFRESH_REASON_PAGE_OPEN)
- // Skip loading data.
- listener.receiveSafetyCenterData()
-
- val lockScreenSafetyCenterData = listener.receiveSafetyCenterData()
- val lockScreenEntry = lockScreenSafetyCenterData.entriesOrGroups.first().entry!!
- val entryPendingIntent = lockScreenEntry.pendingIntent!!
- val iconActionPendingIntent = lockScreenEntry.iconAction!!.pendingIntent
- // This test passes for now but will eventually start failing once we introduce the fix in
- // the Settings app. This will warn if the assumption is failed rather than fail, at which
- // point we can remove this test (and potentially even this magnificent hack).
- assumeTrue(iconActionPendingIntent == entryPendingIntent)
- }
-
- @Test
- fun lockScreenSource_withReplaceLockScreenIconActionFlag_replaces() {
- // Must have a screen lock for the icon action to be set
- assumeTrue(ScreenLockHelper.isDeviceSecure(context))
- safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.settingsLockScreenSourceConfig)
- val listener = safetyCenterTestHelper.addListener()
-
- safetyCenterManager.refreshSafetySourcesWithPermission(REFRESH_REASON_PAGE_OPEN)
- // Skip loading data.
- listener.receiveSafetyCenterData()
-
- val lockScreenSafetyCenterData = listener.receiveSafetyCenterData()
- val lockScreenEntry = lockScreenSafetyCenterData.entriesOrGroups.first().entry!!
- val entryPendingIntent = lockScreenEntry.pendingIntent!!
- val iconActionPendingIntent = lockScreenEntry.iconAction!!.pendingIntent
- assertThat(iconActionPendingIntent).isNotEqualTo(entryPendingIntent)
- }
-
- @Test
fun beforeAnyDataSet_noLastUpdatedTimestamps() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -3629,6 +3796,17 @@ class SafetyCenterManagerTest {
assertThat(lastUpdated[key]).isNotNull()
}
+ @Test
+ fun setSafetySourceData_dynamicHiddenWithIssueOnlyData_allowed() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.hiddenSourceConfig)
+ val expectedData = SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue)
+
+ safetyCenterTestHelper.setData(DYNAMIC_HIDDEN_ID, expectedData)
+
+ val actualData = safetyCenterManager.getSafetySourceDataWithPermission(DYNAMIC_HIDDEN_ID)
+ assertThat(actualData).isEqualTo(expectedData)
+ }
+
private fun dumpLastUpdated(): Map<String, String> {
val dump = SystemUtil.runShellCommand("dumpsys safety_center data")
return dump
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt
index 70d6468fa..9c9e9b009 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt
@@ -28,19 +28,21 @@ import android.safetycenter.SafetyCenterStatus
import android.safetycenter.SafetyEvent
import android.safetycenter.SafetySourceErrorDetails
import android.safetycenter.SafetySourceIssue
-import android.safetycenter.functional.testing.NotificationCharacteristics
-import android.safetycenter.functional.testing.TestNotificationListener
+import android.service.notification.StatusBarNotification
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.util.DisableAnimationRule
+import com.android.compatibility.common.util.FreezeRotationRule
import com.android.safetycenter.pendingintents.PendingIntentSender
+import com.android.safetycenter.testing.Coroutines
import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
+import com.android.safetycenter.testing.NotificationCharacteristics
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.executeBlockAndExit
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.clearAllSafetySourceDataForTestsWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.reportSafetySourceErrorWithPermission
import com.android.safetycenter.testing.SafetyCenterFlags
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_1
@@ -48,20 +50,23 @@ import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_5
import com.android.safetycenter.testing.SafetyCenterTestData
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceIntentHandler.Request
import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
import com.android.safetycenter.testing.SafetySourceReceiver
import com.android.safetycenter.testing.SafetySourceTestData
import com.android.safetycenter.testing.SafetySourceTestData.Companion.ISSUE_TYPE_ID
import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import com.android.safetycenter.testing.StatusBarNotificationWithChannel
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
+import com.android.safetycenter.testing.TestNotificationListener
import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueDisplayed
import com.google.common.truth.Truth.assertThat
import java.time.Duration
import kotlin.test.assertFailsWith
import kotlinx.coroutines.TimeoutCancellationException
-import org.junit.After
-import org.junit.Assume.assumeTrue
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -74,41 +79,23 @@ class SafetyCenterNotificationTest {
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
private val safetyCenterManager =
requireNotNull(context.getSystemService(SafetyCenterManager::class.java)) {
- "Could not get system service"
+ "Could not get SafetyCenterManager"
}
- // JUnit's Assume is not supported in @BeforeClass by the CTS tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2)
+ val safetyCenterTestRule =
+ SafetyCenterTestRule(safetyCenterTestHelper, withNotifications = true)
+ @get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
@Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
-
- @Before
- fun setUp() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
- TestNotificationListener.setup()
+ fun enableNotificationsForTestSourceBeforeTest() {
SafetyCenterFlags.notificationsEnabled = true
setFlagsForImmediateNotifications(SINGLE_SOURCE_ID)
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
}
- @After
- fun tearDown() {
- if (!shouldRunTests) {
- return
- }
- // It is important to reset the notification listener last because it waits/ensures that
- // all notifications have been removed before returning.
- safetyCenterTestHelper.reset()
- TestNotificationListener.reset()
- }
-
@Test
fun setSafetySourceData_withNoIssue_noNotification() {
safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
@@ -153,7 +140,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_withNotificationBehaviorNever_noNotification() {
val data =
safetySourceTestData
@@ -172,7 +159,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_withNotificationBehaviorDelay_noImmediateNotification() {
SafetyCenterFlags.notificationsMinDelay = Duration.ofDays(1)
val data =
@@ -192,7 +179,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_withNotificationBehaviorDelay_sendsNotificationAfterDelay() {
SafetyCenterFlags.notificationsMinDelay = Duration.ofDays(1)
val delayedNotificationIssue =
@@ -237,7 +224,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_withNotificationBehaviorDelayOfZero_sendsNotificationImmediately() {
SafetyCenterFlags.immediateNotificationBehaviorIssues = emptySet()
SafetyCenterFlags.notificationsMinDelay = Duration.ofSeconds(0)
@@ -264,7 +251,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_withNotificationBehaviorImmediately_sendsNotification() {
SafetyCenterFlags.immediateNotificationBehaviorIssues = emptySet()
val data =
@@ -309,8 +296,8 @@ class SafetyCenterNotificationTest {
@Test
fun setSafetySourceData_issueWithTwoActions_notificationWithTwoActions() {
- val intent1 = safetySourceTestData.testActivityRedirectPendingIntent(identifier = "1")
- val intent2 = safetySourceTestData.testActivityRedirectPendingIntent(identifier = "2")
+ val intent1 = safetySourceTestData.createTestActivityRedirectPendingIntent(identifier = "1")
+ val intent2 = safetySourceTestData.createTestActivityRedirectPendingIntent(identifier = "2")
val data =
safetySourceTestData
@@ -341,7 +328,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_withNotificationsAllowedForSourceByConfig_sendsNotification() {
SafetyCenterFlags.notificationsAllowedSources = emptySet()
SafetyCenterFlags.immediateNotificationBehaviorIssues = emptySet()
@@ -372,10 +359,10 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_withCustomNotification_usesCustomValues() {
- val intent1 = safetySourceTestData.testActivityRedirectPendingIntent(identifier = "1")
- val intent2 = safetySourceTestData.testActivityRedirectPendingIntent(identifier = "2")
+ val intent1 = safetySourceTestData.createTestActivityRedirectPendingIntent(identifier = "1")
+ val intent2 = safetySourceTestData.createTestActivityRedirectPendingIntent(identifier = "2")
val notification =
SafetySourceIssue.Notification.Builder("Custom title", "Custom text")
@@ -397,7 +384,7 @@ class SafetyCenterNotificationTest {
SafetySourceIssue.Action.Builder(
"default_action",
"Default action",
- safetySourceTestData.testActivityRedirectPendingIntent
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
)
.build()
)
@@ -418,7 +405,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_withEmptyCustomActions_notificationHasNoActions() {
val notification =
SafetySourceIssue.Notification.Builder("Custom title", "Custom text")
@@ -435,7 +422,7 @@ class SafetyCenterNotificationTest {
SafetySourceIssue.Action.Builder(
"default_action",
"Default action",
- safetySourceTestData.testActivityRedirectPendingIntent
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
)
.build()
)
@@ -488,7 +475,7 @@ class SafetyCenterNotificationTest {
SafetySourceIssue.Action.Builder(
"new_action",
"New action",
- safetySourceTestData.testActivityRedirectPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent(
identifier = "new_action"
)
)
@@ -539,6 +526,22 @@ class SafetyCenterNotificationTest {
TestNotificationListener.waitForZeroNotifications()
}
+ // TODO(b/284271124): Decide what to do with existing notifications when flag flipped off
+ @Test
+ fun setSafetySourceData_removingAnIssue_afterFlagTurnedOff_noNotificationChanges() {
+ val data1 = safetySourceTestData.recommendationWithAccountIssue
+ val data2 = safetySourceTestData.information
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data1)
+
+ TestNotificationListener.waitForSingleNotification()
+
+ SafetyCenterFlags.notificationsEnabled = false
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data2)
+
+ TestNotificationListener.waitForZeroNotificationEvents()
+ }
+
@Test
fun reportSafetySourceError_sourceWithNotification_cancelsNotification() {
val data = safetySourceTestData.recommendationWithAccountIssue
@@ -630,7 +633,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_duplicateIssues_sendsOneNotification() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -660,7 +663,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun setSafetySourceData_duplicateIssueOfLowerSeverityDismissed_sendsNotification() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -784,7 +787,7 @@ class SafetyCenterNotificationTest {
}
@Test
- @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
fun dismissingNotification_withDuplicateIssues_allDismissed() {
safetyCenterTestHelper.setConfig(
safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
@@ -898,13 +901,135 @@ class SafetyCenterNotificationTest {
sendActionPendingIntentAndWaitWithPermission(action)
- TestNotificationListener.waitForSingleNotificationMatching(
- NotificationCharacteristics(
- "Issue solved",
- "",
- actions = emptyList(),
+ TestNotificationListener.waitForSuccessNotification("Issue solved")
+ }
+
+ @Test
+ fun successNotification_notificationHasAutoCancel() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage
+ )
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+ val action =
+ notificationWithChannel.statusBarNotification.notification.actions.firstOrNull()
+ checkNotNull(action) { "Notification action unexpectedly null" }
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ sendActionPendingIntentAndWaitWithPermission(action)
+
+ TestNotificationListener.waitForSuccessNotification("Issue solved") {
+ assertThat(it.hasAutoCancel()).isTrue()
+ }
+ }
+
+ // TODO(b/284271124): Decide what to do with existing notifications when flag flipped off
+ @Test
+ fun sendActionPendingIntent_flagDisabled_pendingIntentNotSentToSource() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage
+ )
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+ val action =
+ notificationWithChannel.statusBarNotification.notification.actions.firstOrNull()
+ checkNotNull(action) { "Notification action unexpectedly null" }
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ SafetyCenterFlags.notificationsEnabled = false
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ sendActionPendingIntentAndWaitWithPermission(action, timeout = TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun sendActionPendingIntent_sourceStateChangedSafetyEvent_successNotification() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage
+ )
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+ val action =
+ notificationWithChannel.statusBarNotification.notification.actions.firstOrNull()
+ checkNotNull(action) { "Notification action unexpectedly null" }
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(
+ safetySourceTestData.information,
+ overrideSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
)
)
+
+ sendActionPendingIntentAndWaitWithPermission(action)
+
+ TestNotificationListener.waitForSuccessNotification("Issue solved")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
+ fun sendActionPendingIntent_actionIdDiffersFromIssueActionId_successNotification() {
+ val notification =
+ SafetySourceIssue.Notification.Builder("Custom title", "Custom text")
+ .addAction(
+ SafetySourceIssue.Action.Builder(
+ "notification_action_id",
+ "Solve now!",
+ safetySourceTestData.resolvingActionPendingIntent(
+ sourceIssueActionId = "notification_action_id"
+ )
+ )
+ .setWillResolve(true)
+ .setSuccessMessage("Solved via notification action :)")
+ .build()
+ )
+ .build()
+ val data =
+ safetySourceTestData
+ .defaultCriticalDataBuilder()
+ .clearIssues()
+ .addIssue(
+ safetySourceTestData
+ .defaultCriticalResolvingIssueBuilder()
+ .clearActions()
+ .addAction(
+ SafetySourceIssue.Action.Builder(
+ "issue_action_id",
+ "Default action",
+ safetySourceTestData.resolvingActionPendingIntent(
+ sourceIssueActionId = "issue_action_id"
+ )
+ )
+ .setWillResolve(true)
+ .setSuccessMessage("Solved via issue action :(")
+ .build()
+ )
+ .setCustomNotification(notification)
+ .setNotificationBehavior(
+ SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+ val action =
+ notificationWithChannel.statusBarNotification.notification.actions.firstOrNull()
+ checkNotNull(action) { "Notification action unexpectedly null" }
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ sendActionPendingIntentAndWaitWithPermission(action)
+
+ TestNotificationListener.waitForSuccessNotification("Solved via notification action :)")
}
@Test
@@ -941,12 +1066,10 @@ class SafetyCenterNotificationTest {
safetySourceTestData.recommendationWithDeviceIssue
)
val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
- val contentIntent = notificationWithChannel.statusBarNotification.notification.contentIntent
- executeBlockAndExit(
- launchActivity = { PendingIntentSender.send(contentIntent) },
- block = { waitSourceIssueDisplayed(safetySourceTestData.recommendationDeviceIssue) }
- )
+ sendContentPendingIntent(notificationWithChannel) {
+ waitSourceIssueDisplayed(safetySourceTestData.recommendationDeviceIssue)
+ }
}
@Test
@@ -962,34 +1085,69 @@ class SafetyCenterNotificationTest {
safetySourceTestData.criticalWithResolvingGeneralIssue
)
val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
- val contentIntent = notificationWithChannel.statusBarNotification.notification.contentIntent
- executeBlockAndExit(
- launchActivity = { PendingIntentSender.send(contentIntent) },
- block = {
- waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
- waitSourceIssueDisplayed(safetySourceTestData.recommendationGeneralIssue)
- }
+ sendContentPendingIntent(notificationWithChannel) {
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ waitSourceIssueDisplayed(safetySourceTestData.recommendationDeviceIssue)
+ }
+ }
+
+ @Test
+ fun whenGreenIssue_notificationHasAutoCancel() {
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+
+ assertThat(notificationWithChannel.statusBarNotification.hasAutoCancel()).isTrue()
+ }
+
+ @Test
+ fun whenNotGreenIssue_notificationDoesntHaveAutoCancel() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithDeviceIssue
)
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+
+ assertThat(notificationWithChannel.statusBarNotification.hasAutoCancel()).isFalse()
}
- companion object {
- private val SafetyCenterData.inFlightActions: List<SafetyCenterIssue.Action>
+ private companion object {
+ val SafetyCenterData.inFlightActions: List<SafetyCenterIssue.Action>
get() = issues.flatMap { it.actions }.filter { it.isInFlight }
- private fun sendActionPendingIntentAndWaitWithPermission(action: Notification.Action) {
+ fun sendActionPendingIntentAndWaitWithPermission(
+ action: Notification.Action,
+ timeout: Duration = Coroutines.TIMEOUT_LONG
+ ) {
callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
PendingIntentSender.send(action.actionIntent)
// Sending the action's PendingIntent above is asynchronous and we need to wait for
// it to be received by the fake receiver below.
- SafetySourceReceiver.receiveResolveAction()
+ SafetySourceReceiver.receiveResolveAction(timeout)
}
}
- private fun setFlagsForImmediateNotifications(vararg sourceIds: String) {
+ fun setFlagsForImmediateNotifications(vararg sourceIds: String) {
SafetyCenterFlags.notificationsAllowedSources = sourceIds.toSet()
SafetyCenterFlags.immediateNotificationBehaviorIssues =
sourceIds.map { "$it/$ISSUE_TYPE_ID" }.toSet()
}
+
+ fun StatusBarNotification.hasAutoCancel(): Boolean {
+ val autoCancelMask = notification.flags and Notification.FLAG_AUTO_CANCEL
+ return autoCancelMask != 0
+ }
+
+ fun sendContentPendingIntent(
+ statusBarNotificationWithChannel: StatusBarNotificationWithChannel,
+ andExecuteBlock: () -> Unit = {}
+ ) {
+ val contentIntent =
+ statusBarNotificationWithChannel.statusBarNotification.notification.contentIntent
+ executeBlockAndExit(
+ launchActivity = { PendingIntentSender.send(contentIntent) },
+ block = andExecuteBlock
+ )
+ }
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterShellCommandsTest.kt
index b0860d751..7c5b41944 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterShellCommandsTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,20 +14,23 @@
* limitations under the License.
*/
-package android.safetycenter.cts
+package android.safetycenter.functional
+import android.Manifest.permission.INTERACT_ACROSS_USERS
+import android.app.ActivityManager
import android.content.Context
import android.safetycenter.SafetyCenterManager
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.isSafetyCenterEnabledWithPermission
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import com.android.safetycenter.testing.deviceSupportsSafetyCenter
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
-/** CTS tests for Safety Center's shell commands. */
+/** Tests for Safety Center's shell commands. */
@RunWith(AndroidJUnit4::class)
class SafetyCenterShellCommandsTest {
private val context: Context = getApplicationContext()
@@ -54,6 +57,39 @@ class SafetyCenterShellCommandsTest {
assertThat(packageName).isEqualTo(context.packageManager.permissionControllerPackageName)
}
+ @Test
+ fun clearData_executesSuccessfully() {
+ executeShellCommand("cmd safety_center clear-data")
+ }
+
+ @Test
+ fun refresh_executesSuccessfully() {
+ val currentUser =
+ callWithShellPermissionIdentity(INTERACT_ACROSS_USERS) {
+ ActivityManager.getCurrentUser()
+ }
+ executeShellCommand("cmd safety_center refresh --reason OTHER --user $currentUser")
+ }
+
+ @Test
+ fun help_containsAllCommands() {
+ val help = executeShellCommand("cmd safety_center help")
+
+ assertThat(help).contains("help")
+ assertThat(help).contains("enabled")
+ assertThat(help).contains("supported")
+ assertThat(help).contains("package-name")
+ assertThat(help).contains("clear-data")
+ assertThat(help).contains("refresh")
+ }
+
+ @Test
+ fun dump_containsSafetyCenterService() {
+ val dump = executeShellCommand("dumpsys safety_center")
+
+ assertThat(dump).contains("SafetyCenterService")
+ }
+
private fun executeShellCommand(command: String): String =
- SystemUtil.runShellCommand(command).trim()
+ SystemUtil.runShellCommandOrThrow(command).trim()
}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetySourceDataFixesTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetySourceDataFixesTest.kt
new file mode 100644
index 000000000..4ba293eb9
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetySourceDataFixesTest.kt
@@ -0,0 +1,298 @@
+package android.safetycenter.functional
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
+import android.safetycenter.SafetySourceIssue
+import android.safetycenter.SafetySourceStatus
+import androidx.annotation.RequiresApi
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.preconditions.ScreenLockHelper
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetySourceDataWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.refreshSafetySourcesWithPermission
+import com.android.safetycenter.testing.SafetyCenterFlags
+import com.android.safetycenter.testing.SafetyCenterTestConfigs
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_1
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_2
+import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
+import com.android.safetycenter.testing.SafetySourceTestData
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Functional tests for "fixes" applied to Safety Source data received by [SafetyCenterManager]. */
+@RunWith(AndroidJUnit4::class)
+class SafetySourceDataFixesTest {
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
+ private val safetySourceTestData = SafetySourceTestData(context)
+ private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
+ private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
+
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+
+ @Test
+ fun lockScreenSource_withoutReplaceLockScreenIconActionFlag_doesntReplace() {
+ // Must have a screen lock for the icon action to be set
+ assumeTrue(ScreenLockHelper.isDeviceSecure(context))
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.settingsLockScreenSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ SafetyCenterFlags.replaceLockScreenIconAction = false
+
+ safetyCenterManager.refreshSafetySourcesWithPermission(
+ SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
+ )
+ // Skip loading data.
+ listener.receiveSafetyCenterData()
+
+ val lockScreenSafetyCenterData = listener.receiveSafetyCenterData()
+ val lockScreenEntry = lockScreenSafetyCenterData.entriesOrGroups.first().entry!!
+ val entryPendingIntent = lockScreenEntry.pendingIntent!!
+ val iconActionPendingIntent = lockScreenEntry.iconAction!!.pendingIntent
+ // This test passes for now but will eventually start failing once we introduce the fix in
+ // the Settings app. This will warn if the assumption is failed rather than fail, at which
+ // point we can remove this test (and potentially even this magnificent hack).
+ assumeTrue(iconActionPendingIntent == entryPendingIntent)
+ }
+
+ @Test
+ fun lockScreenSource_withReplaceLockScreenIconActionFlag_replaces() {
+ // Must have a screen lock for the icon action to be set
+ assumeTrue(ScreenLockHelper.isDeviceSecure(context))
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.settingsLockScreenSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithPermission(
+ SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
+ )
+ // Skip loading data.
+ listener.receiveSafetyCenterData()
+
+ val lockScreenSafetyCenterData = listener.receiveSafetyCenterData()
+ val lockScreenEntry = lockScreenSafetyCenterData.entriesOrGroups.first().entry!!
+ val entryPendingIntent = lockScreenEntry.pendingIntent!!
+ val iconActionPendingIntent = lockScreenEntry.iconAction!!.pendingIntent
+ assertThat(iconActionPendingIntent).isNotEqualTo(entryPendingIntent)
+ }
+
+ @Test
+ fun defaultActionOverride_issue_overridesMatchingActions() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val targetActionId = "TargetActionId"
+ SafetyCenterFlags.actionsToOverrideWithDefaultIntent =
+ mapOf(SINGLE_SOURCE_ID to setOf(targetActionId, "AdditionalActionId"))
+
+ val originalPendingIntent = pendingIntent(Intent("blah.wrong.INTENT"))
+ val dataWithActionToOverride =
+ sourceDataBuilder()
+ .addIssue(
+ issueBuilder()
+ .clearActions()
+ .addAction(
+ safetySourceTestData.action(
+ id = targetActionId,
+ pendingIntent = originalPendingIntent
+ )
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataWithActionToOverride)
+
+ val overriddenPendingIntent =
+ safetyCenterManager
+ .getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)!!
+ .issues[0]
+ .actions[0]
+ .pendingIntent
+ val expectedPendingIntent =
+ pendingIntent(
+ Intent(SafetyCenterTestConfigs.ACTION_TEST_ACTIVITY).setPackage(context.packageName)
+ )
+ assertThat(intentsFilterEqual(overriddenPendingIntent, expectedPendingIntent)).isTrue()
+ }
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
+ fun defaultActionOverride_notification_overridesMatchingActions() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val targetActionId = "TargetActionId"
+ SafetyCenterFlags.actionsToOverrideWithDefaultIntent =
+ mapOf(SINGLE_SOURCE_ID to setOf(targetActionId, "AdditionalActionId"))
+
+ val originalPendingIntent = pendingIntent(Intent("blah.wrong.INTENT"))
+ val dataWithNotificationActionToOverride =
+ sourceDataBuilder()
+ .addIssue(
+ issueBuilder()
+ .setCustomNotification(
+ notification(
+ safetySourceTestData.action(
+ id = targetActionId,
+ pendingIntent = originalPendingIntent
+ )
+ )
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataWithNotificationActionToOverride)
+
+ val overriddenPendingIntent =
+ safetyCenterManager
+ .getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)!!
+ .issues[0]
+ .customNotification!!
+ .actions[0]
+ .pendingIntent
+ val expectedPendingIntent =
+ pendingIntent(
+ Intent(SafetyCenterTestConfigs.ACTION_TEST_ACTIVITY).setPackage(context.packageName)
+ )
+ assertThat(intentsFilterEqual(overriddenPendingIntent, expectedPendingIntent)).isTrue()
+ }
+
+ @Test
+ fun defaultActionOverride_sameActionIdDifferentSource_doesNotOverride() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ val targetActionId = "TargetActionId"
+ SafetyCenterFlags.actionsToOverrideWithDefaultIntent =
+ mapOf(SOURCE_ID_1 to setOf(targetActionId, "AdditionalActionId"))
+
+ val originalPendingIntent = pendingIntent(Intent("blah.wrong.INTENT"))
+ val dataWithoutActionToOverride =
+ sourceDataBuilder()
+ .addIssue(
+ issueBuilder()
+ .clearActions()
+ .addAction(
+ safetySourceTestData.action(
+ id = targetActionId,
+ pendingIntent = originalPendingIntent
+ )
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2, // Different source ID
+ dataWithoutActionToOverride
+ )
+
+ val actualPendingIntent =
+ safetyCenterManager
+ .getSafetySourceDataWithPermission(SOURCE_ID_2)!!
+ .issues[0]
+ .actions[0]
+ .pendingIntent
+ assertThat(intentsFilterEqual(actualPendingIntent, originalPendingIntent)).isTrue()
+ }
+
+ @Test
+ fun defaultActionOverride_sameSourceDifferentActionId_doesNotOverride() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ SafetyCenterFlags.actionsToOverrideWithDefaultIntent =
+ mapOf(SOURCE_ID_1 to setOf("TargetActionId"))
+
+ val originalPendingIntent = pendingIntent(Intent("blah.wrong.INTENT"))
+ val dataWithoutActionToOverride =
+ sourceDataBuilder()
+ .addIssue(
+ issueBuilder()
+ .clearActions()
+ .addAction(
+ safetySourceTestData.action(
+ id = "DifferentActionId",
+ pendingIntent = originalPendingIntent
+ )
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SOURCE_ID_1, dataWithoutActionToOverride)
+
+ val actualPendingIntent =
+ safetyCenterManager
+ .getSafetySourceDataWithPermission(SOURCE_ID_1)!!
+ .issues[0]
+ .actions[0]
+ .pendingIntent
+ assertThat(intentsFilterEqual(actualPendingIntent, originalPendingIntent)).isTrue()
+ }
+
+ @Test
+ fun defaultActionOverride_noDefaultIntent_doesNotOverride() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceInvalidIntentConfig)
+ val targetActionId = "TargetActionId"
+ SafetyCenterFlags.actionsToOverrideWithDefaultIntent =
+ mapOf(SINGLE_SOURCE_ID to setOf(targetActionId, "AdditionalActionId"))
+
+ val originalPendingIntent = pendingIntent(Intent("blah.wrong.INTENT"))
+ val dataWithActionToOverride =
+ sourceDataBuilder()
+ .addIssue(
+ issueBuilder()
+ .clearActions()
+ .addAction(
+ safetySourceTestData.action(
+ id = targetActionId,
+ pendingIntent = originalPendingIntent
+ )
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataWithActionToOverride)
+
+ val actualPendingIntent =
+ safetyCenterManager
+ .getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)!!
+ .issues[0]
+ .actions[0]
+ .pendingIntent
+ assertThat(intentsFilterEqual(actualPendingIntent, originalPendingIntent)).isTrue()
+ }
+
+ private fun issueBuilder() = safetySourceTestData.defaultInformationIssueBuilder()
+
+ private fun pendingIntent(intent: Intent) =
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+
+ companion object {
+ private fun sourceDataBuilder() =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("OK", "Blah", SEVERITY_LEVEL_INFORMATION).build()
+ )
+
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private fun notification(action: SafetySourceIssue.Action) =
+ SafetySourceIssue.Notification.Builder("Blah", "Bleh").addAction(action).build()
+
+ private fun intentsFilterEqual(
+ actualPendingIntent: PendingIntent,
+ expectedPendingIntent: PendingIntent?
+ ) =
+ callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") {
+ actualPendingIntent.intentFilterEquals(expectedPendingIntent)
+ }
+ }
+}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt
index 9c4d720d3..73d6a0737 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt
@@ -16,29 +16,23 @@
package android.safetycenter.functional.ui
-import android.Manifest.permission.MANAGE_SENSOR_PRIVACY
-import android.Manifest.permission.OBSERVE_SENSOR_PRIVACY
import android.content.Context
-import android.hardware.SensorPrivacyManager
import android.hardware.SensorPrivacyManager.Sensors.CAMERA
import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
-import android.hardware.SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE
-import android.platform.test.rule.ScreenRecordRule
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.uiautomator.By
import com.android.compatibility.common.util.DisableAnimationRule
import com.android.compatibility.common.util.FreezeRotationRule
+import com.android.safetycenter.testing.EnableSensorRule
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterQsActivity
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestHelper
-import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import com.android.safetycenter.testing.SafetyCenterTestRule
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.android.safetycenter.testing.UiTestHelper.waitAllTextDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitPageTitleDisplayed
-import org.junit.After
-import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -48,66 +42,22 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SafetyCenterQsActivityTest {
- @get:Rule val disableAnimationRule = DisableAnimationRule()
-
- @get:Rule val freezeRotationRule = FreezeRotationRule()
-
- @get:Rule val screenRecordRule = ScreenRecordRule()
-
private val context: Context = getApplicationContext()
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
- private val sensorPrivacyManager = context.getSystemService(SensorPrivacyManager::class.java)!!
- private var shouldRunTests =
- context.deviceSupportsSafetyCenter() &&
- deviceSupportsSensorToggle(CAMERA) &&
- deviceSupportsSensorToggle(MICROPHONE)
- private var oldCameraState: Boolean = false
- private var oldMicrophoneState: Boolean = false
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val enableCameraRule = EnableSensorRule(context, CAMERA)
+ @get:Rule(order = 3) val enableMicrophoneRule = EnableSensorRule(context, MICROPHONE)
+ @get:Rule(order = 4) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+ @get:Rule(order = 5) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 6) val freezeRotationRule = FreezeRotationRule()
@Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
+ fun setTestConfigBeforeTest() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
}
- @After
- fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
- }
-
- @Before
- fun enablePrivacyControlsBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- oldCameraState = isSensorEnabled(CAMERA)
- setSensorState(CAMERA, true)
-
- oldMicrophoneState = isSensorEnabled(MICROPHONE)
- setSensorState(MICROPHONE, true)
- }
-
- @After
- fun restorePrivacyControlsAfterTest() {
- if (!shouldRunTests) {
- return
- }
- setSensorState(CAMERA, oldCameraState)
- setSensorState(MICROPHONE, oldMicrophoneState)
- }
-
@Test
fun launchActivity_fromQuickSettings_hasContentDescriptions() {
context.launchSafetyCenterQsActivity {
@@ -122,7 +72,6 @@ class SafetyCenterQsActivityTest {
}
@Test
- @ScreenRecordRule.ScreenRecord
fun launchActivity_togglePrivacyControls_hasUpdatedDescriptions() {
context.launchSafetyCenterQsActivity {
// Toggle privacy controls
@@ -134,25 +83,4 @@ class SafetyCenterQsActivityTest {
waitDisplayed(By.desc("Switch. Mic access. Blocked"))
}
}
-
- private fun deviceSupportsSensorToggle(sensor: Int): Boolean {
- return sensorPrivacyManager.supportsSensorToggle(sensor) &&
- sensorPrivacyManager.supportsSensorToggle(TOGGLE_TYPE_SOFTWARE, sensor)
- }
-
- private fun isSensorEnabled(sensor: Int): Boolean {
- val isSensorDisabled =
- callWithShellPermissionIdentity(OBSERVE_SENSOR_PRIVACY) {
- sensorPrivacyManager.isSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, sensor)
- }
- return !isSensorDisabled
- }
-
- private fun setSensorState(sensor: Int, enabled: Boolean) {
- val disableSensor = !enabled
- // The sensor is enabled iff the privacy control is disabled.
- callWithShellPermissionIdentity(MANAGE_SENSOR_PRIVACY, OBSERVE_SENSOR_PRIVACY) {
- sensorPrivacyManager.setSensorPrivacy(sensor, disableSensor)
- }
- }
}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt
index f4ed328ae..f76a52256 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt
@@ -17,31 +17,31 @@
package android.safetycenter.functional.ui
import android.content.Context
+import android.os.Build
+import android.safetycenter.SafetySourceData
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.uiautomator.By
import com.android.compatibility.common.util.DisableAnimationRule
import com.android.compatibility.common.util.FreezeRotationRule
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
import com.android.safetycenter.testing.SafetyCenterTestData
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceIntentHandler.Request
import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
import com.android.safetycenter.testing.SafetySourceReceiver
import com.android.safetycenter.testing.SafetySourceTestData
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.android.safetycenter.testing.UiTestHelper.RESCAN_BUTTON_LABEL
import com.android.safetycenter.testing.UiTestHelper.waitAllTextDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitButtonDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitButtonNotDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitNotDisplayed
-import org.junit.After
-import org.junit.Assume.assumeTrue
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -50,42 +50,17 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SafetyCenterStatusCardTest {
- @get:Rule val disableAnimationRule = DisableAnimationRule()
-
- @get:Rule val freezeRotationRule = FreezeRotationRule()
-
private val context: Context = getApplicationContext()
-
- private val safetyCenterResourcesContext = SafetyCenterResourcesContext.forTests(context)
+ private val safetyCenterResourcesApk = SafetyCenterResourcesApk.forTests(context)
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestData = SafetyCenterTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
- // JUnit's Assume is not supported in @BeforeClass by the tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
-
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
-
- @Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
- }
-
- @After
- fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
- }
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+ @get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
@Test
fun withUnknownStatus_displaysScanningOnLoad() {
@@ -93,8 +68,8 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName("scanning_title"),
- safetyCenterResourcesContext.getStringByName("loading_summary")
+ safetyCenterResourcesApk.getStringByName("scanning_title"),
+ safetyCenterResourcesApk.getStringByName("loading_summary")
)
}
}
@@ -109,8 +84,8 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
- safetyCenterResourcesContext.getStringByName("loading_summary")
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesApk.getStringByName("loading_summary")
)
}
}
@@ -122,12 +97,8 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity(withReceiverPermission = true) {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_ok_review_title"
- ),
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_ok_review_summary"
- )
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_review_title"),
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_review_summary")
)
waitButtonDisplayed(RESCAN_BUTTON_LABEL)
}
@@ -136,6 +107,7 @@ class SafetyCenterStatusCardTest {
@Test
fun withInformationAndNoIssues_hasRescanButton() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.information)
SafetySourceReceiver.setResponse(
Request.Refresh(SINGLE_SOURCE_ID),
Response.SetData(safetySourceTestData.information)
@@ -143,8 +115,8 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity(withReceiverPermission = true) {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_summary")
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary")
)
waitButtonDisplayed(RESCAN_BUTTON_LABEL)
}
@@ -153,6 +125,7 @@ class SafetyCenterStatusCardTest {
@Test
fun withInformationAndNoIssues_hasContentDescriptions() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.information)
SafetySourceReceiver.setResponse(
Request.Refresh(SINGLE_SOURCE_ID),
Response.SetData(safetySourceTestData.information)
@@ -167,6 +140,7 @@ class SafetyCenterStatusCardTest {
@Test
fun withInformationIssue_doesNotHaveRescanButton() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
SafetySourceReceiver.setResponse(
Request.Refresh(SINGLE_SOURCE_ID),
Response.SetData(safetySourceTestData.informationWithIssue)
@@ -174,7 +148,7 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity(withReceiverPermission = true) {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
safetyCenterTestData.getAlertString(1)
)
waitButtonNotDisplayed(RESCAN_BUTTON_LABEL)
@@ -184,6 +158,10 @@ class SafetyCenterStatusCardTest {
@Test
fun withRecommendationIssue_doesNotHaveRescanButton() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
SafetySourceReceiver.setResponse(
Request.Refresh(SINGLE_SOURCE_ID),
Response.SetData(safetySourceTestData.recommendationWithGeneralIssue)
@@ -191,7 +169,7 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity(withReceiverPermission = true) {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName(
+ safetyCenterResourcesApk.getStringByName(
"overall_severity_level_safety_recommendation_title"
),
safetyCenterTestData.getAlertString(1)
@@ -203,6 +181,10 @@ class SafetyCenterStatusCardTest {
@Test
fun withCriticalWarningIssue_doesNotHaveRescanButton() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
SafetySourceReceiver.setResponse(
Request.Refresh(SINGLE_SOURCE_ID),
Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
@@ -210,7 +192,7 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity(withReceiverPermission = true) {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName(
+ safetyCenterResourcesApk.getStringByName(
"overall_severity_level_critical_safety_warning_title"
),
safetyCenterTestData.getAlertString(1)
@@ -222,6 +204,7 @@ class SafetyCenterStatusCardTest {
@Test
fun withKnownStatus_displaysScanningOnRescan() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.information)
SafetySourceReceiver.setResponse(
Request.Refresh(SINGLE_SOURCE_ID),
Response.SetData(safetySourceTestData.information)
@@ -229,15 +212,15 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity(withReceiverPermission = true) {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_summary")
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary")
)
waitButtonDisplayed(RESCAN_BUTTON_LABEL) { it.click() }
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName("scanning_title"),
- safetyCenterResourcesContext.getStringByName("loading_summary")
+ safetyCenterResourcesApk.getStringByName("scanning_title"),
+ safetyCenterResourcesApk.getStringByName("loading_summary")
)
}
}
@@ -245,6 +228,7 @@ class SafetyCenterStatusCardTest {
@Test
fun rescan_updatesDataAfterScanCompletes() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.information)
SafetySourceReceiver.setResponse(
Request.Refresh(SINGLE_SOURCE_ID),
Response.SetData(safetySourceTestData.information)
@@ -256,18 +240,28 @@ class SafetyCenterStatusCardTest {
context.launchSafetyCenterActivity(withReceiverPermission = true) {
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_summary")
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary")
)
waitButtonDisplayed(RESCAN_BUTTON_LABEL) { it.click() }
waitAllTextDisplayed(
- safetyCenterResourcesContext.getStringByName(
+ safetyCenterResourcesApk.getStringByName(
"overall_severity_level_safety_recommendation_title"
),
safetyCenterTestData.getAlertString(1)
)
}
}
+
+ /**
+ * Sets the given data for the given source ID if this test is running on T builds. This is a
+ * mitigation for b/301234118 which seems to only fail consistently on T.
+ */
+ private fun preSetDataOnT(sourceId: String, safetySourceData: SafetySourceData) {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
+ safetyCenterTestHelper.setData(sourceId, safetySourceData)
+ }
+ }
}
diff --git a/tests/functional/safetycenter/subpages/Android.bp b/tests/functional/safetycenter/subpages/Android.bp
new file mode 100644
index 000000000..4279ca26f
--- /dev/null
+++ b/tests/functional/safetycenter/subpages/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "SafetyCenterSubpagesTestCases",
+ defaults: ["mts-target-sdk-version-current"],
+ sdk_version: "test_current",
+ min_sdk_version: "30",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "androidx.test.monitor",
+ "compatibility-device-preconditions",
+ "kotlin-test",
+ "platform-test-rules",
+ "safety-center-test-util-lib",
+ ],
+ test_suites: [
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/functional/safetycenter/subpages/AndroidManifest.xml b/tests/functional/safetycenter/subpages/AndroidManifest.xml
new file mode 100644
index 000000000..ea59a99c6
--- /dev/null
+++ b/tests/functional/safetycenter/subpages/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.safetycenter.functional.subpages">
+ <application>
+
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Functional tests for SafetyCenter Subpages"
+ android:targetPackage="android.safetycenter.functional.subpages"/>
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+</manifest>
diff --git a/tests/functional/safetycenter/subpages/AndroidTest.xml b/tests/functional/safetycenter/subpages/AndroidTest.xml
new file mode 100644
index 000000000..c3245e9d7
--- /dev/null
+++ b/tests/functional/safetycenter/subpages/AndroidTest.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<configuration description="Config for SafetyCenter subpages testcases">
+
+ <object
+ class="com.android.tradefed.testtype.suite.module.Sdk34ModuleController"
+ type="module_controller"/>
+
+ <option name="config-descriptor:metadata" key="component" value="framework"/>
+ <option name="config-descriptor:metadata" key="parameter"
+ value="not_instant_app"/>
+ <option name="config-descriptor:metadata" key="parameter"
+ value="not_multi_abi"/>
+ <option name="config-descriptor:metadata" key="parameter"
+ value="secondary_user"/>
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" />
+ <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" />
+
+ <option name="test-suite-tag" value="functional"/>
+
+ <target_preparer
+ class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="SafetyCenterSubpagesTestCases.apk"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <!-- Ensure all broadcasts are dispatched prior to running our tests, to make sure they
+ aren't polluted by `BOOT_COMPLETED` or similar broadcasts still being delivered, which
+ causes our `ActivityManager#waitForBroadcastIdle()` calls to timeout. -->
+ <option name="run-command" value="am wait-for-broadcast-idle" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
+ <!-- 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" />
+ <!-- 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>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/user/0/android.safetycenter.functional.subpages/files" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="android.safetycenter.functional.subpages"/>
+ <option name="exclude-annotation" value="org.junit.Ignore"/>
+ <option name="runtime-hint" value="10m"/>
+ </test>
+</configuration>
diff --git a/tests/functional/safetycenter/subpages/TEST_MAPPING b/tests/functional/safetycenter/subpages/TEST_MAPPING
new file mode 100644
index 000000000..e6802586e
--- /dev/null
+++ b/tests/functional/safetycenter/subpages/TEST_MAPPING
@@ -0,0 +1,17 @@
+{
+ "presubmit": [
+ {
+ "name": "SafetyCenterSubpagesTestCases"
+ }
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "SafetyCenterSubpagesTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt b/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt
index 0c90029e0..7ad83b949 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt
+++ b/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt
@@ -17,13 +17,15 @@
package android.safetycenter.functional.ui
import android.content.Context
-import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.content.pm.PackageManager
+import android.hardware.SensorPrivacyManager
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
import android.os.Bundle
import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID
import android.safetycenter.config.SafetySource
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
import androidx.test.uiautomator.By
import com.android.compatibility.common.util.DisableAnimationRule
import com.android.compatibility.common.util.FreezeRotationRule
@@ -31,23 +33,24 @@ import com.android.compatibility.common.util.UiAutomatorUtils2
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.openPageAndExit
import com.android.safetycenter.testing.SafetyCenterFlags
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.PRIVACY_SOURCE_ID_1
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_1
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceTestData
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.android.safetycenter.testing.UiTestHelper.MORE_ISSUES_LABEL
import com.android.safetycenter.testing.UiTestHelper.clickMoreIssuesCard
import com.android.safetycenter.testing.UiTestHelper.resetRotation
import com.android.safetycenter.testing.UiTestHelper.waitAllTextDisplayed
+import com.android.safetycenter.testing.UiTestHelper.waitAllTextNotDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitButtonDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitPageTitleDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueNotDisplayed
import org.junit.After
-import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -55,42 +58,27 @@ import org.junit.runner.RunWith
/** Functional tests for the Privacy subpage in Safety Center. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
class PrivacySubpageTest {
- @get:Rule val disableAnimationRule = DisableAnimationRule()
-
- @get:Rule val freezeRotationRule = FreezeRotationRule()
-
private val context: Context = getApplicationContext()
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
+ private val sensorPrivacyManager: SensorPrivacyManager =
+ context.getSystemService(SensorPrivacyManager::class.java)!!
- // JUnit's Assume is not supported in @BeforeClass by the tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
-
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+ @get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
@Before
fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
SafetyCenterFlags.showSubpages = true
}
@After
fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
UiAutomatorUtils2.getUiDevice().resetRotation()
}
@@ -166,13 +154,20 @@ class PrivacySubpageTest {
extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, config.safetySourcesGroups.first().id)
context.launchSafetyCenterActivity(extras) {
- waitAllTextDisplayed(
- "Camera access",
- "Microphone access",
- "Show clipboard access",
- "Show passwords",
- "Location access"
+ waitAllText(
+ displayed = sensorPrivacyManager.supportsSensorToggle(CAMERA),
+ text = "Camera access"
+ )
+ waitAllText(
+ displayed = sensorPrivacyManager.supportsSensorToggle(MICROPHONE),
+ text = "Microphone access"
+ )
+ waitAllTextDisplayed("Show clipboard access")
+ waitAllText(
+ displayed = getPermissionControllerBool("config_display_show_password_toggle"),
+ text = "Show passwords"
)
+ waitAllTextDisplayed("Location access")
}
}
@@ -216,6 +211,34 @@ class PrivacySubpageTest {
}
}
+ private fun waitAllText(displayed: Boolean, text: String) {
+ if (displayed) {
+ waitAllTextDisplayed(text)
+ } else {
+ waitAllTextNotDisplayed(text)
+ }
+ }
+
+ private fun getPermissionControllerBool(resourceName: String): Boolean {
+ val permissionControllerContext = getPermissionControllerContext()
+ val resourceId =
+ permissionControllerContext.resources.getIdentifier(
+ resourceName,
+ "bool",
+ "com.android.permissioncontroller"
+ )
+ return permissionControllerContext.resources.getBoolean(resourceId)
+ }
+
+ private fun getPermissionControllerContext(): Context {
+ val permissionControllerPkg = context.packageManager.permissionControllerPackageName
+ try {
+ return context.createPackageContext(permissionControllerPkg, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ throw RuntimeException(e)
+ }
+ }
+
companion object {
private const val EXTRA_SETTINGS_FRAGMENT_ARGS_KEY = ":settings:fragment_args_key"
}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt b/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt
index eeb512037..236beb34e 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt
+++ b/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt
@@ -17,7 +17,6 @@
package android.safetycenter.functional.ui
import android.content.Context
-import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.os.Bundle
import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID
import android.safetycenter.SafetySourceData
@@ -26,21 +25,16 @@ import android.safetycenter.config.SafetySource
import android.safetycenter.config.SafetySourcesGroup
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import com.android.compatibility.common.util.DisableAnimationRule
import com.android.compatibility.common.util.FreezeRotationRule
-import com.android.compatibility.common.util.RetryRule
import com.android.compatibility.common.util.UiAutomatorUtils2
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.openPageAndExit
-import com.android.safetycenter.testing.SafetyCenterActivityLauncher.openPageAndExitAllowingRetries
import com.android.safetycenter.testing.SafetyCenterFlags
-import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MULTIPLE_SOURCES_GROUP_ID_1
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
@@ -51,10 +45,12 @@ import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_5
import com.android.safetycenter.testing.SafetyCenterTestData
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceIntentHandler.Request
import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
import com.android.safetycenter.testing.SafetySourceReceiver
import com.android.safetycenter.testing.SafetySourceTestData
+import com.android.safetycenter.testing.SupportsSafetyCenterRule
import com.android.safetycenter.testing.UiTestHelper.MORE_ISSUES_LABEL
import com.android.safetycenter.testing.UiTestHelper.clickConfirmDismissal
import com.android.safetycenter.testing.UiTestHelper.clickDismissIssueCard
@@ -75,64 +71,34 @@ import com.android.safetycenter.testing.UiTestHelper.waitPageTitleDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitPageTitleNotDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueDisplayed
import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueNotDisplayed
-import java.util.concurrent.TimeUnit
import org.junit.After
-import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.Timeout
import org.junit.runner.RunWith
/** Functional tests for generic subpages in Safety Center. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
class SafetyCenterSubpagesTest {
- @get:Rule val disableAnimationRule = DisableAnimationRule()
-
- @get:Rule val freezeRotationRule = FreezeRotationRule()
-
- // It is necessery to couple RetryRule and Timeout to ensure that all the retries together are
- // restricted with the test timeout
- @get:Rule val retryRule = RetryRule(/* retries= */ 3)
- @get:Rule
- val timeoutRule =
- Timeout(
- InstrumentationRegistry.getArguments().getString("timeout_msec", "60000").toLong(),
- TimeUnit.MILLISECONDS
- )
-
private val context: Context = getApplicationContext()
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
- private val safetyCenterResourcesContext = SafetyCenterResourcesContext.forTests(context)
+ private val safetyCenterResourcesApk = SafetyCenterResourcesApk.forTests(context)
- // JUnit's Assume is not supported in @BeforeClass by the tests runner, so this is used to
- // manually skip the setup and teardown methods.
- private val shouldRunTests = context.deviceSupportsSafetyCenter()
+ @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context)
+ @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+ @get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
+ @get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
@Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(shouldRunTests)
- }
-
- @Before
- fun enableSafetyCenterBeforeTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.setup()
+ fun enableSubpagesBeforeTest() {
SafetyCenterFlags.showSubpages = true
}
@After
- fun clearDataAfterTest() {
- if (!shouldRunTests) {
- return
- }
- safetyCenterTestHelper.reset()
+ fun resetRotationAfterTest() {
UiAutomatorUtils2.getUiDevice().resetRotation()
}
@@ -527,7 +493,7 @@ class SafetyCenterSubpagesTest {
)
context.launchSafetyCenterActivity(withReceiverPermission = true) {
- openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
waitSourceIssueDisplayed(issue)
waitButtonDisplayed(action.label) { it.click() }
@@ -547,7 +513,7 @@ class SafetyCenterSubpagesTest {
val issue = sourceData.issues[0]
context.launchSafetyCenterActivity {
- openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
waitSourceIssueDisplayed(issue)
clickDismissIssueCard()
@@ -568,7 +534,7 @@ class SafetyCenterSubpagesTest {
val issue = sourceData.issues[0]
context.launchSafetyCenterActivity {
- openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
waitSourceIssueDisplayed(issue)
clickDismissIssueCard()
waitAllTextDisplayed("Dismiss this alert?")
@@ -611,7 +577,7 @@ class SafetyCenterSubpagesTest {
val issue = sourceData.issues[0]
context.launchSafetyCenterActivity {
- openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
waitSourceIssueDisplayed(issue)
clickDismissIssueCard()
waitAllTextDisplayed("Dismiss this alert?")
@@ -635,7 +601,7 @@ class SafetyCenterSubpagesTest {
val issue = sourceData.issues[0]
context.launchSafetyCenterActivity {
- openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
waitSourceIssueDisplayed(issue)
clickDismissIssueCard()
waitAllTextDisplayed("Dismiss this alert?")
@@ -822,6 +788,24 @@ class SafetyCenterSubpagesTest {
}
@Test
+ fun dismissedIssuesCard_doesntShowGreenCards() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.informationWithIssueWithAttributionTitle
+ )
+ val safetyCenterIssueId = SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, issue.id)
+ safetyCenterTestHelper.dismissSafetyCenterIssue(safetyCenterIssueId)
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitAllTextNotDisplayed("Dismissed alerts")
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
fun moreIssuesCard_expandWithDismissedIssues_showsAdditionalCards() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesInSingleGroupConfig)
@@ -968,9 +952,7 @@ class SafetyCenterSubpagesTest {
waitAllTextDisplayed(
context.getString(source.titleResId),
context.getString(source.summaryResId),
- safetyCenterResourcesContext.getStringByName(
- "test_single_source_group_id_footer"
- )
+ safetyCenterResourcesApk.getStringByName("test_single_source_group_id_footer")
)
}
}
diff --git a/tests/hostside/safetycenter/Android.bp b/tests/hostside/safetycenter/Android.bp
index 499e44f62..c66cae23a 100644
--- a/tests/hostside/safetycenter/Android.bp
+++ b/tests/hostside/safetycenter/Android.bp
@@ -27,6 +27,7 @@ java_test_host {
libs: [
"tradefed",
"junit",
+ "compatibility-host-util",
],
static_libs: [
"cts-statsd-atom-host-test-utils",
diff --git a/tests/hostside/safetycenter/AndroidTest.xml b/tests/hostside/safetycenter/AndroidTest.xml
index 09ddf9d84..a28b70c3c 100644
--- a/tests/hostside/safetycenter/AndroidTest.xml
+++ b/tests/hostside/safetycenter/AndroidTest.xml
@@ -28,9 +28,12 @@
aren't polluted by `BOOT_COMPLETED` or similar broadcasts still being delivered, which
causes our `ActivityManager#waitForBroadcastIdle()` calls to timeout. -->
<option name="run-command" value="am wait-for-broadcast-idle" />
+ <option name="run-command" value="am wait-for-broadcast-barrier" />
<!-- 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" />
+ <!-- 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>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.StayAwakePreparer" />
diff --git a/tests/hostside/safetycenter/helper-app/Android.bp b/tests/hostside/safetycenter/helper-app/Android.bp
index cf4372d99..a05f8d2f3 100644
--- a/tests/hostside/safetycenter/helper-app/Android.bp
+++ b/tests/hostside/safetycenter/helper-app/Android.bp
@@ -30,6 +30,7 @@ android_test_helper_app {
static_libs: [
"androidx.test.rules",
"androidx.test.ext.junit",
+ "safety-center-pending-intents",
"safety-center-test-util-lib",
],
} \ No newline at end of file
diff --git a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt
index c72166c65..0f1356ca4 100644
--- a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt
+++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt
@@ -19,15 +19,23 @@ package android.safetycenter.hostside.device
import android.content.Context
import android.os.Bundle
import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity
+import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterQsActivity
import com.android.safetycenter.testing.SafetyCenterActivityLauncher.openPageAndExit
import com.android.safetycenter.testing.SafetyCenterFlags
import com.android.safetycenter.testing.SafetyCenterTestConfigs
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
import com.android.safetycenter.testing.SafetyCenterTestHelper
-import org.junit.After
+import com.android.safetycenter.testing.SafetyCenterTestRule
+import com.android.safetycenter.testing.SafetySourceTestData
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.INFORMATION_ISSUE_ID
+import com.android.safetycenter.testing.UiTestHelper.waitAllTextDisplayed
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -46,24 +54,49 @@ class SafetyCenterInteractionLoggingHelperTests {
private val context: Context = ApplicationProvider.getApplicationContext()
private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
+ private val safetySourceTestData = SafetySourceTestData(context)
+
+ @get:Rule val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
@Before
fun setUp() {
- safetyCenterTestHelper.setup()
SafetyCenterFlags.showSubpages = true
}
- @After
- fun tearDown() {
- safetyCenterTestHelper.reset()
- }
-
@Test
fun openSafetyCenter() {
context.launchSafetyCenterActivity {}
}
@Test
+ fun openSafetyCenterFullFromQs() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+
+ context.launchSafetyCenterQsActivity {
+ openPageAndExit("Settings") { waitAllTextDisplayed("OK") }
+ }
+ }
+
+ @Test
+ fun openSafetyCenterWithIssueIntent() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCE_ID, SINGLE_SOURCE_ID)
+ extras.putString(EXTRA_SAFETY_SOURCE_ISSUE_ID, INFORMATION_ISSUE_ID)
+
+ context.launchSafetyCenterActivity(extras) {}
+ }
+
+ @Test
+ fun openSafetyCenterQs() {
+ context.launchSafetyCenterQsActivity {}
+ }
+
+ @Test
fun openSubpageFromIntentExtra() {
val config = safetyCenterTestConfigs.singleSourceConfig
safetyCenterTestHelper.setConfig(config)
diff --git a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt
index f4677cfed..dc3cb3fc2 100644
--- a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt
+++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt
@@ -21,13 +21,18 @@ import android.safetycenter.SafetySourceData
import android.safetycenter.SafetySourceIssue
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.safetycenter.pendingintents.PendingIntentSender
+import com.android.safetycenter.testing.SafetyCenterActivityLauncher
import com.android.safetycenter.testing.SafetyCenterFlags
import com.android.safetycenter.testing.SafetyCenterTestConfigs
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceTestData
-import org.junit.After
+import com.android.safetycenter.testing.StatusBarNotificationWithChannel
+import com.android.safetycenter.testing.TestNotificationListener
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -48,23 +53,28 @@ class SafetyCenterNotificationLoggingHelperTests {
private val safetySourceTestData = SafetySourceTestData(context)
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
+ @get:Rule
+ val safetyCenterTestRule =
+ SafetyCenterTestRule(safetyCenterTestHelper, withNotifications = true)
+
@Before
fun setUp() {
- safetyCenterTestHelper.setup()
SafetyCenterFlags.notificationsEnabled = true
SafetyCenterFlags.notificationsAllowedSources = setOf(SINGLE_SOURCE_ID)
SafetyCenterFlags.allowStatsdLogging = true
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
}
- @After
- fun tearDown() {
- safetyCenterTestHelper.reset()
+ @Test
+ fun sendNotification() {
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, newTestDataWithNotifiableIssue())
}
@Test
- fun sendNotification() {
+ fun openSafetyCenterFromNotification() {
safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, newTestDataWithNotifiableIssue())
+
+ sendContentPendingIntent(TestNotificationListener.waitForSingleNotification())
}
private fun newTestDataWithNotifiableIssue(): SafetySourceData =
@@ -77,4 +87,17 @@ class SafetyCenterNotificationLoggingHelperTests {
.build()
)
.build()
+
+ companion object {
+ private fun sendContentPendingIntent(
+ statusBarNotificationWithChannel: StatusBarNotificationWithChannel
+ ) {
+ val contentIntent =
+ statusBarNotificationWithChannel.statusBarNotification.notification.contentIntent
+ SafetyCenterActivityLauncher.executeBlockAndExit(
+ launchActivity = { PendingIntentSender.send(contentIntent) },
+ block = {} // No action required
+ )
+ }
+ }
}
diff --git a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt
index d0e6dd430..4d945aad7 100644
--- a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt
+++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt
@@ -23,16 +23,27 @@ import android.safetycenter.SafetySourceErrorDetails
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil
-import com.android.safetycenter.testing.*
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.reportSafetySourceErrorWithPermission
+import com.android.safetycenter.testing.SafetyCenterFlags
+import com.android.safetycenter.testing.SafetyCenterTestConfigs
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_1
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_2
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_3
+import com.android.safetycenter.testing.SafetyCenterTestData
+import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestRule
import com.android.safetycenter.testing.SafetySourceIntentHandler.Request
import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
+import com.android.safetycenter.testing.SafetySourceReceiver
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.executeSafetyCenterIssueActionWithPermissionAndWait
import com.android.safetycenter.testing.SafetySourceReceiver.Companion.refreshSafetySourcesWithReceiverPermissionAndWait
-import org.junit.After
+import com.android.safetycenter.testing.SafetySourceTestData
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ACTION_ID
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ID
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,18 +55,14 @@ class SafetySourceStateCollectedLoggingHelperTests {
private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
+ @get:Rule val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
+
@Before
fun setUp() {
- safetyCenterTestHelper.setup()
SafetyCenterFlags.allowStatsdLogging = true
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
}
- @After
- fun tearDown() {
- safetyCenterTestHelper.reset()
- }
-
@Test
fun triggerStatsPull() {
val label = 1 // Arbitrary label in [0, 16)
@@ -124,13 +131,11 @@ class SafetySourceStateCollectedLoggingHelperTests {
@Test
fun refreshAllSources_reasonPageOpen_oneSuccessOneErrorOneTimeout() {
- SafetyCenterFlags.setAllRefreshTimeoutsTo(Coroutines.TIMEOUT_SHORT)
simulateRefresh(Response.SetData(safetySourceTestData.information), Response.Error, null)
}
@Test
fun refreshAllSources_reasonButtonClick_oneSuccessOneErrorOneTimeout() {
- SafetyCenterFlags.setAllRefreshTimeoutsTo(Coroutines.TIMEOUT_SHORT)
simulateRefresh(
Response.SetData(safetySourceTestData.information),
Response.Error,
@@ -139,6 +144,16 @@ class SafetySourceStateCollectedLoggingHelperTests {
)
}
+ @Test
+ fun resolvingAction_success() {
+ simulateResolvingActionWith(Response.SetData(safetySourceTestData.information))
+ }
+
+ @Test
+ fun resolvingAction_error() {
+ simulateResolvingActionWith(Response.Error)
+ }
+
private fun simulateRefresh(
source1Response: Response?,
source2Response: Response?,
@@ -155,8 +170,34 @@ class SafetySourceStateCollectedLoggingHelperTests {
SafetySourceReceiver.setResponse(Request.Refresh(SOURCE_ID_3), source3Response)
}
+ val atLeastOneTimeout =
+ source1Response == null || source2Response == null || source3Response == null
+ if (atLeastOneTimeout) {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ }
+
+ // Refresh sources and wait until the refresh has fully completed / timed out to ensure that
+ // things are logged.
val listener = safetyCenterTestHelper.addListener()
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(refreshReason)
listener.waitForSafetyCenterRefresh()
}
+
+ private fun simulateResolvingActionWith(response: Response) {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ SafetySourceReceiver.setResponse(Request.ResolveAction(SINGLE_SOURCE_ID), response)
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+ }
}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt
index 5ef8ed84a..91222d045 100644
--- a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt
@@ -20,31 +20,31 @@ import android.cts.statsdatom.lib.ConfigUtils
import android.cts.statsdatom.lib.ReportUtils
import android.safetycenter.hostside.rules.HelperAppRule
import android.safetycenter.hostside.rules.RequireSafetyCenterRule
+import com.android.compatibility.common.util.ApiLevelUtil
import com.android.os.AtomsProto.Atom
import com.android.os.AtomsProto.SafetyCenterInteractionReported
import com.android.os.AtomsProto.SafetyCenterInteractionReported.Action
+import com.android.os.AtomsProto.SafetyCenterInteractionReported.NavigationSource
import com.android.os.AtomsProto.SafetyCenterInteractionReported.ViewType
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
import com.google.common.truth.Truth.assertThat
+import java.math.BigInteger
+import java.security.MessageDigest
import org.junit.After
+import org.junit.Assume.assumeTrue
import org.junit.Before
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.RuleChain
import org.junit.runner.RunWith
/** Host-side tests for Safety Center statsd logging. */
@RunWith(DeviceJUnit4ClassRunner::class)
class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() {
- private val safetyCenterRule = RequireSafetyCenterRule(this)
- private val helperAppRule = HelperAppRule(this, HelperApp.APK_NAME, HelperApp.PACKAGE_NAME)
-
- @Rule
- @JvmField
- val rules: RuleChain = RuleChain.outerRule(safetyCenterRule).around(helperAppRule)
+ @get:Rule(order = 1) val safetyCenterRule = RequireSafetyCenterRule(this)
+ @get:Rule(order = 2)
+ val helperAppRule = HelperAppRule(this, HelperApp.APK_NAME, HelperApp.PACKAGE_NAME)
@Before
fun setUp() {
@@ -70,11 +70,74 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() {
val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
- assertThat(safetyCenterViewedAtoms).isNotEmpty()
+ assertThat(safetyCenterViewedAtoms).hasSize(1)
+ with(safetyCenterViewedAtoms.first()) {
+ assertThat(navigationSource).isEqualTo(NavigationSource.SOURCE_UNKNOWN)
+ assertThat(viewType).isEqualTo(ViewType.FULL)
+ }
+ }
+
+ @Test
+ fun openSafetyCenterQs_recordsSafetyCenterViewedEvent() {
+ helperAppRule.runTest(TEST_CLASS_NAME, "openSafetyCenterQs")
+
+ val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+
+ assertThat(safetyCenterViewedAtoms).hasSize(1)
+ with(safetyCenterViewedAtoms.first()) {
+ assertThat(navigationSource).isEqualTo(NavigationSource.QUICK_SETTINGS_TILE)
+ assertThat(viewType).isEqualTo(ViewType.QUICK_SETTINGS)
+ }
+ }
+
+ @Test
+ fun openSafetyCenterFullFromQs_recordsViewEventWithCorrectSource() {
+ helperAppRule.runTest(TEST_CLASS_NAME, "openSafetyCenterFullFromQs")
+
+ val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+
+ val viewTypesToNavSources =
+ safetyCenterViewedAtoms.associate { Pair(it.viewType, it.navigationSource) }
+ assertThat(viewTypesToNavSources)
+ .containsEntry(ViewType.FULL, NavigationSource.QUICK_SETTINGS_TILE)
+ }
+
+ @Test
+ fun openSafetyCenterWithIssueIntent_recordsViewEventWithAssociatedIssueMetadata() {
+ helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSafetyCenterWithIssueIntent")
+
+ val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+
+ assertThat(safetyCenterViewedAtoms).hasSize(1)
+ with(safetyCenterViewedAtoms.first()) {
+ assertThat(navigationSource).isEqualTo(NavigationSource.NOTIFICATION)
+ assertThat(encodedSafetySourceId).isEqualTo(ENCODED_SINGLE_SOURCE_ID)
+ assertThat(encodedIssueTypeId).isEqualTo(ENCODED_ISSUE_TYPE_ID)
+ }
+ }
+
+ @Test
+ fun openSafetyCenterWithNotification_recordsViewEventWithAssociatedIssueMetadata() {
+ assumeAtLeastUpsideDownCake("Safety Center notification APIs require Android U+")
+
+ helperAppRule.runTest(
+ testClassName = ".SafetyCenterNotificationLoggingHelperTests",
+ testMethodName = "openSafetyCenterFromNotification"
+ )
+
+ val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+
+ assertThat(safetyCenterViewedAtoms).hasSize(1)
+ with(safetyCenterViewedAtoms.first()) {
+ assertThat(navigationSource).isEqualTo(NavigationSource.NOTIFICATION)
+ assertThat(encodedSafetySourceId).isEqualTo(ENCODED_SINGLE_SOURCE_ID)
+ assertThat(encodedIssueTypeId).isEqualTo(ENCODED_ISSUE_TYPE_ID)
+ }
}
@Test
fun sendNotification_recordsNotificationPostedEvent() {
+ assumeAtLeastUpsideDownCake("Safety Center notification APIs require Android U+")
helperAppRule.runTest(
testClassName = ".SafetyCenterNotificationLoggingHelperTests",
testMethodName = "sendNotification"
@@ -89,6 +152,8 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() {
@Test
fun openSubpageFromIntentExtra_recordsEventWithUnknownNavigationSource() {
+ assumeAtLeastUpsideDownCake("Safety Center subpages require Android U+")
+
helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSubpageFromIntentExtra")
val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
@@ -96,32 +161,29 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() {
assertThat(safetyCenterViewedAtoms).hasSize(1)
with(safetyCenterViewedAtoms.first()) {
assertThat(viewType).isEqualTo(ViewType.SUBPAGE)
- assertThat(navigationSource)
- .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SOURCE_UNKNOWN)
+ assertThat(navigationSource).isEqualTo(NavigationSource.SOURCE_UNKNOWN)
assertThat(sessionId).isNotNull()
}
}
@Test
- @Ignore
- // TODO(b/278202773): Fix/de-flake this test
fun openSubpageFromHomepage_recordsEventWithSafetyCenterNavigationSource() {
+ assumeAtLeastUpsideDownCake("Safety Center subpages require Android U+")
+
helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSubpageFromHomepage")
val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+ val subpageViewedEvent = safetyCenterViewedAtoms.find { it.viewType == ViewType.SUBPAGE }
- assertThat(safetyCenterViewedAtoms.map { it.viewType })
- .containsExactly(ViewType.FULL, ViewType.SUBPAGE, ViewType.FULL)
- .inOrder()
- assertThat(safetyCenterViewedAtoms[1].navigationSource)
- .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SAFETY_CENTER)
+ assertThat(subpageViewedEvent).isNotNull()
+ assertThat(subpageViewedEvent!!.navigationSource).isEqualTo(NavigationSource.SAFETY_CENTER)
assertThat(safetyCenterViewedAtoms.map { it.sessionId }.distinct()).hasSize(1)
}
@Test
- @Ignore
- // TODO(b/278202773): Fix/de-flake this test
fun openSubpageFromSettingsSearch_recordsEventWithSettingsNavigationSource() {
+ assumeAtLeastUpsideDownCake("Safety Center subpages require Android U+")
+
helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSubpageFromSettingsSearch")
val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
@@ -129,8 +191,7 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() {
assertThat(safetyCenterViewedAtoms).hasSize(1)
with(safetyCenterViewedAtoms.first()) {
assertThat(viewType).isEqualTo(ViewType.SUBPAGE)
- assertThat(navigationSource)
- .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SETTINGS)
+ assertThat(navigationSource).isEqualTo(NavigationSource.SETTINGS)
assertThat(sessionId).isNotNull()
}
}
@@ -142,7 +203,33 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() {
.mapNotNull { it.atom.safetyCenterInteractionReported }
.filter { it.action == action }
+ private fun assumeAtLeastUpsideDownCake(message: String) {
+ assumeTrue(message, ApiLevelUtil.isAtLeast(device, 34))
+ }
+
private companion object {
const val TEST_CLASS_NAME = ".SafetyCenterInteractionLoggingHelperTests"
+
+ // LINT.IfChange(single_source_id)
+ val ENCODED_SINGLE_SOURCE_ID = encodeId("test_single_source_id")
+ // LINT.ThenChange(/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt:issue_type_id)
+
+ // LINT.IfChange(issue_type_id)
+ val ENCODED_ISSUE_TYPE_ID = encodeId("issue_type_id")
+ // LINT.ThenChange(/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt:issue_type_id)
+
+ /**
+ * Encodes a string into an long ID. The ID is a SHA-256 of the string, truncated to 64
+ * bits.
+ */
+ fun encodeId(id: String?): Long {
+ if (id == null) return 0
+
+ val digest = MessageDigest.getInstance("MD5")
+ digest.update(id.toByteArray())
+
+ // Truncate to the size of a long
+ return BigInteger(digest.digest()).toLong()
+ }
}
}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt
index 65e47fa91..2589c7a47 100644
--- a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt
@@ -31,18 +31,14 @@ import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.RuleChain
import org.junit.runner.RunWith
@RunWith(DeviceJUnit4ClassRunner::class)
class SafetyCenterSystemEventReportedLoggingHostTest : BaseHostJUnit4Test() {
- private val safetyCenterRule = RequireSafetyCenterRule(this)
- private val helperAppRule = HelperAppRule(this, HelperApp.APK_NAME, HelperApp.PACKAGE_NAME)
-
- @Rule
- @JvmField
- val rules: RuleChain = RuleChain.outerRule(safetyCenterRule).around(helperAppRule)
+ @get:Rule(order = 1) val safetyCenterRule = RequireSafetyCenterRule(this)
+ @get:Rule(order = 2)
+ val helperAppRule = HelperAppRule(this, HelperApp.APK_NAME, HelperApp.PACKAGE_NAME)
@Before
fun setUp() {
@@ -143,6 +139,7 @@ class SafetyCenterSystemEventReportedLoggingHostTest : BaseHostJUnit4Test() {
.that(systemEventAtoms.count { it.refreshReason == REFRESH_REASON_BUTTON_CLICK })
}
+ @Test
fun refreshAllSources_firstTime_allSourcesSuccessful_dataChangedTrueForAll() {
helperAppRule.runTest(
".SafetySourceStateCollectedLoggingHelperTests",
@@ -183,18 +180,50 @@ class SafetyCenterSystemEventReportedLoggingHostTest : BaseHostJUnit4Test() {
@Test
fun refreshAllSources_secondTime_someSourcesChanged_dataChangedCorrect() {
helperAppRule.runTest(
- ".SafetySourceStateCollectedLoggingHelperTests",
- "refreshAllSources_twiceDifferentData_onlySource1Unchanged"
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "refreshAllSources_twiceDifferentData_onlySource1Unchanged"
)
val systemEventAtoms =
- ReportUtils.getEventMetricDataList(device).mapNotNull {
- it.atom.safetyCenterSystemEventReported
- }
+ ReportUtils.getEventMetricDataList(device).mapNotNull {
+ it.atom.safetyCenterSystemEventReported
+ }
assertWithMessage("the number of atoms with dataChanged=false")
- .that(systemEventAtoms.count { !it.dataChanged })
- .isEqualTo(1) // Only source 1
+ .that(systemEventAtoms.count { !it.dataChanged })
+ .isEqualTo(1) // Only source 1
+ }
+
+ @Test
+ fun resolveAction_success_resolvingActionSuccessEvent() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "resolvingAction_success"
+ )
+
+ val resolvingActionEvent =
+ ReportUtils.getEventMetricDataList(device)
+ .mapNotNull { it.atom.safetyCenterSystemEventReported }
+ .single { it.eventType == EventType.INLINE_ACTION }
+
+ assertThat(resolvingActionEvent.result).isEqualTo(Result.SUCCESS)
+ assertThat(resolvingActionEvent.encodedIssueTypeId).isNotEqualTo(0)
+ }
+
+ @Test
+ fun resolveAction_error_resolvingActionErrorEvent() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "resolvingAction_error"
+ )
+
+ val resolvingActionEvent =
+ ReportUtils.getEventMetricDataList(device)
+ .mapNotNull { it.atom.safetyCenterSystemEventReported }
+ .single { it.eventType == EventType.INLINE_ACTION }
+
+ assertThat(resolvingActionEvent.result).isEqualTo(Result.ERROR)
+ assertThat(resolvingActionEvent.encodedIssueTypeId).isNotEqualTo(0)
}
companion object {
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt
index 22a380e12..a86041b5b 100644
--- a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt
@@ -29,19 +29,15 @@ import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.RuleChain
import org.junit.runner.RunWith
/** Host-side tests for Safety Center statsd logging. */
@RunWith(DeviceJUnit4ClassRunner::class)
class SafetySourceStateCollectedLoggingHostTest : BaseHostJUnit4Test() {
- private val safetyCenterRule = RequireSafetyCenterRule(this)
- private val helperAppRule = HelperAppRule(this, HelperApp.APK_NAME, HelperApp.PACKAGE_NAME)
-
- @Rule
- @JvmField
- val rules: RuleChain = RuleChain.outerRule(safetyCenterRule).around(helperAppRule)
+ @get:Rule(order = 1) val safetyCenterRule = RequireSafetyCenterRule(this)
+ @get:Rule(order = 2)
+ val helperAppRule = HelperAppRule(this, HelperApp.APK_NAME, HelperApp.PACKAGE_NAME)
@Before
fun setUp() {
@@ -66,8 +62,10 @@ class SafetySourceStateCollectedLoggingHostTest : BaseHostJUnit4Test() {
val sourceStateAtoms = getSafetySourceStateCollectedAtoms()
+ // This assertion purposefully uses containsAtLeast and not containsExact because on test
+ // devices with multiple primary users there will be multiple atoms per source.
assertThat(sourceStateAtoms.map { it.encodedSafetySourceId })
- .containsExactly(
+ .containsAtLeast(
SOURCE_1_ENCODED_SOURCE_ID,
SOURCE_2_ENCODED_SOURCE_ID,
SOURCE_3_ENCODED_SOURCE_ID
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt
index 809fe5f0f..fe75a05a2 100644
--- a/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt
@@ -24,14 +24,23 @@ import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
+/** toBooleanString() doesn't seem available on all Kotlin versions we need to support. */
+private fun String.toBooleanStrictInt(): Boolean =
+ when (this) {
+ "true" -> true
+ "false" -> false
+ else ->
+ throw IllegalArgumentException("The string doesn't represent a boolean value: $this")
+ }
+
/** JUnit rule for host side tests that requires Safety Center to be supported and enabled. */
class RequireSafetyCenterRule(private val hostTestClass: BaseHostJUnit4Test) : TestRule {
private val safetyCenterSupported: Boolean by lazy {
- executeShellCommandOrThrow("cmd safety_center supported").toBoolean()
+ shellCommandStdoutOrThrow("cmd safety_center supported").toBooleanStrictInt()
}
private val safetyCenterEnabled: Boolean by lazy {
- executeShellCommandOrThrow("cmd safety_center enabled").toBoolean()
+ shellCommandStdoutOrThrow("cmd safety_center enabled").toBooleanStrictInt()
}
override fun apply(base: Statement, description: Description): Statement {
@@ -45,13 +54,20 @@ class RequireSafetyCenterRule(private val hostTestClass: BaseHostJUnit4Test) : T
}
/** Returns the package name of Safety Center on the test device. */
- fun getSafetyCenterPackageName(): String =
- executeShellCommandOrThrow("cmd safety_center package-name")
+ fun getSafetyCenterPackageName(): String {
+ return shellCommandStdoutOrThrow("cmd safety_center package-name")
+ }
- private fun executeShellCommandOrThrow(command: String): String {
+ private fun shellCommandStdoutOrThrow(command: String): String {
val result = hostTestClass.device.executeShellV2Command(command)
if (result.status != CommandStatus.SUCCESS) {
- throw IOException("$command exited with status ${result.exitCode}")
+ throw IOException(
+ """Host-side test failed to execute adb shell command on test device.
+ |Command '$command' exited with status code ${result.exitCode}.
+ |This probably means the test device does not have a compatible version of
+ |the Permission Mainline module. Please check the test configuration."""
+ .trimMargin("|")
+ )
}
return result.stdout.trim()
}
diff --git a/tests/utils/safetycenter/AndroidManifest.xml b/tests/utils/safetycenter/AndroidManifest.xml
index 9d7c52e62..ce3724318 100644
--- a/tests/utils/safetycenter/AndroidManifest.xml
+++ b/tests/utils/safetycenter/AndroidManifest.xml
@@ -40,11 +40,25 @@
<activity android:name=".TestActivity"
android:exported="false">
- <intent-filter>
+ <intent-filter android:priority="-1">
+ <action android:name="com.android.safetycenter.testing.action.TEST_ACTIVITY"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
+ <!-- Create an alias at higher priority, disabled. We have seen flakes where implicit
+ intents for TEST_ACTIVITY fail owing to multiple receivers, perhaps due to an older
+ CTS APK hanging around. We turn this component on (and off in tidyup) in tests, in
+ the hope of only resolving to the actively running test in these cases. -->
+ <activity-alias android:name=".TestActivityPriority"
+ android:targetActivity=".TestActivity"
+ android:enabled="false"
+ android:exported="false">
+ <intent-filter android:priority="0">
<action android:name="com.android.safetycenter.testing.action.TEST_ACTIVITY"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
- </activity>
+ </activity-alias>
<activity-alias android:name=".TestActivityExported"
android:targetActivity=".TestActivity"
@@ -54,5 +68,14 @@
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity-alias>
+
+ <service android:name=".TestNotificationListener"
+ android:label="TestNotificationListener"
+ android:exported="false"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService" />
+ </intent-filter>
+ </service>
</application>
</manifest>
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt
index 29d1c1f09..a7009b19e 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt
@@ -29,6 +29,7 @@ import kotlinx.coroutines.withTimeoutOrNull
/** A class that facilitates interacting with coroutines. */
object Coroutines {
+
/**
* The timeout of a test case, typically varies depending on whether the test is running
* locally, on pre-submit or post-submit.
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/EnableSensorRule.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/EnableSensorRule.kt
new file mode 100644
index 000000000..1ed0ecbc3
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/EnableSensorRule.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.testing
+
+import android.Manifest.permission.MANAGE_SENSOR_PRIVACY
+import android.Manifest.permission.OBSERVE_SENSOR_PRIVACY
+import android.content.Context
+import android.hardware.SensorPrivacyManager
+import android.hardware.SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import org.junit.Assume.assumeTrue
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * A JUnit [TestRule] to ensure a given [sensor] is enabled.
+ *
+ * This rule disables sensor privacy before a test and restores the prior state afterwards.
+ */
+class EnableSensorRule(context: Context, val sensor: Int) : TestRule {
+
+ private val sensorPrivacyManager: SensorPrivacyManager =
+ context.getSystemService(SensorPrivacyManager::class.java)!!
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ assumeTrue(
+ "Test device does not support toggling sensor $sensor",
+ supportsSensorToggle()
+ )
+ val oldSensorPrivacy = isSensorPrivacyEnabled()
+ setSensorPrivacy(false)
+ try {
+ base.evaluate()
+ } finally {
+ setSensorPrivacy(oldSensorPrivacy)
+ }
+ }
+ }
+ }
+
+ private fun supportsSensorToggle(): Boolean =
+ sensorPrivacyManager.supportsSensorToggle(sensor) &&
+ sensorPrivacyManager.supportsSensorToggle(TOGGLE_TYPE_SOFTWARE, sensor)
+
+ private fun isSensorPrivacyEnabled(): Boolean =
+ callWithShellPermissionIdentity(OBSERVE_SENSOR_PRIVACY) {
+ sensorPrivacyManager.isSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, sensor)
+ }
+
+ private fun setSensorPrivacy(enabled: Boolean) {
+ callWithShellPermissionIdentity(MANAGE_SENSOR_PRIVACY, OBSERVE_SENSOR_PRIVACY) {
+ sensorPrivacyManager.setSensorPrivacy(sensor, enabled)
+ }
+ }
+}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/NotificationCharacteristics.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/NotificationCharacteristics.kt
index b91c72422..177c2359c 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/NotificationCharacteristics.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/NotificationCharacteristics.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.safetycenter.functional.testing
+package com.android.safetycenter.testing
import android.app.Notification
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt
index 537eb7ead..40515fa33 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt
@@ -28,7 +28,6 @@ import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Bundle
import androidx.annotation.RequiresApi
import androidx.test.uiautomator.By
-import com.android.compatibility.common.util.RetryableException
import com.android.compatibility.common.util.UiAutomatorUtils2.getUiDevice
import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
@@ -46,13 +45,14 @@ object SafetyCenterActivityLauncher {
*/
fun Context.launchSafetyCenterActivity(
intentExtras: Bundle? = null,
+ intentAction: String = ACTION_SAFETY_CENTER,
withReceiverPermission: Boolean = false,
preventTrampolineToSettings: Boolean = true,
block: () -> Unit
) {
val launchSafetyCenterIntent =
createIntent(
- ACTION_SAFETY_CENTER,
+ intentAction,
intentExtras,
preventTrampolineToSettings = preventTrampolineToSettings
)
@@ -80,19 +80,6 @@ object SafetyCenterActivityLauncher {
executeBlockAndExit(block) { waitDisplayed(By.text(entryPoint)) { it.click() } }
}
- /**
- * Launches a page in Safety Center and exits it once [block] completes, throwing a
- * [RetryableException] for any [RuntimeException] thrown by [block] to allow [RetryRule] to
- * retry the test invocation.
- */
- fun openPageAndExitAllowingRetries(entryPoint: String, block: () -> Unit) {
- try {
- openPageAndExit(entryPoint, block)
- } catch (e: Throwable) {
- throw RetryableException(e, "Exception occurred when checking a Safety Center page")
- }
- }
-
private fun createIntent(
intentAction: String,
intentExtras: Bundle?,
@@ -107,6 +94,7 @@ object SafetyCenterActivityLauncher {
return launchIntent
}
+ /** Executes the given [block] and presses the back button to exit. */
fun executeBlockAndExit(block: () -> Unit, launchActivity: () -> Unit) {
val uiDevice = getUiDevice()
uiDevice.waitForIdle()
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt
index b948dc52c..f8926caac 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt
@@ -24,8 +24,8 @@ import android.content.IntentFilter
import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED
import androidx.annotation.RequiresApi
-import com.android.compatibility.common.util.SystemUtil
import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout
import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
import java.time.Duration
@@ -55,20 +55,18 @@ class SafetyCenterEnabledChangedReceiver(private val context: Context) : Broadca
fun setSafetyCenterEnabledWithReceiverPermissionAndWait(
value: Boolean,
timeout: Duration = TIMEOUT_LONG
- ) =
+ ): Boolean =
callWithShellPermissionIdentity(READ_SAFETY_CENTER_STATUS) {
- setSafetyCenterEnabledWithoutReceiverPermissionAndWait(value, timeout)
+ SafetyCenterFlags.isEnabled = value
+ receiveSafetyCenterEnabledChanged(timeout)
}
fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait(
value: Boolean,
- timeout: Duration = TIMEOUT_LONG
- ): Boolean {
+ ) {
SafetyCenterFlags.isEnabled = value
- if (timeout < TIMEOUT_LONG) {
- SystemUtil.waitForBroadcasts()
- }
- return receiveSafetyCenterEnabledChanged(timeout)
+ WaitForBroadcasts.waitForBroadcasts()
+ receiveSafetyCenterEnabledChanged(TIMEOUT_SHORT)
}
fun unregister() {
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt
index f7b5f486d..912ea44ad 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt
@@ -20,9 +20,7 @@ import android.Manifest.permission.READ_DEVICE_CONFIG
import android.Manifest.permission.WRITE_DEVICE_CONFIG
import android.annotation.TargetApi
import android.app.job.JobInfo
-import android.content.Context
import android.content.pm.PackageManager
-import android.content.res.Resources
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_PRIVACY
@@ -35,6 +33,7 @@ import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PERIODIC
import android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
import android.safetycenter.SafetyCenterManager.REFRESH_REASON_SAFETY_CENTER_ENABLED
import android.safetycenter.SafetySourceData
+import com.android.modules.utils.build.SdkLevel
import com.android.safetycenter.testing.Coroutines.TEST_TIMEOUT
import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
@@ -46,7 +45,7 @@ object SafetyCenterFlags {
/** Flag that determines whether Safety Center is enabled. */
private val isEnabledFlag =
- Flag("safety_center_is_enabled", defaultValue = false, BooleanParser())
+ Flag("safety_center_is_enabled", defaultValue = SdkLevel.isAtLeastU(), BooleanParser())
/** Flag that determines whether Safety Center can send notifications. */
private val notificationsFlag =
@@ -102,13 +101,6 @@ object SafetyCenterFlags {
DurationParser()
)
- /**
- * Flag that determines whether we should show error entries for sources that timeout when
- * refreshing them.
- */
- private val showErrorEntriesOnTimeoutFlag =
- Flag("safety_center_show_error_entries_on_timeout", defaultValue = true, BooleanParser())
-
/** Flag that determines whether we should replace the IconAction of the lock screen source. */
private val replaceLockScreenIconActionFlag =
Flag("safety_center_replace_lock_screen_icon_action", defaultValue = true, BooleanParser())
@@ -211,6 +203,18 @@ object SafetyCenterFlags {
)
/**
+ * Flag containing a map (a comma separated list of colon separated pairs) where the key is a
+ * Safety Source ID and the value is a vertical-bar-delimited list of Action IDs that should
+ * have their PendingIntent replaced with the source's default PendingIntent.
+ */
+ private val actionsToOverrideWithDefaultIntentFlag =
+ Flag(
+ "safety_center_actions_to_override_with_default_intent",
+ defaultValue = emptyMap(),
+ MapParser(StringParser(), SetParser(StringParser(), delimiter = "|"))
+ )
+
+ /**
* Flag that represents a comma delimited list of IDs of sources that should only be refreshed
* when Safety Center is on screen. We will refresh these sources only on page open and when the
* scan button is clicked.
@@ -293,13 +297,6 @@ object SafetyCenterFlags {
MapParser(StringParser(), SetParser(StringParser(), delimiter = "|"))
)
- /**
- * Flag that determines whether background refreshes require charging in
- * [SafetyCenterBackgroundRefreshJobService]. See [JobInfo.setRequiresCharging] for details.
- */
- private val backgroundRefreshRequiresChargingFlag =
- Flag("safety_center_background_requires_charging", defaultValue = false, BooleanParser())
-
/** Every Safety Center flag. */
private val FLAGS: List<Flag<*>> =
listOf(
@@ -309,7 +306,6 @@ object SafetyCenterFlags {
notificationsMinDelayFlag,
immediateNotificationBehaviorIssuesFlag,
notificationResurfaceIntervalFlag,
- showErrorEntriesOnTimeoutFlag,
replaceLockScreenIconActionFlag,
refreshSourceTimeoutsFlag,
resolveActionTimeoutFlag,
@@ -319,6 +315,7 @@ object SafetyCenterFlags {
resurfaceIssueMaxCountsFlag,
resurfaceIssueDelaysFlag,
issueCategoryAllowlistsFlag,
+ actionsToOverrideWithDefaultIntentFlag,
allowedAdditionalPackageCertsFlag,
backgroundRefreshDeniedSourcesFlag,
allowStatsdLoggingFlag,
@@ -326,14 +323,7 @@ object SafetyCenterFlags {
showSubpagesFlag,
overrideRefreshOnPageOpenSourcesFlag,
backgroundRefreshIsEnabledFlag,
- periodicBackgroundRefreshIntervalFlag,
- backgroundRefreshRequiresChargingFlag
- )
-
- /** Returns whether the device supports Safety Center. */
- fun Context.deviceSupportsSafetyCenter() =
- resources.getBoolean(
- Resources.getSystem().getIdentifier("config_enableSafetyCenter", "bool", "android")
+ periodicBackgroundRefreshIntervalFlag
)
/** A property that allows getting and setting the [isEnabledFlag]. */
@@ -354,9 +344,6 @@ object SafetyCenterFlags {
/** A property that allows getting and setting the [notificationResurfaceIntervalFlag]. */
var notificationResurfaceInterval: Duration by notificationResurfaceIntervalFlag
- /** A property that allows getting and setting the [showErrorEntriesOnTimeoutFlag]. */
- var showErrorEntriesOnTimeout: Boolean by showErrorEntriesOnTimeoutFlag
-
/** A property that allows getting and setting the [replaceLockScreenIconActionFlag]. */
var replaceLockScreenIconAction: Boolean by replaceLockScreenIconActionFlag
@@ -384,6 +371,10 @@ object SafetyCenterFlags {
/** A property that allows getting and setting the [issueCategoryAllowlistsFlag]. */
var issueCategoryAllowlists: Map<Int, Set<String>> by issueCategoryAllowlistsFlag
+ /** A property that allows getting and setting the [actionsToOverrideWithDefaultIntentFlag]. */
+ var actionsToOverrideWithDefaultIntent: Map<String, Set<String>> by
+ actionsToOverrideWithDefaultIntentFlag
+
var allowedAdditionalPackageCerts: Map<String, Set<String>> by allowedAdditionalPackageCertsFlag
/** A property that allows getting and setting the [backgroundRefreshDeniedSourcesFlag]. */
@@ -398,15 +389,6 @@ object SafetyCenterFlags {
/** A property that allows getting and setting the [overrideRefreshOnPageOpenSourcesFlag]. */
var overrideRefreshOnPageOpenSources: Set<String> by overrideRefreshOnPageOpenSourcesFlag
- /** A property that allows getting and settings the [backgroundRefreshIsEnabledFlag]. */
- var backgroundRefreshIsEnabled: Boolean by backgroundRefreshIsEnabledFlag
-
- /** A property that allows getting and settings the [periodicBackgroundRefreshIntervalFlag]. */
- var periodicBackgroundRefreshInterval: Duration by periodicBackgroundRefreshIntervalFlag
-
- /** A property that allows getting and settings the [backgroundRefreshRequiresChargingFlag]. */
- var backgroundRefreshRequiresCharging: Boolean by backgroundRefreshRequiresChargingFlag
-
/**
* Returns a snapshot of all the Safety Center flags.
*
@@ -460,7 +442,7 @@ object SafetyCenterFlags {
/** Returns the [isEnabledFlag] value of the Safety Center flags snapshot. */
fun Properties.isSafetyCenterEnabled() =
- getBoolean(isEnabledFlag.name, /* defaultValue */ false)
+ getBoolean(isEnabledFlag.name, isEnabledFlag.defaultValue)
@TargetApi(UPSIDE_DOWN_CAKE)
private fun getAllRefreshTimeoutsMap(refreshTimeout: Duration): Map<Int, Duration> =
@@ -533,11 +515,7 @@ object SafetyCenterFlags {
.joinToString(entriesDelimiter)
}
- private class Flag<T>(
- val name: String,
- private val defaultValue: T,
- private val parser: Parser<T>
- ) {
+ private class Flag<T>(val name: String, val defaultValue: T, private val parser: Parser<T>) {
val defaultStringValue = parser.toString(defaultValue)
operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt
index de4cf7094..fd3749094 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt
@@ -49,7 +49,7 @@ class SafetyCenterTestConfigs(private val context: Context) {
context.packageName,
PackageInfoFlags.of(GET_SIGNING_CERTIFICATES.toLong())
)
- .signingInfo
+ .signingInfo!!
.apkContentsSigners[0]
.toByteArray()
)
@@ -64,7 +64,9 @@ class SafetyCenterTestConfigs(private val context: Context) {
*/
val singleSourceInvalidIntentConfig =
singleSourceConfig(
- dynamicSafetySourceBuilder(SINGLE_SOURCE_ID).setIntentAction("stub").build()
+ dynamicSafetySourceBuilder(SINGLE_SOURCE_ID)
+ .setIntentAction(INTENT_ACTION_NOT_RESOLVING)
+ .build()
)
/**
@@ -157,6 +159,14 @@ class SafetyCenterTestConfigs(private val context: Context) {
/** A [SafetyCenterConfig] with a dynamic source in a different, missing package. */
val singleSourceOtherPackageConfig = singleSourceConfig(dynamicOtherPackageSafetySource)
+ /** A [SafetyCenterConfig] with a dynamic hidden-by-default source. */
+ val hiddenSourceConfig =
+ singleSourceConfig(
+ dynamicSafetySourceBuilder(DYNAMIC_HIDDEN_ID)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .build()
+ )
+
/** A simple [SafetyCenterConfig] with a source supporting all profiles. */
val singleSourceAllProfileConfig =
singleSourceConfig(
@@ -348,7 +358,9 @@ class SafetyCenterTestConfigs(private val context: Context) {
.addSafetySourcesGroup(
safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_1)
.addSafetySource(
- dynamicSafetySourceBuilder(SOURCE_ID_1).setIntentAction("stub").build()
+ dynamicSafetySourceBuilder(SOURCE_ID_1)
+ .setIntentAction(INTENT_ACTION_NOT_RESOLVING)
+ .build()
)
.addSafetySource(dynamicSafetySource(SOURCE_ID_2))
.build()
@@ -373,9 +385,7 @@ class SafetyCenterTestConfigs(private val context: Context) {
* Source group provided by [staticSourcesConfig] containing a single source [staticSource1].
*/
val staticSourceGroup1 =
- SafetySourcesGroup.Builder()
- .setId("test_static_sources_group_id_1")
- .setTitleResId(android.R.string.paste)
+ staticSafetySourcesGroupBuilder("test_static_sources_group_id_1")
.addSafetySource(staticSource1)
.build()
@@ -383,8 +393,7 @@ class SafetyCenterTestConfigs(private val context: Context) {
* Source group provided by [staticSourcesConfig] containing a single source [staticSource2].
*/
val staticSourceGroup2 =
- SafetySourcesGroup.Builder()
- .setId("test_static_sources_group_id_2")
+ staticSafetySourcesGroupBuilder("test_static_sources_group_id_2")
.setTitleResId(android.R.string.copy)
.addSafetySource(staticSource2)
.build()
@@ -402,7 +411,44 @@ class SafetyCenterTestConfigs(private val context: Context) {
* The particular source ID is configured in the same way as sources hosted by the Settings app,
* to launch as if it is part of the Settings app UI.
*/
- val singleStaticSettingsSource = singleSourceConfig(staticSafetySource("TestSource"))
+ val singleStaticSettingsSourceConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ staticSafetySourcesGroupBuilder("single_static_source_group")
+ .addSafetySource(staticSafetySource("TestSource"))
+ .build()
+ )
+ .build()
+
+ /** A [SafetyCenterConfig] with a single static source and an intent that doesn't resolve */
+ val singleStaticInvalidIntentConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ staticSafetySourcesGroupBuilder("single_static_source_group")
+ .addSafetySource(
+ staticSafetySourceBuilder(SINGLE_SOURCE_ID)
+ .setIntentAction(INTENT_ACTION_NOT_RESOLVING)
+ .build()
+ )
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetyCenterConfig] with a single static source and an implicit intent that isn't exported
+ */
+ val singleStaticImplicitIntentNotExportedConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ staticSafetySourcesGroupBuilder("single_static_source_group")
+ .addSafetySource(
+ staticSafetySourceBuilder(SINGLE_SOURCE_ID)
+ .setIntentAction(ACTION_TEST_ACTIVITY)
+ .build()
+ )
+ .build()
+ )
+ .build()
/** [SafetyCenterConfig] used in tests for Your Work Policy Info source. */
val workPolicyInfoConfig =
@@ -750,7 +796,7 @@ class SafetyCenterTestConfigs(private val context: Context) {
.setId(id)
.setTitleResId(android.R.string.ok)
.setSummaryResId(android.R.string.ok)
- .setIntentAction(ACTION_TEST_ACTIVITY)
+ .setIntentAction(ACTION_TEST_ACTIVITY_EXPORTED)
.setProfile(SafetySource.PROFILE_PRIMARY)
private fun staticAllProfileSafetySourceBuilder(id: String) =
@@ -780,6 +826,9 @@ class SafetyCenterTestConfigs(private val context: Context) {
.setTitleResId(android.R.string.ok)
.setSummaryResId(android.R.string.ok)
+ private fun staticSafetySourcesGroupBuilder(id: String) =
+ SafetySourcesGroup.Builder().setId(id).setTitleResId(android.R.string.paste)
+
fun singleSourceConfig(safetySource: SafetySource) =
SafetyCenterConfig.Builder()
.addSafetySourcesGroup(
@@ -807,7 +856,9 @@ class SafetyCenterTestConfigs(private val context: Context) {
* ID of the only source provided in [singleSourceConfig], [severityZeroConfig] and
* [noPageOpenConfig].
*/
+ // LINT.IfChange(single_source_id)
const val SINGLE_SOURCE_ID = "test_single_source_id"
+ // LINT.ThenChange(/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt:single_source_id)
/** ID of the only source provided in [singleSourceAllProfileConfig]. */
const val SINGLE_SOURCE_ALL_PROFILE_ID = "test_single_source_all_profile_id"
@@ -1033,5 +1084,7 @@ class SafetyCenterTestConfigs(private val context: Context) {
* [privacySubpageWithoutDataSourcesConfig], to replicate the privacy sources group.
*/
const val ANDROID_PRIVACY_SOURCES_GROUP_ID = "AndroidPrivacySources"
+
+ private const val INTENT_ACTION_NOT_RESOLVING = "there.is.no.way.this.resolves"
}
}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt
index 5ff42e23c..289bc32a8 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt
@@ -48,7 +48,7 @@ import com.android.safetycenter.internaldata.SafetyCenterIds
import com.android.safetycenter.internaldata.SafetyCenterIssueActionId
import com.android.safetycenter.internaldata.SafetyCenterIssueId
import com.android.safetycenter.internaldata.SafetyCenterIssueKey
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.resources.SafetyCenterResourcesApk
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_GROUP_ID
import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ACTION_ID
import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ID
@@ -66,23 +66,24 @@ import java.util.Locale
@RequiresApi(TIRAMISU)
class SafetyCenterTestData(context: Context) {
- private val safetyCenterResourcesContext = SafetyCenterResourcesContext.forTests(context)
+ private val safetyCenterResourcesApk = SafetyCenterResourcesApk.forTests(context)
private val safetySourceTestData = SafetySourceTestData(context)
/**
* The [SafetyCenterStatus] used when the overall status is unknown and no scan is in progress.
*/
- val safetyCenterStatusUnknown =
- SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_ok_review_title"
- ),
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_ok_review_summary"
+ val safetyCenterStatusUnknown: SafetyCenterStatus
+ get() =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_ok_review_title"
+ ),
+ safetyCenterResourcesApk.getStringByName(
+ "overall_severity_level_ok_review_summary"
+ )
)
- )
- .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
- .build()
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ .build()
/**
* Returns a [SafetyCenterStatus] with one alert and the given [statusResource] and
@@ -103,7 +104,7 @@ class SafetyCenterTestData(context: Context) {
numAlerts: Int,
): SafetyCenterStatus =
SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(statusResource),
+ safetyCenterResourcesApk.getStringByName(statusResource),
getAlertString(numAlerts)
)
.setSeverityLevel(overallSeverityLevel)
@@ -117,11 +118,8 @@ class SafetyCenterTestData(context: Context) {
numTipIssues: Int,
): SafetyCenterStatus =
SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
- safetyCenterResourcesContext.getStringByName(
- "overall_severity_level_tip_summary",
- numTipIssues
- )
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
+ getIcuPluralsString("overall_severity_level_tip_summary", numTipIssues)
)
.setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
.build()
@@ -134,8 +132,8 @@ class SafetyCenterTestData(context: Context) {
numAutomaticIssues: Int,
): SafetyCenterStatus =
SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
- safetyCenterResourcesContext.getStringByName(
+ safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"),
+ getIcuPluralsString(
"overall_severity_level_action_taken_summary",
numAutomaticIssues
)
@@ -149,7 +147,7 @@ class SafetyCenterTestData(context: Context) {
*/
fun safetyCenterStatusCritical(numAlerts: Int) =
SafetyCenterStatus.Builder(
- safetyCenterResourcesContext.getStringByName(
+ safetyCenterResourcesApk.getStringByName(
"overall_severity_level_critical_safety_warning_title"
),
getAlertString(numAlerts)
@@ -166,7 +164,8 @@ class SafetyCenterTestData(context: Context) {
sourceId: String,
userId: Int = UserHandle.myUserId(),
title: CharSequence = "OK",
- pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
+ pendingIntent: PendingIntent? =
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
) =
SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
@@ -183,7 +182,8 @@ class SafetyCenterTestData(context: Context) {
sourceId: String,
userId: Int = UserHandle.myUserId(),
title: CharSequence = "OK",
- pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
+ pendingIntent: PendingIntent? =
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
) = safetyCenterEntryDefaultBuilder(sourceId, userId, title, pendingIntent).build()
/**
@@ -199,7 +199,9 @@ class SafetyCenterTestData(context: Context) {
SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
.setSummary("OK")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setPendingIntent(
+ safetySourceTestData.createTestActivityRedirectPendingIntent(explicit = false)
+ )
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON)
/**
@@ -216,7 +218,8 @@ class SafetyCenterTestData(context: Context) {
*/
fun safetyCenterEntryUnspecified(
sourceId: String,
- pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
+ pendingIntent: PendingIntent? =
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
) =
SafetyCenterEntry.Builder(entryId(sourceId), "Unspecified title")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
@@ -239,7 +242,7 @@ class SafetyCenterTestData(context: Context) {
SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_OK)
.setSummary("Ok summary")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setPendingIntent(safetySourceTestData.createTestActivityRedirectPendingIntent())
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
/**
@@ -264,7 +267,7 @@ class SafetyCenterTestData(context: Context) {
SafetyCenterEntry.Builder(entryId(sourceId), "Recommendation title")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
.setSummary(summary)
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setPendingIntent(safetySourceTestData.createTestActivityRedirectPendingIntent())
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
.build()
@@ -276,7 +279,7 @@ class SafetyCenterTestData(context: Context) {
SafetyCenterEntry.Builder(entryId(sourceId), "Critical title")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
.setSummary("Critical summary")
- .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setPendingIntent(safetySourceTestData.createTestActivityRedirectPendingIntent())
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
.build()
@@ -307,7 +310,7 @@ class SafetyCenterTestData(context: Context) {
userId
),
"Review",
- safetySourceTestData.testActivityRedirectPendingIntent
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
)
.build()
)
@@ -347,7 +350,7 @@ class SafetyCenterTestData(context: Context) {
userId
),
"See issue",
- safetySourceTestData.testActivityRedirectPendingIntent
+ safetySourceTestData.createTestActivityRedirectPendingIntent()
)
.apply {
if (confirmationDialog && SdkLevel.isAtLeastU()) {
@@ -428,7 +431,7 @@ class SafetyCenterTestData(context: Context) {
private fun getIcuPluralsString(name: String, count: Int, vararg formatArgs: Any): String {
val messageFormat =
MessageFormat(
- safetyCenterResourcesContext.getStringByName(name, formatArgs),
+ safetyCenterResourcesApk.getStringByName(name, formatArgs),
Locale.getDefault()
)
val arguments = ArrayMap<String, Any>()
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt
index 82f7326fd..2902cdd6a 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt
@@ -27,6 +27,7 @@ import android.safetycenter.SafetyEvent
import android.safetycenter.SafetySourceData
import android.safetycenter.config.SafetyCenterConfig
import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_STATIC
+import android.util.Log
import androidx.annotation.RequiresApi
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.addOnSafetyCenterDataChangedListenerWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.clearAllSafetySourceDataForTestsWithPermission
@@ -44,7 +45,7 @@ import com.google.common.util.concurrent.MoreExecutors.directExecutor
/** A class that facilitates settings up Safety Center in tests. */
@RequiresApi(TIRAMISU)
-class SafetyCenterTestHelper(private val context: Context) {
+class SafetyCenterTestHelper(val context: Context) {
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
private val userManager = context.getSystemService(UserManager::class.java)!!
@@ -55,14 +56,17 @@ class SafetyCenterTestHelper(private val context: Context) {
* values. To be called before each test.
*/
fun setup() {
- SafetySourceReceiver.setup()
+ Log.d(TAG, "setup")
Coroutines.enableDebugging()
+ SafetySourceReceiver.setup()
+ TestActivity.enableHighPriorityAlias()
SafetyCenterFlags.setup()
setEnabled(true)
}
/** Resets the state of Safety Center. To be called after each test. */
fun reset() {
+ Log.d(TAG, "reset")
setEnabled(true)
listeners.forEach {
safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(it)
@@ -72,12 +76,14 @@ class SafetyCenterTestHelper(private val context: Context) {
safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
safetyCenterManager.clearSafetyCenterConfigForTestsWithPermission()
resetFlags()
+ TestActivity.disableHighPriorityAlias()
SafetySourceReceiver.reset()
Coroutines.resetDebugging()
}
/** Enables or disables SafetyCenter based on [value]. */
fun setEnabled(value: Boolean) {
+ Log.d(TAG, "setEnabled to $value")
val safetyCenterConfig = safetyCenterManager.getSafetyCenterConfigWithPermission()
if (safetyCenterConfig == null) {
// No broadcasts are dispatched when toggling the flag when SafetyCenter is not
@@ -87,8 +93,8 @@ class SafetyCenterTestHelper(private val context: Context) {
SafetyCenterFlags.isEnabled = value
return
}
- val currentValue = safetyCenterManager.isSafetyCenterEnabledWithPermission()
- if (currentValue == value) {
+ if (value == isEnabled()) {
+ Log.d(TAG, "isEnabled is already $value")
return
}
setEnabledWaitingForSafetyCenterBroadcastIdle(value, safetyCenterConfig)
@@ -96,6 +102,7 @@ class SafetyCenterTestHelper(private val context: Context) {
/** Sets the given [SafetyCenterConfig]. */
fun setConfig(config: SafetyCenterConfig) {
+ Log.d(TAG, "setConfig")
require(isEnabled())
safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(config)
}
@@ -107,6 +114,7 @@ class SafetyCenterTestHelper(private val context: Context) {
* initial SafetyCenter update
*/
fun addListener(skipInitialData: Boolean = true): SafetyCenterTestListener {
+ Log.d(TAG, "addListener")
require(isEnabled())
val listener = SafetyCenterTestListener()
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
@@ -126,6 +134,7 @@ class SafetyCenterTestHelper(private val context: Context) {
safetySourceData: SafetySourceData?,
safetyEvent: SafetyEvent = EVENT_SOURCE_STATE_CHANGED
) {
+ Log.d(TAG, "setData for $safetySourceId")
require(isEnabled())
safetyCenterManager.setSafetySourceDataWithPermission(
safetySourceId,
@@ -137,6 +146,8 @@ class SafetyCenterTestHelper(private val context: Context) {
/** Dismisses the [SafetyCenterIssue] for the given [safetyCenterIssueId]. */
@RequiresApi(UPSIDE_DOWN_CAKE)
fun dismissSafetyCenterIssue(safetyCenterIssueId: String) {
+ Log.d(TAG, "dismissSafetyCenterIssue")
+ require(isEnabled())
safetyCenterManager.dismissSafetyCenterIssueWithPermission(safetyCenterIssueId)
}
@@ -155,6 +166,7 @@ class SafetyCenterTestHelper(private val context: Context) {
// Wait for all ACTION_SAFETY_CENTER_ENABLED_CHANGED broadcasts to be dispatched to
// avoid them leaking onto other tests.
if (safetyCenterConfig.containsTestSource()) {
+ Log.d(TAG, "Waiting for test source enabled changed broadcast")
SafetySourceReceiver.receiveSafetyCenterEnabledChanged()
// The explicit ACTION_SAFETY_CENTER_ENABLED_CHANGED broadcast is also sent to the
// dynamically registered receivers.
@@ -166,6 +178,7 @@ class SafetyCenterTestHelper(private val context: Context) {
// 2: test finishes, 3: new test starts, 4: a test config is set, 5: broadcast from 1
// dispatched).
if (userManager.isSystemUser) {
+ Log.d(TAG, "Waiting for system enabled changed broadcast")
// The implicit broadcast is only sent to the system user.
enabledChangedReceiver.receiveSafetyCenterEnabledChanged()
}
@@ -188,4 +201,8 @@ class SafetyCenterTestHelper(private val context: Context) {
.any { it.packageName == context.packageName }
private fun isEnabled() = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+
+ private companion object {
+ const val TAG: String = "SafetyCenterTestHelper"
+ }
}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestRule.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestRule.kt
new file mode 100644
index 000000000..dcbc4ebe9
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestRule.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.testing
+
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/** A JUnit [TestRule] that performs setup and reset steps before and after Safety Center tests. */
+class SafetyCenterTestRule(
+ private val safetyCenterTestHelper: SafetyCenterTestHelper,
+ private val withNotifications: Boolean = false
+) : TestRule {
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ setup()
+ try {
+ base.evaluate()
+ } finally {
+ reset()
+ }
+ }
+ }
+ }
+
+ private fun setup() {
+ safetyCenterTestHelper.setup()
+ if (withNotifications) {
+ TestNotificationListener.setup(safetyCenterTestHelper.context)
+ }
+ }
+
+ private fun reset() {
+ safetyCenterTestHelper.reset()
+ if (withNotifications) {
+ // It is important to reset the notification listener last because it waits/ensures that
+ // all notifications have been removed before returning.
+ TestNotificationListener.reset(safetyCenterTestHelper.context)
+ }
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt
index 2bd662ee8..8386228b8 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt
@@ -221,7 +221,7 @@ class SafetySourceIntentHandler {
safetyEventForResponse: (Response) -> SafetyEvent
) {
val response = mutex.withLock { requestsToResponses[request] } ?: return
- val safetyEvent = safetyEventForResponse(response)
+ val safetyEvent = response.overrideSafetyEvent ?: safetyEventForResponse(response)
when (response) {
is Response.Error ->
reportSafetySourceError(request.sourceId, SafetySourceErrorDetails(safetyEvent))
@@ -270,6 +270,13 @@ class SafetySourceIntentHandler {
*/
sealed interface Response {
+ /**
+ * If non-null, the [SafetyEvent] to use when calling any applicable [SafetyCenterManager]
+ * methods.
+ */
+ val overrideSafetyEvent: SafetyEvent?
+ get() = null
+
/** Creates an error [Response]. */
object Error : Response
@@ -282,10 +289,13 @@ class SafetySourceIntentHandler {
* @param overrideBroadcastId an optional override of the broadcast id to use in the
* [SafetyEvent] sent to the [SafetyCenterManager], in case of [Request.Refresh] or
* [Request.Rescan]. This is used to simulate a misuse of the [SafetyCenterManager] APIs
+ * @param overrideSafetyEvent like [overrideBroadcastId] but allows the whole [SafetyEvent]
+ * to be override to send different types of [SafetyEvent].
*/
data class SetData(
val safetySourceData: SafetySourceData,
- val overrideBroadcastId: String? = null
+ val overrideBroadcastId: String? = null,
+ override val overrideSafetyEvent: SafetyEvent? = null
) : Response
}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt
index 2ba87040a..29072c989 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt
@@ -35,8 +35,8 @@ import android.safetycenter.SafetyCenterManager
import android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED
import androidx.annotation.RequiresApi
import androidx.test.core.app.ApplicationProvider
-import com.android.compatibility.common.util.SystemUtil
import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission
import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.executeSafetyCenterIssueActionWithPermission
@@ -164,46 +164,38 @@ class SafetySourceReceiver : BroadcastReceiver() {
fun SafetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
refreshReason: Int,
- timeout: Duration = TIMEOUT_LONG,
- safetySourceIds: List<String>? = null
- ) =
+ safetySourceIds: List<String>? = null,
+ timeout: Duration = TIMEOUT_LONG
+ ): String =
callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
- refreshSafetySourcesWithoutReceiverPermissionAndWait(
- refreshReason,
- timeout,
- safetySourceIds
- )
+ refreshSafetySourcesWithPermission(refreshReason, safetySourceIds)
+ receiveRefreshSafetySources(timeout)
}
fun SafetyCenterManager.refreshSafetySourcesWithoutReceiverPermissionAndWait(
refreshReason: Int,
- timeout: Duration,
safetySourceIds: List<String>? = null
- ): String {
+ ) {
refreshSafetySourcesWithPermission(refreshReason, safetySourceIds)
- if (timeout < TIMEOUT_LONG) {
- SystemUtil.waitForBroadcasts()
- }
- return receiveRefreshSafetySources(timeout)
+ WaitForBroadcasts.waitForBroadcasts()
+ receiveRefreshSafetySources(TIMEOUT_SHORT)
}
fun setSafetyCenterEnabledWithReceiverPermissionAndWait(
value: Boolean,
timeout: Duration = TIMEOUT_LONG
- ) =
+ ): Boolean =
callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
- setSafetyCenterEnabledWithoutReceiverPermissionAndWait(value, timeout)
+ SafetyCenterFlags.isEnabled = value
+ receiveSafetyCenterEnabledChanged(timeout)
}
fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait(
value: Boolean,
- timeout: Duration = TIMEOUT_LONG
- ): Boolean {
+ ) {
SafetyCenterFlags.isEnabled = value
- if (timeout < TIMEOUT_LONG) {
- SystemUtil.waitForBroadcasts()
- }
- return receiveSafetyCenterEnabledChanged(timeout)
+ WaitForBroadcasts.waitForBroadcasts()
+ receiveSafetyCenterEnabledChanged(TIMEOUT_SHORT)
}
fun SafetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt
index 97e2078e0..66be55fa8 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt
@@ -20,7 +20,6 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.Intent.FLAG_RECEIVER_FOREGROUND
-import android.content.pm.PackageManager.ResolveInfoFlags
import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.SafetyEvent
@@ -39,13 +38,13 @@ import android.safetycenter.SafetySourceStatus.IconAction.ICON_TYPE_INFO
import androidx.annotation.RequiresApi
import com.android.modules.utils.build.SdkLevel
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ACTION_TEST_ACTIVITY
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ACTION_TEST_ACTIVITY_EXPORTED
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
import com.android.safetycenter.testing.SafetySourceIntentHandler.Companion.ACTION_DISMISS_ISSUE
import com.android.safetycenter.testing.SafetySourceIntentHandler.Companion.ACTION_RESOLVE_ACTION
import com.android.safetycenter.testing.SafetySourceIntentHandler.Companion.EXTRA_SOURCE_ID
import com.android.safetycenter.testing.SafetySourceIntentHandler.Companion.EXTRA_SOURCE_ISSUE_ACTION_ID
import com.android.safetycenter.testing.SafetySourceIntentHandler.Companion.EXTRA_SOURCE_ISSUE_ID
-import java.lang.IllegalStateException
import kotlin.math.max
/**
@@ -55,16 +54,21 @@ import kotlin.math.max
@RequiresApi(TIRAMISU)
class SafetySourceTestData(private val context: Context) {
- /** A [PendingIntent] that redirects to the [TestActivity] page. */
- val testActivityRedirectPendingIntent =
- createRedirectPendingIntent(context, Intent(ACTION_TEST_ACTIVITY))
-
/**
- * A [PendingIntent] that redirects to the [TestActivity] page, the [Intent] is constructed with
- * the given [identifier].
+ * A [PendingIntent] that redirects to the [TestActivity] page.
+ *
+ * @param explicit whether the returned [PendingIntent] should use an explicit [Intent] (default
+ * [true])
+ * @param identifier the [Intent] identifier (default [null])
*/
- fun testActivityRedirectPendingIntent(identifier: String? = null) =
- createRedirectPendingIntent(context, Intent(ACTION_TEST_ACTIVITY).setIdentifier(identifier))
+ fun createTestActivityRedirectPendingIntent(
+ explicit: Boolean = true,
+ identifier: String? = null
+ ) =
+ createRedirectPendingIntent(
+ context,
+ createTestActivityIntent(context, explicit).setIdentifier(identifier)
+ )
/** A [SafetySourceData] with a [SEVERITY_LEVEL_UNSPECIFIED] [SafetySourceStatus]. */
val unspecified =
@@ -93,7 +97,7 @@ class SafetySourceTestData(private val context: Context) {
SEVERITY_LEVEL_UNSPECIFIED
)
.setEnabled(false)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.build()
@@ -110,14 +114,14 @@ class SafetySourceTestData(private val context: Context) {
summary: String = "Information issue summary"
) =
SafetySourceIssue.Builder(id, title, summary, SEVERITY_LEVEL_INFORMATION, ISSUE_TYPE_ID)
- .addAction(
- Action.Builder(
- INFORMATION_ISSUE_ACTION_ID,
- "Review",
- testActivityRedirectPendingIntent
- )
- .build()
- )
+ .addAction(action())
+
+ /** Creates an action with some defaults set. */
+ fun action(
+ id: String = INFORMATION_ISSUE_ACTION_ID,
+ label: String = "Review",
+ pendingIntent: PendingIntent = createTestActivityRedirectPendingIntent()
+ ) = Action.Builder(id, label, pendingIntent).build()
/**
* A [SafetySourceIssue] with a [SEVERITY_LEVEL_INFORMATION] and a redirecting [Action]. With
@@ -132,14 +136,7 @@ class SafetySourceTestData(private val context: Context) {
ISSUE_TYPE_ID
)
.setSubtitle("Information issue subtitle")
- .addAction(
- Action.Builder(
- INFORMATION_ISSUE_ACTION_ID,
- "Review",
- testActivityRedirectPendingIntent
- )
- .build()
- )
+ .addAction(action())
.build()
/**
@@ -154,7 +151,7 @@ class SafetySourceTestData(private val context: Context) {
"Unspecified summary",
SEVERITY_LEVEL_UNSPECIFIED
)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.addIssue(informationIssue)
@@ -172,7 +169,7 @@ class SafetySourceTestData(private val context: Context) {
"Unspecified summary",
SEVERITY_LEVEL_UNSPECIFIED
)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.addIssue(informationIssue)
@@ -183,7 +180,7 @@ class SafetySourceTestData(private val context: Context) {
SafetySourceData.Builder()
.setStatus(
SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.build()
@@ -209,8 +206,10 @@ class SafetySourceTestData(private val context: Context) {
SafetySourceData.Builder()
.setStatus(
SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
- .setPendingIntent(testActivityRedirectPendingIntent)
- .setIconAction(IconAction(ICON_TYPE_INFO, testActivityRedirectPendingIntent))
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
+ .setIconAction(
+ IconAction(ICON_TYPE_INFO, createTestActivityRedirectPendingIntent())
+ )
.build()
)
.build()
@@ -223,8 +222,10 @@ class SafetySourceTestData(private val context: Context) {
SafetySourceData.Builder()
.setStatus(
SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
- .setPendingIntent(testActivityRedirectPendingIntent)
- .setIconAction(IconAction(ICON_TYPE_GEAR, testActivityRedirectPendingIntent))
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
+ .setIconAction(
+ IconAction(ICON_TYPE_GEAR, createTestActivityRedirectPendingIntent())
+ )
.build()
)
.build()
@@ -237,7 +238,7 @@ class SafetySourceTestData(private val context: Context) {
SafetySourceData.Builder()
.setStatus(
SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.addIssue(informationIssue)
@@ -253,7 +254,7 @@ class SafetySourceTestData(private val context: Context) {
SafetySourceData.Builder()
.setStatus(
SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.addIssue(
@@ -275,7 +276,7 @@ class SafetySourceTestData(private val context: Context) {
"Ok summary",
SEVERITY_LEVEL_INFORMATION
)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.addIssue(informationIssue)
@@ -289,7 +290,7 @@ class SafetySourceTestData(private val context: Context) {
SafetySourceData.Builder()
.setStatus(
SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.addIssue(informationIssueWithSubtitle)
@@ -315,7 +316,7 @@ class SafetySourceTestData(private val context: Context) {
Action.Builder(
RECOMMENDATION_ISSUE_ACTION_ID,
"See issue",
- testActivityRedirectPendingIntent
+ createTestActivityRedirectPendingIntent()
)
.apply {
if (confirmationDialog && SdkLevel.isAtLeastU()) {
@@ -383,7 +384,7 @@ class SafetySourceTestData(private val context: Context) {
"Recommendation summary",
SEVERITY_LEVEL_RECOMMENDATION
)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
@@ -425,12 +426,25 @@ class SafetySourceTestData(private val context: Context) {
.build()
/** A [PendingIntent] used by the resolving [Action] in [criticalResolvingGeneralIssue]. */
- val criticalIssueActionPendingIntent =
+ val criticalIssueActionPendingIntent = resolvingActionPendingIntent()
+
+ /**
+ * Returns a [PendingIntent] for a resolving [Action] with the given [sourceId], [sourceIssueId]
+ * and [sourceIssueActionId]. Default values are the same as those used by
+ * [criticalIssueActionPendingIntent]. *
+ */
+ fun resolvingActionPendingIntent(
+ sourceId: String = SINGLE_SOURCE_ID,
+ sourceIssueId: String = CRITICAL_ISSUE_ID,
+ sourceIssueActionId: String = CRITICAL_ISSUE_ACTION_ID
+ ) =
broadcastPendingIntent(
Intent(ACTION_RESOLVE_ACTION)
- .putExtra(EXTRA_SOURCE_ID, SINGLE_SOURCE_ID)
- .putExtra(EXTRA_SOURCE_ISSUE_ID, CRITICAL_ISSUE_ID)
- .putExtra(EXTRA_SOURCE_ISSUE_ACTION_ID, CRITICAL_ISSUE_ACTION_ID)
+ .putExtra(EXTRA_SOURCE_ID, sourceId)
+ .putExtra(EXTRA_SOURCE_ISSUE_ID, sourceIssueId)
+ .putExtra(EXTRA_SOURCE_ISSUE_ACTION_ID, sourceIssueActionId)
+ // Identifier is set because intent extras do not disambiguate PendingIntents
+ .setIdentifier(sourceId + sourceIssueId + sourceIssueActionId)
)
/** A resolving Critical [Action] */
@@ -454,7 +468,11 @@ class SafetySourceTestData(private val context: Context) {
/** An action that redirects to [TestActivity] */
val testActivityRedirectAction =
- Action.Builder(CRITICAL_ISSUE_ACTION_ID, "Redirect", testActivityRedirectPendingIntent)
+ Action.Builder(
+ CRITICAL_ISSUE_ACTION_ID,
+ "Redirect",
+ createTestActivityRedirectPendingIntent()
+ )
.build()
/** A resolving Critical [Action] that declares a success message */
@@ -492,7 +510,7 @@ class SafetySourceTestData(private val context: Context) {
Action.Builder(
CRITICAL_ISSUE_ACTION_ID,
"Go solve issue",
- testActivityRedirectPendingIntent
+ createTestActivityRedirectPendingIntent()
)
.build()
)
@@ -571,7 +589,7 @@ class SafetySourceTestData(private val context: Context) {
"Critical summary",
SEVERITY_LEVEL_CRITICAL_WARNING
)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
@@ -685,7 +703,7 @@ class SafetySourceTestData(private val context: Context) {
"Critical summary",
SEVERITY_LEVEL_CRITICAL_WARNING
)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.addIssue(criticalResolvingIssueWithSuccessMessage)
@@ -710,7 +728,7 @@ class SafetySourceTestData(private val context: Context) {
"Critical summary 2",
SEVERITY_LEVEL_CRITICAL_WARNING
)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.addIssue(criticalRedirectingIssue)
@@ -729,7 +747,7 @@ class SafetySourceTestData(private val context: Context) {
SafetySourceData.Builder()
.setStatus(
SafetySourceStatus.Builder(entryTitle, entrySummary, severityLevel)
- .setPendingIntent(testActivityRedirectPendingIntent)
+ .setPendingIntent(createTestActivityRedirectPendingIntent())
.build()
)
.apply {
@@ -746,7 +764,7 @@ class SafetySourceTestData(private val context: Context) {
Action.Builder(
"action_id",
"Action",
- testActivityRedirectPendingIntent
+ createTestActivityRedirectPendingIntent()
)
.build()
)
@@ -784,7 +802,9 @@ class SafetySourceTestData(private val context: Context) {
const val CRITICAL_ISSUE_ACTION_ID = "critical_issue_action_id"
/** Issue type ID for all the issues in this file */
+ // LINT.IfChange(issue_type_id)
const val ISSUE_TYPE_ID = "issue_type_id"
+ // LINT.ThenChange(/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt:issue_type_id)
const val CONFIRMATION_TITLE = "Confirmation title"
const val CONFIRMATION_TEXT = "Confirmation text"
@@ -811,28 +831,28 @@ class SafetySourceTestData(private val context: Context) {
return builder.build()
}
- /** Returns a [PendingIntent] that redirects to [intent]. */
+ /** Returns an [Intent] that redirects to the [TestActivity] page. */
+ fun createTestActivityIntent(context: Context, explicit: Boolean = true): Intent =
+ if (explicit) {
+ Intent(ACTION_TEST_ACTIVITY).setPackage(context.packageName)
+ } else {
+ val intent = Intent(ACTION_TEST_ACTIVITY_EXPORTED)
+ // We have seen some flakiness where implicit intents find multiple receivers
+ // and the ResolveActivity pops up. A test cannot handle this, so crash. Most
+ // likely the cause is other test's APKs being left hanging around by flaky
+ // test infrastructure.
+ intent.flags = intent.flags or Intent.FLAG_ACTIVITY_REQUIRE_DEFAULT
+ intent
+ }
+
+ /** Returns a [PendingIntent] that redirects to the given [Intent]. */
fun createRedirectPendingIntent(context: Context, intent: Intent): PendingIntent {
- val explicitIntent = Intent(intent).setPackage(context.packageName)
- val redirectIntent =
- if (intentResolves(context, explicitIntent)) {
- explicitIntent
- } else if (intentResolves(context, intent)) {
- intent
- } else {
- throw IllegalStateException("Intent doesn't resolve")
- }
return PendingIntent.getActivity(
context,
0 /* requestCode */,
- redirectIntent,
+ intent,
PendingIntent.FLAG_IMMUTABLE
)
}
-
- private fun intentResolves(context: Context, intent: Intent): Boolean =
- context.packageManager
- .queryIntentActivities(intent, ResolveInfoFlags.of(0))
- .isNotEmpty()
}
}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/StatusBarNotificationWithChannel.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/StatusBarNotificationWithChannel.kt
index d9a998c3e..53ea34362 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/StatusBarNotificationWithChannel.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/StatusBarNotificationWithChannel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.safetycenter.functional.testing
+package com.android.safetycenter.testing
import android.app.NotificationChannel
import android.service.notification.StatusBarNotification
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SupportsSafetyCenter.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SupportsSafetyCenter.kt
new file mode 100644
index 000000000..bfb5c4bd7
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SupportsSafetyCenter.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.testing
+
+import android.content.Context
+import android.content.res.Resources
+
+/**
+ * Returns whether the device supports Safety Center according to the `config_enableSafetyCenter`
+ * boolean system resource.
+ */
+fun Context.deviceSupportsSafetyCenter(): Boolean {
+ val resId = Resources.getSystem().getIdentifier("config_enableSafetyCenter", "bool", "android")
+ return resources.getBoolean(resId)
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SupportsSafetyCenterRule.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SupportsSafetyCenterRule.kt
new file mode 100644
index 000000000..7227873ff
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SupportsSafetyCenterRule.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.testing
+
+import android.content.Context
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * JUnit [TestRule] for on-device tests that requires Safety Center to be supported. This rule does
+ * not require Safety Center to be enabled.
+ *
+ * For tests which should only run on devices where Safety Center is not supported, instantiate with
+ * [requireSupportIs] set to `false` to invert the condition.
+ */
+class SupportsSafetyCenterRule(private val context: Context, requireSupportIs: Boolean = true) :
+ TestRule {
+
+ private val shouldSupportSafetyCenter: Boolean = requireSupportIs
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ val support = context.deviceSupportsSafetyCenter()
+ if (shouldSupportSafetyCenter) {
+ assumeTrue("Test device does not support Safety Center", support)
+ } else {
+ assumeFalse("Test device supports Safety Center", support)
+ }
+ base.evaluate()
+ }
+ }
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt
index 124f44101..eceffb74f 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt
@@ -16,9 +16,15 @@
package com.android.safetycenter.testing
import android.app.Activity
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+import android.content.pm.PackageManager.DONT_KILL_APP
import android.os.Bundle
import android.view.View
import android.widget.TextView
+import androidx.test.core.app.ApplicationProvider
/** An activity used in tests to assert the redirects. */
class TestActivity : Activity() {
@@ -32,4 +38,32 @@ class TestActivity : Activity() {
val exitButton: View? = findViewById(R.id.button)
exitButton?.setOnClickListener { finish() }
}
+
+ companion object {
+
+ /**
+ * Enable a higher-priority alias of TestActivity.
+ *
+ * <p>We have seen flakes where implicit intents for TEST_ACTIVITY fail owing to multiple
+ * receivers, perhaps due to an older CTS APK hanging around. This component should be
+ * turned on (and off in tidyup) in tests in the hope of only resolving to the actively
+ * running test in these cases.
+ */
+ fun enableHighPriorityAlias() {
+ setAliasEnabledState(COMPONENT_ENABLED_STATE_ENABLED)
+ }
+ /** @see [enableHighPriorityAlias] */
+ fun disableHighPriorityAlias() {
+ setAliasEnabledState(COMPONENT_ENABLED_STATE_DISABLED)
+ }
+ private fun setAliasEnabledState(state: Int) {
+ val name =
+ ComponentName(getApplicationContext(), TestActivity::class.java.name + "Priority")
+ getApplicationContext()
+ .packageManager
+ .setComponentEnabledSetting(name, state, DONT_KILL_APP)
+ }
+
+ private fun getApplicationContext(): Context = ApplicationProvider.getApplicationContext()
+ }
}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/TestNotificationListener.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestNotificationListener.kt
index 113ad3b23..2b2342d7a 100644
--- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/TestNotificationListener.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestNotificationListener.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package android.safetycenter.functional.testing
+package com.android.safetycenter.testing
import android.app.NotificationChannel
import android.content.ComponentName
+import android.content.Context
import android.os.ConditionVariable
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
@@ -84,15 +85,7 @@ class TestNotificationListener : NotificationListenerService() {
}
companion object {
- private const val TAG = "TestNotificationListene"
-
- private val id: String =
- "android.safetycenter.functional/" + TestNotificationListener::class.java.name
- private val componentName =
- ComponentName(
- "android.safetycenter.functional",
- TestNotificationListener::class.java.name
- )
+ private const val TAG = "SafetyCenterTestNotif"
private val connected = ConditionVariable(false)
private val disconnected = ConditionVariable(true)
@@ -132,7 +125,10 @@ class TestNotificationListener : NotificationListenerService() {
count: Int,
timeout: Duration = TIMEOUT_LONG
): List<StatusBarNotificationWithChannel> {
- return waitForNotificationsToSatisfy(timeout, description = "$count notifications") {
+ return waitForNotificationsToSatisfy(
+ timeout = timeout,
+ description = "$count notifications"
+ ) {
it.size == count
}
}
@@ -162,18 +158,46 @@ class TestNotificationListener : NotificationListenerService() {
): List<StatusBarNotificationWithChannel> {
val charsList = characteristics.toList()
return waitForNotificationsToSatisfy(
- timeout,
+ timeout = timeout,
description = "notification(s) matching characteristics $charsList"
- ) { NotificationCharacteristics.areMatching(it, charsList) }
+ ) {
+ NotificationCharacteristics.areMatching(it, charsList)
+ }
+ }
+
+ /**
+ * Waits for a success notification with the given [successMessage] after resolving an
+ * issue.
+ *
+ * Additional assertions can be made on the [StatusBarNotification] using [onNotification].
+ */
+ fun waitForSuccessNotification(
+ successMessage: String,
+ onNotification: (StatusBarNotification) -> Unit = {}
+ ) {
+ val successNotificationWithChannel =
+ waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ successMessage,
+ "",
+ actions = emptyList(),
+ )
+ )
+ val statusBarNotification = successNotificationWithChannel.statusBarNotification
+ onNotification(statusBarNotification)
+ // Cancel the notification directly to speed up the tests as it's only auto-cancelled
+ // after 10 seconds, and the teardown waits for all notifications to be cancelled to
+ // avoid having unrelated notifications leaking between test cases.
+ cancelAndWait(statusBarNotification.key, waitForIssueCache = false)
}
/**
- * Blocks until [forAtLeast] has elapsed, or throw an [AssertionError] if any notification
- * is posted or removed before then.
+ * Blocks for [TIMEOUT_SHORT], or throw an [AssertionError] if any notification is posted or
+ * removed before then.
*/
- fun waitForZeroNotificationEvents(forAtLeast: Duration = TIMEOUT_SHORT) {
+ fun waitForZeroNotificationEvents() {
val event =
- runBlockingWithTimeoutOrNull(forAtLeast) {
+ runBlockingWithTimeoutOrNull(TIMEOUT_SHORT) {
safetyCenterNotificationEvents.receive()
}
assertThat(event).isNull()
@@ -185,10 +209,6 @@ class TestNotificationListener : NotificationListenerService() {
description: String,
predicate: (List<StatusBarNotificationWithChannel>) -> Boolean
): List<StatusBarNotificationWithChannel> {
- fun formatError(notifs: List<StatusBarNotificationWithChannel>): String {
- return "Expected: $description, but the actual notifications were: $notifs"
- }
-
// First we wait at most timeout for the active notifications to satisfy the given
// predicate or otherwise we throw:
val satisfyingNotifications =
@@ -197,7 +217,11 @@ class TestNotificationListener : NotificationListenerService() {
waitForNotificationsToSatisfyAsync(predicate)
}
} catch (e: TimeoutCancellationException) {
- throw AssertionError(formatError(getSafetyCenterNotifications()), e)
+ throw AssertionError(
+ "Expected: $description, but notifications were " +
+ "${getSafetyCenterNotifications()} after waiting for $timeout",
+ e
+ )
}
// Assuming the predicate was satisfied, now we ensure it is not violated for the
@@ -208,7 +232,10 @@ class TestNotificationListener : NotificationListenerService() {
}
if (nonSatisfyingNotifications != null) {
// In this case the negated-predicate was satisfied before forAtLeast had elapsed
- throw AssertionError(formatError(nonSatisfyingNotifications))
+ throw AssertionError(
+ "Expected: $description to settle, but notifications changed to " +
+ "$nonSatisfyingNotifications within $forAtLeast"
+ )
}
return satisfyingNotifications
@@ -276,16 +303,20 @@ class TestNotificationListener : NotificationListenerService() {
/**
* Cancels a specific notification and then waits for it to be removed by the notification
* manager and marked as dismissed in Safety Center, or throws if it has not been removed
- * within [timeout].
+ * within [TIMEOUT_LONG].
*/
- fun cancelAndWait(key: String, timeout: Duration = TIMEOUT_LONG) {
+ fun cancelAndWait(key: String, waitForIssueCache: Boolean = true) {
getInstanceOrThrow().cancelNotification(key)
waitForNotificationsToSatisfy(
- timeout,
+ timeout = TIMEOUT_LONG,
description = "no notification with the key $key"
- ) { notifications -> notifications.none { it.statusBarNotification.key == key } }
+ ) { notifications ->
+ notifications.none { it.statusBarNotification.key == key }
+ }
- waitForIssueCacheToContainAnyDismissedNotification()
+ if (waitForIssueCache) {
+ waitForIssueCacheToContainAnyDismissedNotification()
+ }
}
private fun waitForIssueCacheToContainAnyDismissedNotification() {
@@ -313,10 +344,12 @@ class TestNotificationListener : NotificationListenerService() {
}
/** Runs a shell command to allow or disallow the listener. Use before and after test. */
- private fun toggleListenerAccess(allowed: Boolean) {
- // TODO(b/260335646): Try to do this using the AndroidTest.xml instead of in code
+ private fun toggleListenerAccess(context: Context, allowed: Boolean) {
+ val componentName = ComponentName(context, TestNotificationListener::class.java)
val verb = if (allowed) "allow" else "disallow"
- SystemUtil.runShellCommand("cmd notification ${verb}_listener $id")
+ SystemUtil.runShellCommand(
+ "cmd notification ${verb}_listener ${componentName.flattenToString()}"
+ )
if (allowed) {
requestRebind(componentName)
if (!connected.block(TIMEOUT_LONG.toMillis())) {
@@ -332,22 +365,29 @@ class TestNotificationListener : NotificationListenerService() {
}
/** Prepare the [TestNotificationListener] for a notification test */
- fun setup() {
- toggleListenerAccess(true)
+ fun setup(context: Context) {
+ toggleListenerAccess(context, true)
}
/** Clean up the [TestNotificationListener] after executing a notification test. */
- fun reset() {
+ fun reset(context: Context) {
waitForNotificationsToSatisfy(
forAtLeast = Duration.ZERO,
description = "all Safety Center notifications removed in tear down"
- ) { it.isEmpty() }
- toggleListenerAccess(false)
+ ) {
+ it.isEmpty()
+ }
+ toggleListenerAccess(context, false)
safetyCenterNotificationEvents.cancel()
safetyCenterNotificationEvents = Channel(capacity = Channel.UNLIMITED)
}
private fun StatusBarNotification.isSafetyCenterNotification(): Boolean =
- packageName == "android" && notification.channelId.startsWith("safety_center")
+ packageName == "android" &&
+ notification.channelId.startsWith("safety_center") &&
+ // Don't consider the grouped system notifications to be a SC notification, in some
+ // scenarios a "ranker_group" notification can remain even when there are no more
+ // notifications associated with the channel. See b/293593539 for more details.
+ tag != "ranker_group"
}
}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt
index ec676e3d9..0e062692a 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt
@@ -29,10 +29,11 @@ import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.StaleObjectException
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
import com.android.compatibility.common.util.SystemUtil.runShellCommand
import com.android.compatibility.common.util.UiAutomatorUtils2.getUiDevice
import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
-import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
+import com.android.compatibility.common.util.UiDumpUtils
import java.time.Duration
import java.util.concurrent.TimeoutException
import java.util.regex.Pattern
@@ -46,19 +47,30 @@ object UiTestHelper {
const val MORE_ISSUES_LABEL = "More alerts"
private const val DISMISS_ISSUE_LABEL = "Dismiss"
- private val WAIT_TIMEOUT = Duration.ofSeconds(10)
- private val NOT_DISPLAYED_TIMEOUT = Duration.ofMillis(500)
+ private const val TAG = "SafetyCenterUiTestHelper"
- private val TAG = UiTestHelper::class.java.simpleName
+ private val WAIT_TIMEOUT = Duration.ofSeconds(20)
/**
- * Waits for the given [selector] to be displayed and performs the given [uiObjectAction] on it.
+ * Waits for the given [selector] to be displayed, and optionally perform a given
+ * [uiObjectAction] on it.
*/
fun waitDisplayed(selector: BySelector, uiObjectAction: (UiObject2) -> Unit = {}) {
- waitFor("$selector to be displayed", WAIT_TIMEOUT) {
- uiObjectAction(waitFindObject(selector, it.toMillis()))
- true
+ val whenToTimeout = currentElapsedRealtime() + WAIT_TIMEOUT
+ var remaining = WAIT_TIMEOUT
+ while (remaining > Duration.ZERO) {
+ getUiDevice().waitForIdle()
+ try {
+ uiObjectAction(waitFindObject(selector, remaining.toMillis()))
+ return
+ } catch (e: StaleObjectException) {
+ Log.w(TAG, "Found stale UI object, retrying", e)
+ remaining = whenToTimeout - currentElapsedRealtime()
+ }
}
+ throw UiDumpUtils.wrapWithUiDump(
+ TimeoutException("Timed out waiting for $selector to be displayed after $WAIT_TIMEOUT")
+ )
}
/** Waits for all the given [textToFind] to be displayed. */
@@ -77,16 +89,21 @@ object UiTestHelper {
/** Waits for the given [selector] not to be displayed. */
fun waitNotDisplayed(selector: BySelector) {
- waitFor("$selector not to be displayed", NOT_DISPLAYED_TIMEOUT) {
- waitFindObjectOrNull(selector, it.toMillis()) == null
+ // TODO(b/294038848): Add scrolling to make sure it is properly gone.
+ val gone = getUiDevice().wait(Until.gone(selector), WAIT_TIMEOUT.toMillis())
+ if (gone) {
+ return
}
+ throw UiDumpUtils.wrapWithUiDump(
+ TimeoutException(
+ "Timed out waiting for $selector not to be displayed after $WAIT_TIMEOUT"
+ )
+ )
}
/** Waits for all the given [textToFind] not to be displayed. */
fun waitAllTextNotDisplayed(vararg textToFind: CharSequence?) {
- for (text in textToFind) {
- if (text != null) waitNotDisplayed(By.text(text.toString()))
- }
+ waitNotDisplayed(By.text(anyOf(*textToFind)))
}
/** Waits for a button with the given [label] not to be displayed. */
@@ -101,11 +118,11 @@ object UiTestHelper {
*/
@RequiresApi(TIRAMISU)
fun waitSourceDataDisplayed(sourceData: SafetySourceData) {
- waitAllTextDisplayed(sourceData.status?.title, sourceData.status?.summary)
-
for (sourceIssue in sourceData.issues) {
waitSourceIssueDisplayed(sourceIssue)
}
+
+ waitAllTextDisplayed(sourceData.status?.title, sourceData.status?.summary)
}
/** Waits for most of the [SafetySourceIssue] information to be displayed. */
@@ -131,7 +148,7 @@ object UiTestHelper {
fun waitCollapsedIssuesDisplayed(vararg sourceIssues: SafetySourceIssue) {
waitSourceIssueDisplayed(sourceIssues.first())
waitAllTextDisplayed(MORE_ISSUES_LABEL)
- sourceIssues.asSequence().drop(1).forEach { waitSourceIssueNotDisplayed(it) }
+ waitAllTextNotDisplayed(*sourceIssues.drop(1).map { it.title }.toTypedArray())
}
/** Waits for all the [SafetySourceIssue] to be displayed with the [MORE_ISSUES_LABEL] card. */
@@ -221,35 +238,17 @@ object UiTestHelper {
}
private fun buttonSelector(label: CharSequence): BySelector {
- return By.clickable(true).text(Pattern.compile("$label|${label.toString().uppercase()}"))
+ return By.clickable(true).text(anyOf(label, label.toString().uppercase()))
}
- private fun waitFor(
- message: String,
- uiAutomatorConditionTimeout: Duration,
- uiAutomatorCondition: (Duration) -> Boolean
- ) {
- val elapsedStartMillis = SystemClock.elapsedRealtime()
- while (true) {
- getUiDevice().waitForIdle()
- val durationSinceStart =
- Duration.ofMillis(SystemClock.elapsedRealtime() - elapsedStartMillis)
- if (durationSinceStart >= WAIT_TIMEOUT) {
- break
- }
- val remainingTime = WAIT_TIMEOUT - durationSinceStart
- val uiAutomatorTimeout = minOf(uiAutomatorConditionTimeout, remainingTime)
- try {
- if (uiAutomatorCondition(uiAutomatorTimeout)) {
- return
- } else {
- Log.d(TAG, "Failed condition for $message, will retry if within timeout")
- }
- } catch (e: StaleObjectException) {
- Log.d(TAG, "StaleObjectException for $message, will retry if within timeout", e)
+ private fun anyOf(vararg anyTextToFind: CharSequence?): Pattern {
+ val regex =
+ anyTextToFind.filterNotNull().joinToString(separator = "|") {
+ Pattern.quote(it.toString())
}
- }
-
- throw TimeoutException("Timed out waiting for $message")
+ return Pattern.compile(regex)
}
+
+ private fun currentElapsedRealtime(): Duration =
+ Duration.ofMillis(SystemClock.elapsedRealtime())
}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/WaitForBroadcasts.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/WaitForBroadcasts.kt
new file mode 100644
index 000000000..3c19ea180
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/WaitForBroadcasts.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 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.safetycenter.testing
+
+import android.util.Log
+import androidx.annotation.GuardedBy
+import com.android.compatibility.common.util.SystemUtil
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
+import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.TimeoutCancellationException
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+
+/** A class to help waiting on broadcasts to be processed by the system. */
+object WaitForBroadcasts {
+
+ private const val TAG: String = "WaitForBroadcasts"
+
+ private val mutex = Mutex()
+ @GuardedBy("mutex") private var currentJob: Job? = null
+
+ /**
+ * Waits for broadcasts for at most [TIMEOUT_LONG] and prints a warning if that operation timed
+ * out.
+ *
+ * The [SystemUtil.waitForBroadcasts] operation will keep on running even after the timeout as
+ * it is not interruptible. Further calls to [WaitForBroadcasts.waitForBroadcasts] will re-use
+ * the currently running [SystemUtil.waitForBroadcasts] call if it hasn't completed.
+ */
+ fun waitForBroadcasts() {
+ try {
+ runBlockingWithTimeout {
+ mutex
+ .withLock {
+ val newJob = currentJob.maybeStartNewWaitForBroadcasts()
+ currentJob = newJob
+ newJob
+ }
+ .join()
+ }
+ } catch (e: TimeoutCancellationException) {
+ Log.w(TAG, "Waiting for broadcasts timed out, proceeding anyway", e)
+ }
+ }
+
+ // We're using a GlobalScope here as there doesn't seem to be a straightforward way to timeout
+ // and interrupt the waitForBroadcasts() call. Given it's uninterruptible, we'd rather just have
+ // at most one globally-bound waitForBroadcasts() call running at any given time.
+ @OptIn(DelicateCoroutinesApi::class)
+ private fun Job?.maybeStartNewWaitForBroadcasts(): Job =
+ if (this != null && isActive) {
+ this
+ } else {
+ GlobalScope.launch(Dispatchers.IO) { SystemUtil.waitForBroadcasts() }
+ }
+}